Merge "rdbms: deprecate unused aggregateValue() method"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Sat, 6 Apr 2019 20:03:36 +0000 (20:03 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Sat, 6 Apr 2019 20:03:36 +0000 (20:03 +0000)
101 files changed:
.phan/config.php
.phpcs.xml
autoload.php
includes/MovePage.php
includes/OutputPage.php
includes/Title.php
includes/actions/McrUndoAction.php
includes/api/ApiBase.php
includes/api/i18n/ar.json
includes/api/i18n/de.json
includes/api/i18n/fr.json
includes/api/i18n/zh-hant.json
includes/auth/AuthenticationRequest.php
includes/block/Restriction/AbstractRestriction.php
includes/editpage/TextConflictHelper.php
includes/export/WikiExporter.php
includes/filebackend/lockmanager/LockManagerGroup.php
includes/filerepo/file/File.php
includes/filerepo/file/ForeignDBFile.php
includes/gallery/PackedHoverImageGallery.php [new file with mode: 0644]
includes/gallery/PackedOverlayImageGallery.php
includes/htmlform/OOUIHTMLForm.php
includes/htmlform/fields/HTMLSelectAndOtherField.php
includes/import/UploadSourceAdapter.php
includes/installer/MssqlUpdater.php
includes/installer/PostgresUpdater.php
includes/installer/WebInstallerComplete.php
includes/installer/WebInstallerDocument.php
includes/installer/i18n/it.json
includes/jobqueue/jobs/ClearWatchlistNotificationsJob.php
includes/jobqueue/jobs/DeletePageJob.php
includes/jobqueue/jobs/UserGroupExpiryJob.php
includes/libs/IP.php
includes/libs/mime/MimeAnalyzer.php
includes/libs/mime/XmlTypeCheck.php
includes/libs/objectcache/MemcachedClient.php
includes/libs/objectcache/MemcachedPeclBagOStuff.php
includes/libs/rdbms/database/DBConnRef.php
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/database/IDatabase.php
includes/libs/rdbms/database/MaintainableDBConnRef.php
includes/libs/rdbms/encasing/MssqlBlob.php
includes/libs/rdbms/exception/DBReadOnlyRoleError.php [new file with mode: 0644]
includes/libs/rdbms/lbfactory/ILBFactory.php
includes/libs/rdbms/loadbalancer/ILoadBalancer.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/page/ImagePage.php
includes/profiler/ProfilerStub.php
includes/rcfeed/UDPRCFeedEngine.php
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderFileModule.php
includes/resourceloader/ResourceLoaderImage.php
includes/resourceloader/ResourceLoaderOOUIFileModule.php
includes/resourceloader/ResourceLoaderOOUIModule.php
includes/resourceloader/ResourceLoaderSkinModule.php
includes/resourceloader/ResourceLoaderWikiModule.php
includes/search/NullIndexField.php
includes/specialpage/AuthManagerSpecialPage.php
includes/specialpage/ChangesListSpecialPage.php
includes/specialpage/ImageQueryPage.php
includes/specials/SpecialBlock.php
includes/specials/SpecialComparePages.php
includes/specials/SpecialEmailuser.php
includes/specials/SpecialExpandTemplates.php
includes/specials/SpecialMIMEsearch.php
includes/specials/SpecialPageLanguage.php
includes/specials/SpecialUndelete.php
includes/specials/forms/UploadForm.php
includes/specials/pagers/NewFilesPager.php
includes/utils/BatchRowUpdate.php
languages/LanguageConverter.php
languages/i18n/as.json
languages/i18n/az.json
languages/i18n/be-tarask.json
languages/i18n/bn.json
languages/i18n/cs.json
languages/i18n/de.json
languages/i18n/eu.json
languages/i18n/exif/it.json
languages/i18n/exif/mk.json
languages/i18n/fi.json
languages/i18n/fy.json
languages/i18n/hy.json
languages/i18n/ia.json
languages/i18n/is.json
languages/i18n/ml.json
languages/i18n/nl.json
languages/i18n/pl.json
languages/i18n/sat.json
languages/i18n/sh.json
languages/i18n/skr-arab.json
languages/i18n/th.json
languages/i18n/yue.json
languages/i18n/zh-hant.json
languages/messages/MessagesEn.php
maintenance/populatePPSortKey.php
maintenance/preprocessorFuzzTest.php
maintenance/storage/recompressTracked.php
maintenance/wrapOldPasswords.php
tests/phpunit/includes/db/LoadBalancerTest.php
tests/phpunit/includes/libs/rdbms/database/DBConnRefTest.php

index 2c0035e..37b2153 100644 (file)
@@ -77,53 +77,35 @@ $cfg['suppress_issue_types'] = array_merge( $cfg['suppress_issue_types'], [
        "PhanAccessMethodInternal",
        // approximate error count: 17
        "PhanCommentParamOnEmptyParamList",
-       // approximate error count: 30
+       // approximate error count: 29
        "PhanCommentParamWithoutRealParam",
        // approximate error count: 2
        "PhanCompatibleNegativeStringOffset",
-       // approximate error count: 1
-       "PhanEmptyFQSENInCallable",
-       // approximate error count: 1
-       "PhanInvalidCommentForDeclarationType",
-       // approximate error count: 6
-       "PhanNonClassMethodCall",
        // approximate error count: 21
        "PhanParamReqAfterOpt",
-       // approximate error count: 27
+       // approximate error count: 26
        "PhanParamSignatureMismatch",
        // approximate error count: 4
        "PhanParamSignatureMismatchInternal",
-       // approximate error count: 1
-       "PhanParamSignatureRealMismatchTooFewParameters",
-       // approximate error count: 1
-       "PhanParamSuspiciousOrder",
        // approximate error count: 127
        "PhanParamTooMany",
        // approximate error count: 2
-       "PhanParamTooManyCallable",
-       // approximate error count: 1
-       "PhanParamTooManyInternal",
-       // approximate error count: 2
        "PhanPluginDuplicateExpressionBinaryOp",
        // approximate error count: 2
        "PhanTraitParentReference",
-       // approximate error count: 27
+       // approximate error count: 30
        "PhanTypeArraySuspicious",
-       // approximate error count: 33
+       // approximate error count: 27
        "PhanTypeArraySuspiciousNullable",
        // approximate error count: 26
        "PhanTypeComparisonFromArray",
        // approximate error count: 2
        "PhanTypeComparisonToArray",
-       // approximate error count: 2
-       "PhanTypeExpectedObjectOrClassName",
        // approximate error count: 7
        "PhanTypeExpectedObjectPropAccess",
-       // approximate error count: 3
-       "PhanTypeInstantiateAbstract",
-       // approximate error count: 62
+       // approximate error count: 63
        "PhanTypeInvalidDimOffset",
-       // approximate error count: 10
+       // approximate error count: 6
        "PhanTypeInvalidExpressionArrayDestructuring",
        // approximate error count: 7
        "PhanTypeInvalidLeftOperandOfIntegerOp",
@@ -131,28 +113,22 @@ $cfg['suppress_issue_types'] = array_merge( $cfg['suppress_issue_types'], [
        "PhanTypeInvalidRightOperand",
        // approximate error count: 2
        "PhanTypeInvalidRightOperandOfIntegerOp",
-       // approximate error count: 152
+       // approximate error count: 154
        "PhanTypeMismatchArgument",
-       // approximate error count: 28
+       // approximate error count: 27
        "PhanTypeMismatchArgumentInternal",
        // approximate error count: 1
        "PhanTypeMismatchBitwiseBinaryOperands",
        // approximate error count: 2
        "PhanTypeMismatchDimEmpty",
-       // approximate error count: 29
+       // approximate error count: 27
        "PhanTypeMismatchDimFetch",
        // approximate error count: 10
        "PhanTypeMismatchForeach",
        // approximate error count: 77
        "PhanTypeMismatchProperty",
-       // approximate error count: 88
+       // approximate error count: 84
        "PhanTypeMismatchReturn",
-       // approximate error count: 43
-       "PhanTypeMissingReturn",
-       // approximate error count: 1
-       "PhanTypeNoAccessiblePropertiesForeach",
-       // approximate error count: 4
-       "PhanTypeNonVarPassByRef",
        // approximate error count: 12
        "PhanTypeObjectUnsetDeclaredProperty",
        // approximate error count: 9
@@ -163,18 +139,14 @@ $cfg['suppress_issue_types'] = array_merge( $cfg['suppress_issue_types'], [
        "PhanUndeclaredConstant",
        // approximate error count: 3
        "PhanUndeclaredInvokeInCallable",
-       // approximate error count: 242
+       // approximate error count: 237
        "PhanUndeclaredMethod",
-       // approximate error count: 847
+       // approximate error count: 846
        "PhanUndeclaredProperty",
        // approximate error count: 2
        "PhanUndeclaredVariableAssignOp",
        // approximate error count: 55
        "PhanUndeclaredVariableDim",
-       // approximate error count: 4
-       "PhanUnextractableAnnotationElementName",
-       // approximate error count: 4
-       "PhanUnextractableAnnotationSuffix",
 ] );
 
 $cfg['ignore_undeclared_variables_in_global_scope'] = true;
index 9939c54..170e16d 100644 (file)
                <exclude-pattern>*/includes/diff/DairikiDiff\.php</exclude-pattern>
                <exclude-pattern>*/includes/Feed\.php</exclude-pattern>
                <exclude-pattern>*/includes/filerepo/file/LocalFile\.php</exclude-pattern>
-               <exclude-pattern>*/includes/gallery/PackedOverlayImageGallery\.php</exclude-pattern>
                <exclude-pattern>*/includes/htmlform/HTMLFormElement\.php</exclude-pattern>
                <exclude-pattern>*/includes/libs/filebackend/FileBackendStore\.php</exclude-pattern>
                <exclude-pattern>*/includes/libs/filebackend/FSFileBackend\.php</exclude-pattern>
index bb1b3b2..b22aeab 100644 (file)
@@ -1070,7 +1070,7 @@ $wgAutoloadLocalClasses = [
        'PPNode_Hash_Tree' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
        'PPTemplateFrame_DOM' => __DIR__ . '/includes/parser/Preprocessor_DOM.php',
        'PPTemplateFrame_Hash' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
-       'PackedHoverImageGallery' => __DIR__ . '/includes/gallery/PackedOverlayImageGallery.php',
+       'PackedHoverImageGallery' => __DIR__ . '/includes/gallery/PackedHoverImageGallery.php',
        'PackedImageGallery' => __DIR__ . '/includes/gallery/PackedImageGallery.php',
        'PackedOverlayImageGallery' => __DIR__ . '/includes/gallery/PackedOverlayImageGallery.php',
        'Page' => __DIR__ . '/includes/page/Page.php',
@@ -1636,6 +1636,7 @@ $wgAutoloadLocalClasses = [
        'Wikimedia\\Rdbms\\DBQueryError' => __DIR__ . '/includes/libs/rdbms/exception/DBQueryError.php',
        'Wikimedia\\Rdbms\\DBQueryTimeoutError' => __DIR__ . '/includes/libs/rdbms/exception/DBQueryTimeoutError.php',
        'Wikimedia\\Rdbms\\DBReadOnlyError' => __DIR__ . '/includes/libs/rdbms/exception/DBReadOnlyError.php',
+       'Wikimedia\\Rdbms\\DBReadOnlyRoleError' => __DIR__ . '/includes/libs/rdbms/exception/DBReadOnlyRoleError.php',
        'Wikimedia\\Rdbms\\DBReplicationWaitError' => __DIR__ . '/includes/libs/rdbms/exception/DBReplicationWaitError.php',
        'Wikimedia\\Rdbms\\DBTransactionError' => __DIR__ . '/includes/libs/rdbms/exception/DBTransactionError.php',
        'Wikimedia\\Rdbms\\DBTransactionSizeError' => __DIR__ . '/includes/libs/rdbms/exception/DBTransactionSizeError.php',
index db5750a..2edd669 100644 (file)
@@ -427,8 +427,8 @@ class MovePage {
         * Can also be used to revert after a DB failure.
         *
         * @private
-        * @param Title Old location to move the file from.
-        * @param Title New location to move the file to.
+        * @param Title $oldTitle Old location to move the file from.
+        * @param Title $newTitle New location to move the file to.
         * @return Status
         */
        private function moveFile( $oldTitle, $newTitle ) {
index 786ecc4..cb3f1ad 100644 (file)
@@ -2187,7 +2187,7 @@ class OutputPage extends ContextSource {
         * Parse wikitext and return the HTML (internal implementation helper)
         *
         * @param string $text
-        * @param Title The title to use
+        * @param Title $title The title to use
         * @param bool $linestart Is this the start of a line?
         * @param bool $tidy Whether the output should be tidied
         * @param bool $interface Use interface language (instead of content language) while parsing
index d517b85..3d54750 100644 (file)
@@ -731,6 +731,7 @@ class Title implements LinkTarget, IDBAccessObject {
                                // Allow unicode if a single high-bit character appears
                                $r0 = sprintf( '\x%02x', $ord0 );
                                $allowUnicode = true;
+                               // @phan-suppress-next-line PhanParamSuspiciousOrder false positive
                        } elseif ( strpos( '-\\[]^', $d0 ) !== false ) {
                                $r0 = '\\' . $d0;
                        } else {
index b0f89dc..e9de846 100644 (file)
@@ -30,7 +30,7 @@ class McrUndoAction extends FormAction {
 
        protected $undo = 0, $undoafter = 0, $cur = 0;
 
-       /** @param RevisionRecord|null */
+       /** @var RevisionRecord|null */
        protected $curRev = null;
 
        public function getName() {
index 9b3d116..528ced8 100644 (file)
@@ -800,6 +800,7 @@ abstract class ApiBase extends ContextSource {
                                        // $results if all are done.
                                        unset( $targets[$placeholder] );
                                        $placeholder = '{' . $placeholder . '}';
+                                       // @phan-suppress-next-line PhanTypeNoAccessiblePropertiesForeach
                                        foreach ( $results[$target] as $value ) {
                                                if ( !preg_match( '/^[^{}]*$/', $value ) ) {
                                                        // Skip values that make invalid parameter names.
index ea67f15..cf9785e 100644 (file)
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "يضيف تاريخ تسجيل المستخدم.",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "يضيف عدد الصفحات غير المقروءة في قائمة مراقبة المستخدم (بحد أقصى $1; ترجع <samp>$2</samp> إذا كان أكثر).",
        "apihelp-query+userinfo-paramvalue-prop-centralids": "يضيف المعرفات المركزية وحالة المرفقات للمستخدم.",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "يضيف تاريخ آخر مساهمة للمستخدم.",
        "apihelp-query+userinfo-param-attachedwiki": "باستخدام <kbd>$1prop=centralids</kbd>، حدد ما إذا كان المستخدم مرتبطا بالويكي المحدد بواسطة هذا المعرف.",
        "apihelp-query+userinfo-example-simple": "الحصول على معلومات حول المستخدم الحالي.",
        "apihelp-query+userinfo-example-data": "الحصول على معلومات حول المستخدم الحالي.",
index 883fb55..54d6cc5 100644 (file)
        "apihelp-query+userinfo-paramvalue-prop-options": "Listet alle Einstellungen auf, die der aktuelle Benutzer festgelegt hat.",
        "apihelp-query+userinfo-paramvalue-prop-editcount": "Ergänzt den Bearbeitungszähler des aktuellen Benutzers.",
        "apihelp-query+userinfo-paramvalue-prop-realname": "Fügt den bürgerlichen Namen des Benutzers hinzu.",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "Ergänzt das Datum des letzten Benutzerbeitrags.",
        "apihelp-query+userinfo-example-simple": "Informationen über den aktuellen Benutzer abrufen",
        "apihelp-query+userinfo-example-data": "Ruft zusätzliche Informationen über den aktuellen Benutzer ab.",
        "apihelp-query+users-summary": "Informationen über eine Liste von Benutzern abrufen.",
index 8fc7fe0..9ae584b 100644 (file)
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Ajoute la date d’inscription de l’utilisateur.",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "Ajoute le compteur de pages non lues de la liste de suivi de l’utilisateur (au maximum $1 ; renvoie <samp>$2</samp> s’il y en a plus).",
        "apihelp-query+userinfo-paramvalue-prop-centralids": "Ajoute les IDs centraux et l’état d’attachement de l’utilisateur.",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "Ajoute la date de la dernière contribution de l'utilisateur.",
        "apihelp-query+userinfo-param-attachedwiki": "Avec <kbd>$1prop=centralids</kbd>, indiquer si l’utilisateur est attaché au wiki identifié par cet ID.",
        "apihelp-query+userinfo-example-simple": "Obtenir des informations sur l’utilisateur actuel.",
        "apihelp-query+userinfo-example-data": "Obtenir des informations supplémentaires sur l’utilisateur actuel.",
index c2f586c..a0a920a 100644 (file)
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "添加使用者的註冊日期。",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "添加未讀頁面數目在使用者的監視清單(最多 $1,若有更多則回傳 <samp>$2</samp>)。",
        "apihelp-query+userinfo-paramvalue-prop-centralids": "替使用者添加中心 ID 與附加狀態。",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "添加使用者最新貢獻的日期。",
        "apihelp-query+userinfo-param-attachedwiki": "以 <kbd>$1prop=centralids</kbd> 來表明使用者是否附加於由此 ID 所識別出的 wiki。",
        "apihelp-query+userinfo-example-simple": "取得目前使用者的資訊。",
        "apihelp-query+userinfo-example-data": "取得目前使用者的額外資訊。",
index 7fc362a..4744c4d 100644 (file)
@@ -370,6 +370,7 @@ abstract class AuthenticationRequest {
         * @return AuthenticationRequest
         */
        public static function __set_state( $data ) {
+               // @phan-suppress-next-line PhanTypeInstantiateAbstract
                $ret = new static();
                foreach ( $data as $k => $v ) {
                        $ret->$k = $v;
index 20678ad..7970266 100644 (file)
@@ -97,6 +97,7 @@ abstract class AbstractRestriction implements Restriction {
         * @inheritDoc
         */
        public static function newFromRow( \stdClass $row ) {
+               // @phan-suppress-next-line PhanTypeInstantiateAbstract
                return new static( $row->ir_ipb_id, $row->ir_value );
        }
 
index f7d0945..2471b52 100644 (file)
@@ -166,7 +166,6 @@ class TextConflictHelper {
         * HTML to build the textbox1 on edit conflicts
         *
         * @param array $customAttribs
-        * @return string HTML
         */
        public function getEditConflictMainTextBox( array $customAttribs = [] ) {
                $builder = new TextboxBuilder();
index 120632c..e02cd83 100644 (file)
@@ -469,8 +469,8 @@ class WikiExporter {
        protected function outputPageStreamBatch( $results, $lastRow ) {
                foreach ( $results as $row ) {
                        if ( $lastRow === null ||
-                               $lastRow->page_namespace != $row->page_namespace ||
-                               $lastRow->page_title != $row->page_title ) {
+                               $lastRow->page_namespace !== $row->page_namespace ||
+                               $lastRow->page_title !== $row->page_title ) {
                                if ( $lastRow !== null ) {
                                        $output = '';
                                        if ( $this->dumpUploads ) {
index aa955d0..43f6010 100644 (file)
@@ -129,6 +129,7 @@ class LockManagerGroup {
                        }
                        $config['logger'] = LoggerFactory::getInstance( 'LockManager' );
 
+                       // @phan-suppress-next-line PhanTypeInstantiateAbstract
                        $this->managers[$name]['instance'] = new $class( $config );
                }
 
index 97abe33..7d4f4df 100644 (file)
@@ -29,6 +29,7 @@ use MediaWiki\MediaWikiServices;
  * @ingroup FileAbstraction
  */
 
+// @phan-file-suppress PhanTypeMissingReturn false positives
 /**
  * Implements some public methods and some protected utility functions which
  * are required by multiple child classes. Contains stub functionality for
index 1869967..3438a63 100644 (file)
@@ -24,6 +24,7 @@
 use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\DBUnexpectedError;
 
+// @phan-file-suppress PhanTypeMissingReturn false positives
 /**
  * Foreign file with an accessible MediaWiki database
  *
diff --git a/includes/gallery/PackedHoverImageGallery.php b/includes/gallery/PackedHoverImageGallery.php
new file mode 100644 (file)
index 0000000..2e1ef7d
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Same as Packed except different CSS is applied to make the
+ * caption only show up on hover. If a touch screen is detected,
+ * falls back to PackedHoverGallery. Degrades gracefully for
+ * screen readers.
+ */
+class PackedHoverImageGallery extends PackedOverlayImageGallery {
+}
index 0a5a457..4c72f87 100644 (file)
@@ -53,12 +53,3 @@ class PackedOverlayImageGallery extends PackedImageGallery {
                        . "\n\t\t\t</div></div>";
        }
 }
-
-/**
- * Same as Packed except different CSS is applied to make the
- * caption only show up on hover. If a touch screen is detected,
- * falls back to PackedHoverGallery. Degrades gracefully for
- * screen readers.
- */
-class PackedHoverImageGallery extends PackedOverlayImageGallery {
-}
index 738db09..e21d783 100644 (file)
@@ -145,6 +145,10 @@ class OOUIHTMLForm extends HTMLForm {
                        [ 'class' => 'mw-htmlform-submit-buttons' ], "\n$buttons" ) . "\n";
        }
 
+       /**
+        * @inheritDoc
+        * @return OOUI\PanelLayout
+        */
        protected function wrapFieldSetSection( $legend, $section, $attributes, $isRoot ) {
                // to get a user visible effect, wrap the fieldset into a framed panel layout
                $layout = new OOUI\PanelLayout( [
index 4e64e9d..f137bf1 100644 (file)
@@ -144,7 +144,7 @@ class HTMLSelectAndOtherField extends HTMLSelectField {
        /**
         * @param WebRequest $request
         *
-        * @return array("<overall message>","<select value>","<text field value>")
+        * @return array ["<overall message>","<select value>","<text field value>"]
         */
        public function loadDataFromRequest( $request ) {
                if ( $request->getCheck( $this->mName ) ) {
index ccacbe4..7ac895c 100644 (file)
@@ -32,7 +32,7 @@ class UploadSourceAdapter {
        /** @var array */
        public static $sourceRegistrations = [];
 
-       /** @var string */
+       /** @var ImportSource */
        private $mSource;
 
        /** @var string */
index 75f3894..b8dc5ff 100644 (file)
@@ -166,6 +166,7 @@ class MssqlUpdater extends DatabaseUpdater {
                parent::applyPatch( $path, $isFullPath, $msg );
                $this->db->scrollableCursor( $prevScroll );
                $this->db->prepareStatements( $prevPrep );
+               return true;
        }
 
        /**
index 9ba8d02..008240a 100644 (file)
@@ -839,7 +839,7 @@ END;
                if ( !$this->db->tableExists( $table, __METHOD__ ) ) {
                        $this->output( "...skipping: '$table' table doesn't exist yet.\n" );
 
-                       return;
+                       return true;
                }
 
                // Second requirement: the new index must be missing
@@ -853,17 +853,18 @@ END;
                                        "            $old should be manually removed if not needed anymore.\n" );
                        }
 
-                       return;
+                       return true;
                }
 
                // Third requirement: the old index must exist
                if ( !$this->db->indexExists( $table, $old, __METHOD__ ) ) {
                        $this->output( "...skipping: index $old doesn't exist.\n" );
 
-                       return;
+                       return true;
                }
 
                $this->db->query( "ALTER INDEX $old RENAME TO $new" );
+               return true;
        }
 
        protected function dropPgField( $table, $field ) {
index 456058e..9f80489 100644 (file)
@@ -59,6 +59,7 @@ class WebInstallerComplete extends WebInstallerPage {
 
                $this->parent->restoreLinkPopups();
                $this->endForm( false, false );
+               return '';
        }
 
 }
index f79d272..5241b3c 100644 (file)
@@ -32,6 +32,7 @@ abstract class WebInstallerDocument extends WebInstallerPage {
                $this->parent->output->addWikiTextAsInterface( $text );
                $this->startForm();
                $this->endForm( false );
+               return '';
        }
 
        /**
index 5be6e03..c1eabf2 100644 (file)
        "config-sqlite-cant-create-db": "Impossibile creare il file di database <code>$1</code> .",
        "config-sqlite-fts3-downgrade": "Il PHP è mancante del supporto FTS3, declassamento tabelle in corso",
        "config-can-upgrade": "Ci sono tabelle di MediaWiki in questo database.\nPer aggiornarle a MediaWiki $1, fai clic su '''continua'''.",
+       "config-upgrade-error": "Si è verificato un errore durante l'aggiornamento delle tabelle MediaWiki nel tuo database.\n\nPer ulteriori informazioni guarda nel registro qui sopra, per riprovare clicca su <strong>Continua</strong>.",
        "config-upgrade-done": "Aggiornamento completo.\n\nPuoi [$1 iniziare ad usare il tuo wiki].\n\nSe vuoi rigenerare il tuo file <code>LocalSettings.php</code>, clicca sul pulsante sotto. Questa operazione '''non è raccomandata''', a meno che non hai problemi con il tuo wiki.",
        "config-upgrade-done-no-regenerate": "Aggiornamento completo.\n\nPuoi [$1 iniziare ad usare il tuo wiki].",
        "config-regenerate": "Rigenera LocalSettings.php →",
        "config-install-mainpage-failed": "Impossibile inserire la pagina principale: $1",
        "config-install-done": "<strong>Complimenti!</strong>\nHai installato MediaWiki.\n\nIl programma di installazione ha generato un file <code>LocalSettings.php</code> che contiene tutte le impostazioni.\n\nDevi scaricarlo ed inserirlo nella directory base del tuo wiki (la stessa dove è presente index.php). Il download dovrebbe partire automaticamente.\n\nSe il download non si avvia, o se è stato annullato, puoi riavviarlo cliccando sul collegamento di seguito:\n\n$3\n\n<strong>Nota:</strong> se esci ora dall'installazione senza scaricare il file di configurazione che è stato generato, questo poi non sarà più disponibile in seguito.\n\nQuando hai fatto, puoi <strong>[$2 entrare nel tuo wiki]</strong>.",
        "config-install-done-path": "<strong>Complimenti!</strong>\nHai installato MediaWiki.\n\nIl programma di installazione ha generato un file <code>LocalSettings.php</code> che contiene tutte le impostazioni.\n\nDevi scaricarlo ed inserirlo in <code>$4</code>. Il download dovrebbe partire automaticamente.\n\nSe il download non si avvia, o se è stato annullato, puoi riavviarlo cliccando sul collegamento seguente:\n\n$3\n\n<strong>Nota:</strong> se esci ora dall'installazione senza scaricare il file di configurazione che è stato generato, questo poi non sarà più disponibile in seguito.\n\nQuando hai fatto, puoi <strong>[$2 entrare nel tuo wiki]</strong>.",
+       "config-install-success": "MediaWiki è stato installato corretamente. Ora puoi visitare <$1$2> per vedere il tuo wiki.\nSe hai domande, controlla la nostra lista di domande frequenti:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> o usa usa uno dei forum di supporto riepilogati su quella pagina.",
+       "config-install-db-success": "Il database è stato configurato correttamente",
        "config-download-localsettings": "Scarica <code>LocalSettings.php</code>",
        "config-help": "aiuto",
        "config-help-tooltip": "fai clic per espandere",
index b71580a..3b2c899 100644 (file)
@@ -96,5 +96,6 @@ class ClearWatchlistNotificationsJob extends Job {
                                $firstBatch = false;
                        }
                } while ( $idsToUpdate );
+               return true;
        }
 }
index 9b5cef4..e6dfae4 100644 (file)
@@ -4,7 +4,7 @@
  * Class DeletePageJob
  */
 class DeletePageJob extends Job {
-       public function __construct( $title, $params ) {
+       public function __construct( $title, $params = [] ) {
                parent::__construct( 'deletePage', $title, $params );
        }
 
index 0945e58..bd0df5b 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 class UserGroupExpiryJob extends Job {
-       public function __construct( $params = false ) {
+       public function __construct( $params = [] ) {
                parent::__construct( 'userGroupExpiry', Title::newMainPage(), $params );
                $this->removeDuplicates = true;
        }
index 8efcd15..da525e7 100644 (file)
@@ -467,7 +467,7 @@ class IP {
         * to an integer network and a number of bits
         *
         * @param string $range IP with CIDR prefix
-        * @return array(int or string, int)
+        * @return array [int or string, int]
         */
        public static function parseCIDR( $range ) {
                if ( self::isIPv6( $range ) ) {
@@ -557,7 +557,7 @@ class IP {
         *
         * @param string $range
         *
-        * @return array(string, int)
+        * @return array [string, int]
         */
        private static function parseCIDR6( $range ) {
                # Explode into <expanded IP,range>
@@ -598,7 +598,7 @@ class IP {
         *
         * @param string $range
         *
-        * @return array(string, string)
+        * @return array [string, string]
         */
        private static function parseRange6( $range ) {
                # Expand any IPv6 IP
index e08da61..413fb2a 100644 (file)
@@ -806,6 +806,8 @@ EOT;
                if ( $eocdrPos !== false ) {
                        $this->logger->info( __METHOD__ . ": ZIP signature present in $file\n" );
                        // Check if it really is a ZIP file, make sure the EOCDR is at the end (T40432)
+                       // FIXME: unpack()'s third argument was added in PHP 7.1
+                       // @phan-suppress-next-line PhanParamTooManyInternal
                        $commentLength = unpack( "n", $tail, $eocdrPos + 20 )[0];
                        if ( $eocdrPos + 22 + $commentLength !== strlen( $tail ) ) {
                                $this->logger->info( __METHOD__ . ": ZIP EOCDR not at end. Not a ZIP file." );
index 746f3f5..0b52391 100644 (file)
@@ -72,7 +72,7 @@ class XmlTypeCheck {
         * Additional parsing options
         */
        private $parserOptions = [
-               'processing_instruction_handler' => '',
+               'processing_instruction_handler' => null,
                'external_dtd_handler' => '',
                'dtd_handler' => '',
                'require_safe_dtd' => true
index 1cc07b7..937ca55 100644 (file)
@@ -255,8 +255,6 @@ class MemcachedClient {
         * Memcache initializer
         *
         * @param array $args Associative array of settings
-        *
-        * @return mixed
         */
        public function __construct( $args ) {
                $this->set_servers( $args['servers'] ?? array() );
index 489f001..692771d 100644 (file)
@@ -138,6 +138,9 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
                return $params;
        }
 
+       /**
+        * @suppress PhanTypeNonVarPassByRef
+        */
        protected function doGet( $key, $flags = 0, &$casToken = null ) {
                $this->debugLog( "get($key)" );
                if ( defined( Memcached::class . '::GET_EXTENDED' ) ) { // v3.0.0
index cf582b7..f3ab1c5 100644 (file)
@@ -8,7 +8,6 @@ use InvalidArgumentException;
  * Helper class to handle automatically marking connections as reusable (via RAII pattern)
  * as well handling deferring the actual network connection until the handle is used
  *
- * @note: proxy methods are defined explicitly to avoid interface errors
  * @ingroup Database
  * @since 1.22
  */
@@ -19,6 +18,8 @@ class DBConnRef implements IDatabase {
        private $conn;
        /** @var array|null N-tuple of (server index, group, DatabaseDomain|string) */
        private $params;
+       /** @var int One of DB_MASTER/DB_REPLICA */
+       private $role;
 
        const FLD_INDEX = 0;
        const FLD_GROUP = 1;
@@ -27,10 +28,13 @@ class DBConnRef implements IDatabase {
 
        /**
         * @param ILoadBalancer $lb Connection manager for $conn
-        * @param Database|array $conn Database handle or (server index, query groups, domain, flags)
+        * @param Database|array $conn Database or (server index, query groups, domain, flags)
+        * @param int $role The type of connection asked for; one of DB_MASTER/DB_REPLICA
+        * @internal This method should not be called outside of LoadBalancer
         */
-       public function __construct( ILoadBalancer $lb, $conn ) {
+       public function __construct( ILoadBalancer $lb, $conn, $role ) {
                $this->lb = $lb;
+               $this->role = $role;
                if ( $conn instanceof Database ) {
                        $this->conn = $conn; // live handle
                } elseif ( is_array( $conn ) && count( $conn ) >= 4 && $conn[self::FLD_DOMAIN] !== false ) {
@@ -49,6 +53,14 @@ class DBConnRef implements IDatabase {
                return $this->conn->$name( ...$arguments );
        }
 
+       /**
+        * @return int DB_MASTER when this *requires* the master DB, otherwise DB_REPLICA
+        * @since 1.33
+        */
+       public function getReferenceRole() {
+               return $this->role;
+       }
+
        public function getServerInfo() {
                return $this->__call( __FUNCTION__, func_get_args() );
        }
@@ -255,7 +267,11 @@ class DBConnRef implements IDatabase {
        }
 
        public function query( $sql, $fname = __METHOD__, $flags = 0 ) {
-               return $this->__call( __FUNCTION__, func_get_args() );
+               if ( $this->role !== ILoadBalancer::DB_MASTER ) {
+                       $flags |= IDatabase::QUERY_REPLICA_ROLE;
+               }
+
+               return $this->__call( __FUNCTION__, [ $sql, $fname, $flags ] );
        }
 
        public function freeResult( $res ) {
@@ -310,6 +326,8 @@ class DBConnRef implements IDatabase {
        public function lockForUpdate(
                $table, $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -326,10 +344,14 @@ class DBConnRef implements IDatabase {
        }
 
        public function insert( $table, $a, $fname = __METHOD__, $options = [] ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function update( $table, $values, $conds, $fname = __METHOD__, $options = [] ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -435,26 +457,36 @@ class DBConnRef implements IDatabase {
        }
 
        public function nextSequenceValue( $seqName ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function upsert(
                $table, array $rows, $uniqueIndexes, array $set, $fname = __METHOD__
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function deleteJoin(
                $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = __METHOD__
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function delete( $table, $conds, $fname = __METHOD__ ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -462,6 +494,8 @@ class DBConnRef implements IDatabase {
                $destTable, $srcTable, $varMap, $conds,
                $fname = __METHOD__, $insertOptions = [], $selectOptions = [], $selectJoinConds = []
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -529,18 +563,21 @@ class DBConnRef implements IDatabase {
        }
 
        public function onTransactionResolution( callable $callback, $fname = __METHOD__ ) {
+               // DB_REPLICA role: caller might want to refresh cache after a REPEATABLE-READ snapshot
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function onTransactionCommitOrIdle( callable $callback, $fname = __METHOD__ ) {
+               // DB_REPLICA role: caller might want to refresh cache after a REPEATABLE-READ snapshot
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function onTransactionIdle( callable $callback, $fname = __METHOD__ ) {
-               return $this->__call( __FUNCTION__, func_get_args() );
+               return $this->onTransactionCommitOrIdle( $callback, $fname );
        }
 
        public function onTransactionPreCommitOrIdle( callable $callback, $fname = __METHOD__ ) {
+               // DB_REPLICA role: caller might want to refresh cache after a cache mutex is released
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -551,20 +588,24 @@ class DBConnRef implements IDatabase {
        public function startAtomic(
                $fname = __METHOD__, $cancelable = IDatabase::ATOMIC_NOT_CANCELABLE
        ) {
+               // Don't call assertRoleAllowsWrites(); caller might want a REPEATABLE-READ snapshot
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function endAtomic( $fname = __METHOD__ ) {
+               // Don't call assertRoleAllowsWrites(); caller might want a REPEATABLE-READ snapshot
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function cancelAtomic( $fname = __METHOD__, AtomicSectionIdentifier $sectionId = null ) {
+               // Don't call assertRoleAllowsWrites(); caller might want a REPEATABLE-READ snapshot
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function doAtomicSection(
                $fname, callable $callback, $cancelable = self::ATOMIC_NOT_CANCELABLE
        ) {
+               // Don't call assertRoleAllowsWrites(); caller might want a REPEATABLE-READ snapshot
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -627,18 +668,26 @@ class DBConnRef implements IDatabase {
        }
 
        public function lockIsFree( $lockName, $method ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function lock( $lockName, $method, $timeout = 5 ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function unlock( $lockName, $method ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function getScopedLockAndFlush( $lockKey, $fname, $timeout ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -674,6 +723,26 @@ class DBConnRef implements IDatabase {
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
+       /**
+        * Error out if the role is not DB_MASTER
+        *
+        * Note that the underlying connection may or may not itself be read-only.
+        * It could even be to a writable master (both server-side and to the application).
+        * This error is meant for the case when a DB_REPLICA handle was requested but a
+        * a write was attempted on that handle regardless.
+        *
+        * In configurations where the master DB has some generic read load or is the only server,
+        * DB_MASTER/DB_REPLICA will sometimes (or always) use the same connection to the master DB.
+        * This does not effect the role of DBConnRef instances.
+        * @throws DBReadOnlyRoleError
+        */
+       protected function assertRoleAllowsWrites() {
+               // DB_MASTER is "prima facie" writable
+               if ( $this->role !== ILoadBalancer::DB_MASTER ) {
+                       throw new DBReadOnlyRoleError( $this->conn, "Cannot write with role DB_REPLICA" );
+               }
+       }
+
        /**
         * Clean up the connection when out of scope
         */
index 2739205..c5ef758 100644 (file)
@@ -1032,7 +1032,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         */
        protected function assertIsWritableMaster() {
                if ( $this->getLBInfo( 'replica' ) === true ) {
-                       throw new DBUnexpectedError(
+                       throw new DBReadOnlyRoleError(
                                $this,
                                'Write operations are not allowed on replica database connections.'
                        );
@@ -1194,7 +1194,6 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
 
                $flags = (int)$flags; // b/c; this field used to be a bool
                $ignoreErrors = $this->hasFlags( $flags, self::QUERY_SILENCE_ERRORS );
-               $pseudoPermanent = $this->hasFlags( $flags, self::QUERY_PSEUDO_PERMANENT );
 
                $priorTransaction = $this->trxLevel;
                $priorWritesPending = $this->writesOrCallbacksPending();
@@ -1206,8 +1205,13 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        $this->assertIsWritableMaster();
                        # Do not treat temporary table writes as "meaningful writes" that need committing.
                        # Profile them as reads. Integration tests can override this behavior via $flags.
+                       $pseudoPermanent = $this->hasFlags( $flags, self::QUERY_PSEUDO_PERMANENT );
                        $tableType = $this->registerTempTableWrite( $sql, $pseudoPermanent );
                        $isEffectiveWrite = ( $tableType !== self::TEMP_NORMAL );
+                       # DBConnRef uses QUERY_REPLICA_ROLE to enforce the replica role for raw SQL queries
+                       if ( $isEffectiveWrite && $this->hasFlags( $flags, self::QUERY_REPLICA_ROLE ) ) {
+                               throw new DBReadOnlyRoleError( $this, "Cannot write; target role is DB_REPLICA" );
+                       }
                } else {
                        $isEffectiveWrite = false;
                }
@@ -3580,6 +3584,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                                list( $phpCallback ) = $callback;
                                $this->clearFlag( self::DBO_TRX ); // make each query its own transaction
                                try {
+                                       // @phan-suppress-next-line PhanParamTooManyCallable
                                        call_user_func( $phpCallback, $trigger, $this );
                                } catch ( Exception $ex ) {
                                        call_user_func( $this->errorLogger, $ex );
index 3e3eb3a..e25b4d2 100644 (file)
@@ -113,6 +113,8 @@ interface IDatabase {
         *   permanent as far as write tracking is concerned. This is useful for testing.
         */
        const QUERY_PSEUDO_PERMANENT = 2;
+       /** @var int Enforce that a query does not make effective writes */
+       const QUERY_REPLICA_ROLE = 4;
 
        /** @var bool Parameter to unionQueries() for UNION ALL */
        const UNION_ALL = true;
@@ -1555,7 +1557,6 @@ interface IDatabase {
         *
         * @param callable $callback
         * @param string $fname Caller name
-        * @return mixed
         * @since 1.28
         */
        public function onTransactionResolution( callable $callback, $fname = __METHOD__ );
@@ -1599,7 +1600,6 @@ interface IDatabase {
         *
         * @param callable $callback
         * @param string $fname
-        * @return mixed
         * @since 1.20
         * @deprecated Since 1.32
         */
@@ -1645,7 +1645,6 @@ interface IDatabase {
         *
         * @param string $name Callback name
         * @param callable|null $callback Use null to unset a listener
-        * @return mixed
         * @since 1.28
         */
        public function setTransactionListener( $name, callable $callback = null );
@@ -2173,7 +2172,6 @@ interface IDatabase {
         * the aliases can be removed, and then the old X-named indexes dropped.
         *
         * @param string[] $aliases
-        * @return mixed
         * @since 1.31
         */
        public function setIndexAliases( array $aliases );
index 8a2c795..10a0897 100644 (file)
@@ -30,6 +30,8 @@ class MaintainableDBConnRef extends DBConnRef implements IMaintainableDatabase {
                $fname = false,
                callable $inputCallback = null
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -40,14 +42,20 @@ class MaintainableDBConnRef extends DBConnRef implements IMaintainableDatabase {
                $fname = __METHOD__,
                callable $inputCallback = null
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function dropTable( $tableName, $fName = __METHOD__ ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function deadlockLoop() {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -66,6 +74,8 @@ class MaintainableDBConnRef extends DBConnRef implements IMaintainableDatabase {
        public function duplicateTableStructure(
                $oldName, $newName, $temporary = false, $fname = __METHOD__
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -74,10 +84,14 @@ class MaintainableDBConnRef extends DBConnRef implements IMaintainableDatabase {
        }
 
        public function lockTables( array $read, array $write, $method ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function unlockTables( $method ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
index 6ad934a..97d5072 100644 (file)
@@ -6,12 +6,11 @@ class MssqlBlob extends Blob {
        /** @noinspection PhpMissingParentConstructorInspection */
 
        /**
-        * @param string $data
-        * @suppress PhanTypeMagicVoidWithReturn
+        * @param Blob|array|string $data
         */
        public function __construct( $data ) {
                if ( $data instanceof MssqlBlob ) {
-                       return $data;
+                       $this->data = $data->data;
                } elseif ( $data instanceof Blob ) {
                        $this->data = $data->fetch();
                } elseif ( is_array( $data ) && is_object( $data ) ) {
diff --git a/includes/libs/rdbms/exception/DBReadOnlyRoleError.php b/includes/libs/rdbms/exception/DBReadOnlyRoleError.php
new file mode 100644 (file)
index 0000000..4d565ba
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Database
+ */
+
+namespace Wikimedia\Rdbms;
+
+/**
+ * Exception class for attempted DB write access to a DBConnRef with the DB_REPLICA role
+ *
+ * @ingroup Database
+ */
+class DBReadOnlyRoleError extends DBUnexpectedError {
+}
index 98c06ad..cb8be21 100644 (file)
@@ -390,7 +390,6 @@ interface ILBFactory {
         * the aliases can be removed, and then the old X-named indexes dropped.
         *
         * @param string[] $aliases
-        * @return mixed
         * @since 1.31
         */
        public function setIndexAliases( array $aliases );
index b20bf04..52d8370 100644 (file)
@@ -291,13 +291,13 @@ interface ILoadBalancer {
         *
         * @see ILoadBalancer::getConnection() for parameter information
         *
-        * @param int $db Server index or DB_MASTER/DB_REPLICA
+        * @param int $i Server index or DB_MASTER/DB_REPLICA
         * @param array|string|bool $groups Query group(s), or false for the generic reader
         * @param string|bool $domain Domain ID, or false for the current domain
         * @param int $flags Bitfield of CONN_* class constants (e.g. CONN_TRX_AUTOCOMMIT)
         * @return MaintainableDBConnRef
         */
-       public function getMaintenanceConnectionRef( $db, $groups = [], $domain = false, $flags = 0 );
+       public function getMaintenanceConnectionRef( $i, $groups = [], $domain = false, $flags = 0 );
 
        /**
         * Open a connection to the server given by the specified index
@@ -680,7 +680,6 @@ interface ILoadBalancer {
         * the aliases can be removed, and then the old X-named indexes dropped.
         *
         * @param string[] $aliases
-        * @return mixed
         * @since 1.31
         */
        public function setIndexAliases( array $aliases );
index bd22aca..da5382a 100644 (file)
@@ -834,23 +834,36 @@ class LoadBalancer implements ILoadBalancer {
                }
        }
 
-       public function getConnectionRef( $db, $groups = [], $domain = false, $flags = 0 ) {
+       public function getConnectionRef( $i, $groups = [], $domain = false, $flags = 0 ) {
                $domain = $this->resolveDomainID( $domain );
+               $role = $this->getRoleFromIndex( $i );
 
-               return new DBConnRef( $this, $this->getConnection( $db, $groups, $domain, $flags ) );
+               return new DBConnRef( $this, $this->getConnection( $i, $groups, $domain, $flags ), $role );
        }
 
-       public function getLazyConnectionRef( $db, $groups = [], $domain = false, $flags = 0 ) {
+       public function getLazyConnectionRef( $i, $groups = [], $domain = false, $flags = 0 ) {
                $domain = $this->resolveDomainID( $domain );
+               $role = $this->getRoleFromIndex( $i );
 
-               return new DBConnRef( $this, [ $db, $groups, $domain, $flags ] );
+               return new DBConnRef( $this, [ $i, $groups, $domain, $flags ], $role );
        }
 
-       public function getMaintenanceConnectionRef( $db, $groups = [], $domain = false, $flags = 0 ) {
+       public function getMaintenanceConnectionRef( $i, $groups = [], $domain = false, $flags = 0 ) {
                $domain = $this->resolveDomainID( $domain );
+               $role = $this->getRoleFromIndex( $i );
 
                return new MaintainableDBConnRef(
-                       $this, $this->getConnection( $db, $groups, $domain, $flags ) );
+                       $this, $this->getConnection( $i, $groups, $domain, $flags ), $role );
+       }
+
+       /**
+        * @param int $i Server index or DB_MASTER/DB_REPLICA
+        * @return int One of DB_MASTER/DB_REPLICA
+        */
+       private function getRoleFromIndex( $i ) {
+               return ( $i === self::DB_MASTER || $i === $this->getWriterIndex() )
+                       ? self::DB_MASTER
+                       : self::DB_REPLICA;
        }
 
        public function openConnection( $i, $domain = false, $flags = 0 ) {
index 60237ff..6c1ac39 100644 (file)
@@ -1222,7 +1222,7 @@ EOT
         * @return TitleArray|Title[]
         */
        public function getForeignCategories() {
-               $this->mPage->getForeignCategories();
+               return $this->mPage->getForeignCategories();
        }
 
 }
index 1017e44..fe46798 100644 (file)
@@ -32,9 +32,11 @@ class ProfilerStub extends Profiler {
        }
 
        public function getFunctionStats() {
+               return [];
        }
 
        public function getOutput() {
+               return '';
        }
 
        public function close() {
index f76d771..7e69a02 100644 (file)
@@ -32,5 +32,6 @@ class UDPRCFeedEngine extends RCFeedEngine {
        public function send( array $feed, $line ) {
                $transport = UDPTransport::newFromString( $feed['uri'] );
                $transport->emit( $line );
+               return true;
        }
 }
index 839948d..4cf8735 100644 (file)
@@ -319,8 +319,6 @@ class ResourceLoader implements LoggerAwareInterface {
         * @throws MWException If a duplicate module registration is attempted
         * @throws MWException If a module name contains illegal characters (pipes or commas)
         * @throws MWException If something other than a ResourceLoaderModule is being registered
-        * @return bool False if there were any errors, in which case one or more modules were
-        *   not registered
         */
        public function register( $name, $info = null ) {
                $moduleSkinStyles = $this->config->get( 'ResourceModuleSkinStyles' );
index 9be5de3..031541b 100644 (file)
@@ -385,7 +385,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
                if ( $this->packageFiles !== null ) {
                        $packageFiles = $this->getPackageFiles( $context );
                        if ( $deprecationScript ) {
-                               $mainFile =& $packageFiles['files'][ $packageFiles['main'] ];
+                               $mainFile =& $packageFiles['files'][$packageFiles['main']];
                                $mainFile['content'] = $deprecationScript . $mainFile['content'];
                        }
                        return $packageFiles;
index 8cd5b19..d10be12 100644 (file)
@@ -73,7 +73,7 @@ class ResourceLoaderImage {
                }
                // Remove 'deprecated' key
                if ( is_array( $this->descriptor ) ) {
-                       unset( $this->descriptor[ 'deprecated' ] );
+                       unset( $this->descriptor['deprecated'] );
                }
 
                // Ensure that all files have common extension.
index e97e074..7d39a58 100644 (file)
@@ -28,15 +28,15 @@ class ResourceLoaderOOUIFileModule extends ResourceLoaderFileModule {
        use ResourceLoaderOOUIModule;
 
        public function __construct( $options = [] ) {
-               if ( isset( $options[ 'themeScripts' ] ) ) {
-                       $skinScripts = $this->getSkinSpecific( $options[ 'themeScripts' ], 'scripts' );
+               if ( isset( $options['themeScripts'] ) ) {
+                       $skinScripts = $this->getSkinSpecific( $options['themeScripts'], 'scripts' );
                        if ( !isset( $options['skinScripts'] ) ) {
                                $options['skinScripts'] = [];
                        }
                        $this->extendSkinSpecific( $options['skinScripts'], $skinScripts );
                }
-               if ( isset( $options[ 'themeStyles' ] ) ) {
-                       $skinStyles = $this->getSkinSpecific( $options[ 'themeStyles' ], 'styles' );
+               if ( isset( $options['themeStyles'] ) ) {
+                       $skinStyles = $this->getSkinSpecific( $options['themeStyles'], 'styles' );
                        if ( !isset( $options['skinStyles'] ) ) {
                                $options['skinStyles'] = [];
                        }
index 0a4e94e..0395127 100644 (file)
@@ -104,7 +104,7 @@ trait ResourceLoaderOOUIModule {
         */
        protected function getThemePath( $theme, $kind, $module ) {
                $paths = self::getThemePaths();
-               $path = $paths[ $theme ][ $kind ];
+               $path = $paths[$theme][$kind];
                $path = str_replace( '{module}', $module, $path );
                return $path;
        }
index 6393803..2dd6c17 100644 (file)
@@ -98,14 +98,14 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
 
                if ( !is_array( $logo ) ) {
                        // No media queries required if we only have one variant
-                       $preloadLinks[ $logo ] = [ 'as' => 'image' ];
+                       $preloadLinks[$logo] = [ 'as' => 'image' ];
                        return $preloadLinks;
                }
 
                if ( isset( $logo['svg'] ) ) {
                        // No media queries required if we only have a 1x and svg variant
                        // because all preload-capable browsers support SVGs
-                       $preloadLinks [ $logo['svg'] ] = [ 'as' => 'image' ];
+                       $preloadLinks[$logo['svg']] = [ 'as' => 'image' ];
                        return $preloadLinks;
                }
 
@@ -124,7 +124,10 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
                } );
 
                foreach ( $logosPerDppx as $dppx => $src ) {
-                       $logos[] = [ 'dppx' => $dppx, 'src' => $src ];
+                       $logos[] = [
+                               'dppx' => $dppx,
+                               'src' => $src
+                       ];
                }
 
                $logosCount = count( $logos );
@@ -138,21 +141,24 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
                                // Smallest dppx
                                // min-resolution is ">=" (larger than or equal to)
                                // "not min-resolution" is essentially "<"
-                               $media_query = 'not all and (min-resolution: ' . $logos[ 1 ]['dppx'] . 'dppx)';
+                               $media_query = 'not all and (min-resolution: ' . $logos[1]['dppx'] . 'dppx)';
                        } elseif ( $i !== $logosCount - 1 ) {
                                // In between
                                // Media query expressions can only apply "not" to the entire expression
                                // (e.g. can't express ">= 1.5 and not >= 2).
                                // Workaround: Use <= 1.9999 in place of < 2.
-                               $upper_bound = floatval( $logos[ $i + 1 ]['dppx'] ) - 0.000001;
-                               $media_query = '(min-resolution: ' . $logos[ $i ]['dppx'] .
+                               $upper_bound = floatval( $logos[$i + 1]['dppx'] ) - 0.000001;
+                               $media_query = '(min-resolution: ' . $logos[$i]['dppx'] .
                                        'dppx) and (max-resolution: ' . $upper_bound . 'dppx)';
                        } else {
                                // Largest dppx
-                               $media_query = '(min-resolution: ' . $logos[ $i ]['dppx'] . 'dppx)';
+                               $media_query = '(min-resolution: ' . $logos[$i]['dppx'] . 'dppx)';
                        }
 
-                       $preloadLinks[ $logos[$i]['src'] ] = [ 'as' => 'image', 'media' => $media_query ];
+                       $preloadLinks[$logos[$i]['src']] = [
+                               'as' => 'image',
+                               'media' => $media_query
+                       ];
                }
 
                return $preloadLinks;
index a91537f..9fad348 100644 (file)
@@ -433,7 +433,7 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
                                // Avoid including ids or timestamps of revision/page tables so
                                // that versions are not wasted
                                $title = new TitleValue( (int)$row->page_namespace, $row->page_title );
-                               $titleInfo[ self::makeTitleKey( $title ) ] = [
+                               $titleInfo[self::makeTitleKey( $title )] = [
                                        'page_len' => $row->page_len,
                                        'page_latest' => $row->page_latest,
                                        'page_touched' => $row->page_touched,
index ff1e8cb..22f5998 100644 (file)
@@ -22,6 +22,7 @@ class NullIndexField implements SearchIndexField {
         * @return $this
         */
        public function setFlag( $flag, $unset = false ) {
+               return $this;
        }
 
        /**
index 0e0a26a..101570f 100644 (file)
@@ -710,7 +710,6 @@ abstract class AuthManagerSpecialPage extends SpecialPage {
         * are shown closer to the bottom; weight defaults to 0. Negative weight is allowed.)
         * Keep order if weights are equal.
         * @param array &$formDescriptor
-        * @return array
         */
        protected static function sortFormDescriptorFields( array &$formDescriptor ) {
                $i = 0;
index 82bc84d..1b43a42 100644 (file)
@@ -1052,6 +1052,7 @@ abstract class ChangesListSpecialPage extends SpecialPage {
         *
         * There is light processing to simplify core maintenance.
         * @param array $definition
+        * @phan-param array<int,array{class:string}> $definition
         */
        protected function registerFiltersFromDefinitions( array $definition ) {
                $autoFillPriority = -1;
index 8df6493..722251d 100644 (file)
@@ -68,6 +68,7 @@ abstract class ImageQueryPage extends QueryPage {
 
        // Gotta override this since it's abstract
        function formatResult( $skin, $result ) {
+               return false;
        }
 
        /**
index b558d5e..155d6a4 100644 (file)
@@ -620,6 +620,7 @@ class SpecialBlock extends FormSpecialPage {
         *     the HTMLForm
         * @param WebRequest|null $request Optionally try and get data from a request too
         * @return array [ User|string|null, Block::TYPE_ constant|null ]
+        * @phan-return array{0:User|string|null,1:int|null}
         */
        public static function getTargetAndType( $par, WebRequest $request = null ) {
                $i = 0;
index 9d1b79e..36928ca 100644 (file)
@@ -44,7 +44,6 @@ class SpecialComparePages extends SpecialPage {
         * Show a form for filtering namespace and username
         *
         * @param string|null $par
-        * @return string
         */
        public function execute( $par ) {
                $this->setHeaders();
index 887f905..ded0891 100644 (file)
@@ -298,7 +298,6 @@ class SpecialEmailUser extends UnlistedSpecialPage {
         * Form to ask for target user name.
         *
         * @param string $name User name submitted.
-        * @return string Form asking for user name.
         */
        protected function userForm( $name ) {
                $htmlForm = HTMLForm::factory( 'ooui', [
index 619665b..9ea5e08 100644 (file)
@@ -154,7 +154,6 @@ class SpecialExpandTemplates extends SpecialPage {
         *
         * @param string $title Value for context title field
         * @param string $input Value for input textbox
-        * @return string
         */
        private function makeForm( $title, $input ) {
                $fields = [
index 2599b16..e8e5ea0 100644 (file)
@@ -132,6 +132,7 @@ class MIMEsearchPage extends QueryPage {
                        ->setMethod( 'get' )
                        ->prepareForm()
                        ->displayForm( false );
+               return '';
        }
 
        protected function getSuggestionsForTypes() {
index 52db060..7e41305 100644 (file)
@@ -44,6 +44,7 @@ class SpecialPageLanguage extends FormSpecialPage {
 
        protected function preText() {
                $this->getOutput()->addModules( 'mediawiki.special.pageLanguage' );
+               return parent::preText();
        }
 
        protected function getFormFields() {
index 51d6fd9..5f69426 100644 (file)
@@ -549,7 +549,6 @@ class SpecialUndelete extends SpecialPage {
         *
         * @param Revision $previousRev
         * @param Revision $currentRev
-        * @return string HTML
         */
        function showDiff( $previousRev, $currentRev ) {
                $diffContext = clone $this->getContext();
index da4398a..7a47edf 100644 (file)
@@ -393,7 +393,7 @@ class UploadForm extends HTMLForm {
         */
        public function show() {
                $this->addUploadJS();
-               parent::show();
+               return parent::show();
        }
 
        /**
index d05ebf8..88dff6e 100644 (file)
@@ -204,5 +204,6 @@ class NewFilesPager extends RangeChronologicalPager {
                        . htmlspecialchars( $time )
                        . "</i><br />\n"
                );
+               return '';
        }
 }
index f42b5a0..f2bc615 100644 (file)
@@ -77,7 +77,7 @@ class BatchRowUpdate {
                $this->reader = $reader;
                $this->writer = $writer;
                $this->generator = $generator;
-               $this->output = function () {
+               $this->output = function ( $text ) {
                }; // nop
        }
 
index 8aa7c87..c5ff9d6 100644 (file)
@@ -60,7 +60,13 @@ class LanguageConverter {
        public $mVariantFallbacks;
        public $mVariantNames;
        public $mTablesLoaded = false;
+
+       /**
+        * @var ReplacementArray[]
+        * @phan-var array<string,ReplacementArray>
+        */
        public $mTables;
+
        // 'bidirectional' 'unidirectional' 'disable' for each variant
        public $mManualLevel;
 
index 3030ab4..e2bdb21 100644 (file)
        "version-entrypoints-header-url": "ইউআৰএল",
        "version-libraries-version": "সংস্কৰণ",
        "redirect": "ফাইল, সদস্য, পৃষ্ঠা বা সংশোধন বা লগ আই ডি-ৰে পুনঃনিৰ্দেশ",
-       "redirect-summary": "এই বিশেষ পৃষ্ঠাটোৱে আপোনাক অন্য এটা ফাইললৈ (ফাইলৰ নাম), এটা পৃষ্ঠালৈ (সংশোধন আই ডি বা পৃষ্ঠা আই ডি), অথবা অন্য সদস্যৰ পৃষ্ঠালৈ (সদস্যৰ সাংখ্যিক আই ডি) পুনঃনির্দেশিত কৰিছে।\nব্যৱহাৰ: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], বা [[{{#Special:Redirect}}/user/101]]।",
+       "redirect-summary": "এই বিশেষ পৃষ্ঠাটোৱে আপোনাক অন্য এটা ফাইললৈ (ফাইলৰ নাম), এটা পৃষ্ঠালৈ (সংশোধন আই ডি বা পৃষ্ঠা আই ডি), অথবা অন্য সদস্যৰ পৃষ্ঠালৈ (সদস্যৰ সাংখ্যিক আই ডি), এটা সূচী ভুক্তিলৈ (প্ৰদত্ত সূচী ভুক্তি) পুনঃনির্দেশিত কৰিছে।\nব্যৱহাৰ: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]] বা [[{{#Special:Redirect}}/logid/186]]।",
        "redirect-submit": "যাওক",
        "redirect-lookup": "চাওক:",
        "redirect-value": "মূল্য:",
index cb005a9..e82a793 100644 (file)
@@ -80,6 +80,7 @@
        "tog-norollbackdiff": "Geri qaytardıqdan sonra dəyişikliklər arasındakı fərqi göstərmə",
        "tog-useeditwarning": "Qeyd edilməmiş dəyişikliyə sahib bir dəyişiklik səhifəsindən çıxarkən məni xəbərdar et",
        "tog-prefershttps": "Daxil olarkən hər zaman mühafizə edilən bağlantıdan istifadə et.",
+       "tog-showrollbackconfirmation": "Bir rollback linkinə kliklədiyinizdə təsdiq sorğusunu göstərin",
        "underline-always": "Həmişə",
        "underline-never": "Heç vaxt",
        "underline-default": "Susmaya görə brouzer",
        "createacct-reason-help": "Hesab yaratma qeydlərində göstərilən mesaj",
        "createacct-submit": "İstifadəçi hesabı yarat",
        "createacct-another-submit": "İstifadəçi hesabı yarat",
+       "createacct-continue-submit": "Hesab yaratmağı davam etdirin",
+       "createacct-another-continue-submit": "Hesab yaratmağı davam etdirin",
        "createacct-benefit-heading": "{{SITENAME}} sizin kimi insanlar tərəfindən yaradılır.",
        "createacct-benefit-body1": "{{PLURAL:$1|redaktə}}",
        "createacct-benefit-body2": "{{PLURAL:$1|səhifə|səhifə}}",
        "createacct-benefit-body3": "yeni {{PLURAL:$1|redaktor}}",
        "badretype": "Daxil etdiyiniz parol uyğun gəlmir.",
+       "usernameinprogress": "Bu istifadəçi adı üçün bir hesab yaratma artıq başlamışdır.\nZəhmət olmasa, gözləyin.",
        "userexists": "Daxil edilmiş ad artıq istifadədədir.\nLütfən başqa ad seçin.",
+       "createacct-normalization": "Texniki məhdudiyyətlər səbəbiylə istifadəçi adınız \"$2\" olaraq düzəldiləcək.",
        "loginerror": "Daxil olma xətası",
        "createacct-error": "Hesab yaratma xətası",
        "createaccounterror": "Bu istifadəçi adını yaratmaq mümkün olmadı: $1",
        "nocookieslogin": "{{SITENAME}} istifadəçilərin daxil ola bilməsi üçün \"cookie\"lərdən istifadə edir. Siz \"cookie\"lərin qəbuluna qadağa qoymusunuz. Lütfən, onların qəbuluna icazə verin və bir daha daxil olmağa cəhd edin.",
        "nocookiesfornew": "İstifadəçinin akkauntu yaradılmayıb, ona görə də biz onun mənbəsini təsdiqləyə bilmədik.\nKukların qoşulmasına əmin olduqdan sonra səhifəni yeniləyib bir daha sınayın.",
        "nocookiesforlogin": "{{int:nocookieslogin}}",
+       "createacct-loginerror": "Hesab müvəffəqiyyətlə yaradılıb, lakin avtomatik olaraq daxil olma mümkün olmadə. Zəhmət olmasa, [[Special:UserLogin|daxil olma]] səhifəsinə keçin.",
        "noname": "Siz mövcud olan istifadəçi adı daxil etməmisiniz.",
        "loginsuccesstitle": "Daxil oldunuz",
        "loginsuccess": "'''\"$1\" adı ilə sistemə daxil oldunuz.'''",
        "nosuchusershort": "\"$1\" adlı istifadəçi mövcud deyil. Yazdığınızı yoxlayın.",
        "nouserspecified": "İstifadəçi adı daxil etməlisiniz.",
        "login-userblocked": "Bu istifadəçi bloklanıb. Sistemə giriş üçün icazə verilmir.",
-       "wrongpassword": "Səhv parol. Təkrar yazın.",
+       "wrongpassword": "Yanlış istifadəçi adı və ya parol.\nZəhmət olmasa bir daha cəhd edin.",
        "wrongpasswordempty": "Parol boş. Təkrar yazın.",
        "passwordtooshort": "Parolda ən azı {{PLURAL:$1|1 hərf yaxud simvol|$1 hərf yaxud simvol}} olmalıdır.",
+       "passwordtoolong": "Parolda ən azı {{PLURAL:$1|1 hərf yaxud simvol|$1 hərf yaxud simvol}} olmalıdır.",
+       "passwordtoopopular": "Çox istifadə edilən parollar seçilə bilməz. Xahiş edirik təxmin edilməsi daha çətin olan bir parol seçin.",
+       "passwordinlargeblacklist": "Daxil edilən parol çox istifadə edilən parolların siyahısında mövcuddur. Xahiş edirik daha bənzərsiz parol seçin.",
        "password-name-match": "Parol adınızdan fərqli olmalıdır.",
        "password-login-forbidden": "Bu istifadəçi adından və paroldan istifadə qadağan olunub.",
        "mailmypassword": "E-mail ilə yeni parol göndər",
        "passwordremindertitle": "{{SITENAME}} parol xatırladıcı",
-       "passwordremindertext": "Kimsə (ehtimal ki, siz özünüz, $1 IP ünvanından) {{SITENAME}} ($4) layihəsi \nüçün yeni bir parol göndərilməsini istəyib. \"$2\" adlı istifadəçi üçün müvəqqəti \nolaraq \"$3\" parolu yaradılıb. Əgər bu sizin istəyiniz əsasında olubsa, \nhesabınıza daxil olaraq yeni bir parol yaratmağınız vacibdir. Müvəqqəti parolunuz\n{{PLURAL:$5|1 gün|$5 gün}} ərzində qüvvədə olacaqdır.\n\nParol dəyişdirməni siz istəməmisinizsə və ya parolunuzu xatırladınızsa \nvə artıq parolunuzu dəyişdirmək istəmirsinizsə, bu mesaja əhəmiyyət vermədən \nəvvəlki parolunuzdan istifadə etməyə davam edə bilərsiniz.",
+       "passwordremindertext": "Kimsə ($1 IP ünvanından) {{SITENAME}} ($4) layihəsi \nüçün yeni bir parol göndərilməsini istəyib. \"$2\" adlı istifadəçi üçün müvəqqəti \nolaraq \"$3\" parolu yaradılıb. Əgər bu sizin istəyiniz əsasında olubsa, \nhesabınıza daxil olaraq yeni bir parol yaratmağınız vacibdir. Müvəqqəti parolunuz\n{{PLURAL:$5|1 gün|$5 gün}} ərzində qüvvədə olacaqdır.\n\nParol dəyişdirməni siz istəməmisinizsə və ya parolunuzu xatırladınızsa \nvə artıq parolunuzu dəyişdirmək istəmirsinizsə, bu mesaja əhəmiyyət vermədən \nəvvəlki parolunuzdan istifadə etməyə davam edə bilərsiniz.",
        "noemail": "\"$1\" adlı istifadəçi e-poçt ünvanını qeyd etməmişdir.",
        "noemailcreate": "Düzgün e-poçt ünvanı qeyd etməlisiniz",
        "passwordsent": "Yeni parol \"$1\" üçün qeydiyyata alınan e-poçt ünvanına göndərilmişdir.\nXahiş edirik, e-məktubu aldıqdan sonra yenidən daxil olasınız.",
        "createaccount-text": "Biriləri {{SITENAME}} saytında ($4) sizin e-poçt ünvanınızdan istifadə edərək, parolu \"$3\" olan, \"$2\" adlı bir hesab yaratdı.\n\nSayta daxil olmalı və parolunuzu dəyişdirməlisiniz.\n\nƏgər istifadəçi hesabını səhvən yaratmısınızsa, bu mesajı gözardı edə bilərsiniz.",
        "login-throttled": "Sistemə daxil olmaq üçün həddən artıq cəhd etmisiniz.\nYeni cəhd etməzdən əvvəl $1 gözləyin.",
        "login-abort-generic": "Giriş uğursuz alındı — ləğv olundu",
+       "login-migrated-generic": "Hesabınız köçürüldü və bu vikidə istifadəçi adınız artıq mövcud deyil.",
        "loginlanguagelabel": "Dil: $1",
        "suspicious-userlogout": "Sizin çıxış üçün cəhdiniz uğursuz alındı. Bu, brouzerin yaxud proksi-keşləmənin düzgün işləməməsindən qaynaqlanır.",
        "createacct-another-realname-tip": "Gərçək adınız istəyə bağlıdır.\nƏgər gərçək adınızı göstərsəniz, çalışmalarınıza müraciət etmək üçün istifadə ediləcəkdir.",
        "pt-login": "Daxil ol",
        "pt-login-button": "Daxil ol",
+       "pt-login-continue-button": "Daxil olmağa davam edin",
        "pt-createaccount": "Hesab yarat",
        "pt-userlogout": "Çıxış",
        "php-mail-error-unknown": "PHP-nin mail() funksiyasında naməlum xəta",
        "retypenew": "Yeni parolu təkrar yazın:",
        "resetpass_submit": "Parol yaradın və sistemə daxil olun",
        "changepassword-success": "Parolunuz dəyişdirildi!",
+       "changepassword-throttled": "Sistemə daxil olmaq üçün həddən artıq cəhd etmisiniz.\nYeni cəhd etməzdən əvvəl $1 gözləyin.",
+       "botpasswords": "Bot parolları",
+       "botpasswords-summary": "<em>Bot parolları</em> hesabın əsas giriş etmə məlumatlarını istifadə etmədən API vasitəsilə bir istifadəçi hesabına giriş imkanı verir. Bir bot parol ilə daxil olduqda mövcud istifadəçi hüquqları məhdudlaşdırıla bilər.\n\nNiyə bunu edə biləcəyinizi bilmirsinizsə, bunu etməməlisiniz. Heç kim sizdən bunlardan birini yaratmağı və ona verməyinizi istəməyəcək.",
+       "botpasswords-disabled": "Bot parolları söndürüldü.",
+       "botpasswords-no-central-id": "Bot parollarını istifadə etmək üçün mərkəzləşdirilmiş bir hesaba daxil olmalısınız.",
+       "botpasswords-existing": "Mövcud bot parolları",
+       "botpasswords-createnew": "Yeni bot parolu yarat",
+       "botpasswords-editexisting": "Mövcud bot parolunu redaktə et",
+       "botpasswords-label-needsreset": "(parol sıfırlanmalıdır)",
        "botpasswords-label-appid": "Bot adı:",
        "botpasswords-label-create": "Yarat",
        "botpasswords-label-update": "Yenilə",
        "botpasswords-label-cancel": "Ləğv et",
        "botpasswords-label-delete": "Sil",
+       "botpasswords-label-resetpassword": "Parolu sıfırla",
+       "botpasswords-label-grants": "Tətbiq edilən hüquqlar:",
+       "botpasswords-help-grants": "Hüquqlar, istifadəçi hesabınız tərəfindən artıq saxlanılan hüquqlara giriş imkanı verir. Burada bir hüquq verilərkən, istifadəçi hesabınızın başqa cür olmadığı heç bir haqqı təmin etmir. Daha ətraflı məlumat üçün [[Special:ListGrants| hüquqlar]] səhifəsinə baxın.",
+       "botpasswords-label-grants-column": "Hüquq verildi",
+       "botpasswords-bad-appid": "\"$1\" bot adı etibarlı deyil.",
+       "botpasswords-insert-failed": "Bot adı \"$1\" əlavə etməyib. Artıq əlavə edilsin?",
+       "botpasswords-update-failed": "\"$1\" bot adı yenilənmədi. Silinsin?",
+       "botpasswords-created-title": "Bot parolu yaradıldı",
+       "botpasswords-created-body": "\"$2\" adlı istifadəçinin \"$1\" bot adı üçün bot parolu yaradıldı.",
+       "botpasswords-updated-title": "Bot parolu yeniləndi",
+       "botpasswords-updated-body": "\"$2\" adlı istifadəçinin \"$1\" bot adı üçün bot parolu yeniləndi.",
+       "botpasswords-deleted-title": "Bot parolu silindi",
+       "botpasswords-deleted-body": "\"$2\" adlı istifadəçinin \"$1\" bot adı üçün bot parolu silindi.",
+       "botpasswords-newpassword": "<strong>$1</strong> ilə daxil olmaq üçün yeni parol: <strong>$2</strong>. <em> Gələcək arayış üçün qeyd edin. </em> <br> (Giriş adının nüfuzlu istifadəçi adı ilə eyni olmasını tələb edən köhnə botlara görə <strong>$3</strong> istifadəçi adını və <strong>$4</strong> parolunu da istifadə edə bilərsiniz)",
+       "botpasswords-no-provider": "BotPasswordsSessionProvider mövcud deyil.",
+       "botpasswords-restriction-failed": "Bot parol məhdudiyyətləri bu girişə mane olur.",
+       "botpasswords-invalid-name": "Göstərilən istifadəçi adı bot ayırıcısını (\"$1\") ehtiva etmir.",
+       "botpasswords-not-exist": "\"$1\" istifadəçisinin \"$2\" adlı bot parolu yoxdur.",
+       "botpasswords-needs-reset": "\"$1\" adlı istifadəçinin \"$2\" bot adı üçün bot parolu sıfırlanmalıdır.",
+       "botpasswords-locked": "Hesabınız kilidləndiyinə görə bot parolu ilə giriş edə bilməzsiniz.",
        "resetpass_forbidden": "Parolu dəyişmək mümkün deyil",
+       "resetpass_forbidden-reason": "Parolu dəyişmək mümkün deyil: $1",
        "resetpass-no-info": "Bu səhifəni birbaşa açmaq üçün sistemə daxil olmalısınız.",
        "resetpass-submit-loggedin": "Parolu dəyiş",
        "resetpass-submit-cancel": "Ləğv et",
        "resetpass-wrong-oldpass": "Müvəqqəti və ya daimi parolda yanlışlıq var.\nOla bilər siz parolu müvəffəqiyyətlə dəyişmisiniz, yaxud yeni müvəqqəti parol üçün müraciət etmisiniz.",
+       "resetpass-recycled": "Şifrənizi, mövcud parolunuzdan başqa bir şeyə dəyişdirin.",
+       "resetpass-temp-emailed": "Siz müvəqqəti e-poçt kodu ilə daxil oldunuz. \nDaxil olmağı bitirmək üçün buraya yeni bir parol yazmalısınız:",
        "resetpass-temp-password": "Müvəqqəti parol:",
        "resetpass-abort-generic": "Parol dəyişikliyi bir genişlənmə tərəfindən ləğv edildi.",
+       "resetpass-expired": "Parolunuzun müddəti doldu. Giriş etmək üçün yeni bir parol təyin edin.",
+       "resetpass-expired-soft": "Parolunuzun müddəti başa çatdı və dəyişdirilməlidir. Xahiş edirik yeni bir parol seçin və ya daha sonra dəyişdirmək üçün \"{{int:authprovider-resetpass-skip-label}}\" düyməsini basın.",
+       "resetpass-validity": "Parolunuz etibarlı deyil: $1\n\nGiriş etmək üçün yeni bir parol təyin edin.",
+       "resetpass-validity-soft": "Parolunuz etibarlı deyil: $1\n\nXahiş edirik yeni bir parol seçin və ya daha sonra dəyişdirmək üçün \"{{int: authprovider-resetpass-skip-label}}\" düyməsini basın.",
        "passwordreset": "Parolu yenilə",
        "passwordreset-text-one": "Parolunuzu sıfırlamaq üçün bu formanı doldurun.",
        "passwordreset-text-many": "{{PLURAL:$1|Parolunuzu sıfırlamaq üçün sahələrdən birini doldurun.}}",
        "passwordreset-email": "E-mail ünvanı:",
        "passwordreset-emailtitle": "{{SITENAME}} hesabın yaradılması",
        "passwordreset-emailtext-ip": "Kimsə, (ehtimal ki siz özünüz, $1 IP adresindən) {{SITENAME}} ($4) layihəsindəki hesabınızın \nparolunun yenilənməsini istəyib. Aşağıdakı istifadəçi {{PLURAL:$3|hesabı|hesabları}} bu e-poçt adresinə bağlıdır:\n\n$2\n\nBu müvəqqəti {{PLURAL:$3|parol|parollar}} {{PLURAL:$5|bir gün|$5 gün}} qüvvədə olacaqdır.\nSiz müvəqqəti parolla daxil olub yeni bir parol seçməlisiniz. Əgər parolun dəyişdirilməsini siz istəməmisinizsə və ya parolunuzu xatırladınızsa və artıq onu dəyişmək istəmirsinizsə, bu məktuba əhəmiyyət verməyərək köhnə parolunuzu istifadə etməyə davam edə bilərsiniz.",
+       "passwordreset-emailtext-user": "Kimsə, ($1 IP adresindən) {{SITENAME}} ($4) layihəsindəki hesabınızın \nparolunun sıfırlanmasını istəyib. Aşağıdakı istifadəçi {{PLURAL:$3|hesabı|hesabları}} bu e-poçt adresinə bağlıdır:\n\n$2\n\nBu müvəqqəti {{PLURAL:$3|parol|parollar}} {{PLURAL:$5|bir gün|$5 gün}} qüvvədə olacaqdır.\nSiz müvəqqəti parolla daxil olub yeni bir parol seçməlisiniz. Əgər parolun dəyişdirilməsini siz istəməmisinizsə və ya parolunuzu xatırladınızsa və artıq onu dəyişmək istəmirsinizsə, bu məktuba əhəmiyyət verməyərək köhnə parolunuzu istifadə etməyə davam edə bilərsiniz.",
        "passwordreset-emailelement": "İstifadəçi adı: \n$1\n\nMüvəqqəti parol: \n$2",
        "passwordreset-emailsentemail": "Əgər bu imeyl sizin istifadəçi hesabınıza bağlıdırsa, o halda parol sıfırlama məktubu ora göndəriləcək.",
+       "passwordreset-emailsentusername": "Əgər bu e-poçt sizin istifadəçi hesabınıza bağlıdırsa, o halda parol sıfırlama məktubu ora göndəriləcək.",
+       "passwordreset-nocaller": "Çağırıcı təmin edilməlidir",
+       "passwordreset-nosuchcaller": "Çağırıcı yoxdur: $1",
+       "passwordreset-ignored": "Parolun sıfırlanması işlənməmişdir. Bəlkə heç bir provayder qurulmayıb?",
        "passwordreset-invalidemail": "Səhv e-poçt",
+       "passwordreset-nodata": "Nə bir istifadəçi adı, nə də bir e-poçt ünvanı verilmədi.",
        "changeemail": "E-məktub ünvanını dəyiş və ya sil",
+       "changeemail-header": "E-poçt ünvanınızı dəyişdirmək üçün bu formanı tamamlayın. Hesabınızdakı hər hansı bir e-poçt ünvanının birləşməsini aradan qaldırmaq istəyirsinizsə, formu təqdim edərkən yeni e-poçt ünvanını boş buraxın.",
+       "changeemail-no-info": "Bu səhifəni birbaşa açmaq üçün sistemə daxil olmalısınız.",
        "changeemail-oldemail": "Hazırkı e-poçt ünvanı:",
        "changeemail-newemail": "Yeni e-poçt ünvanı:",
+       "changeemail-newemail-help": "E-poçt ünvanınızı çıxarmaq istəyirsinizsə, bu sahə boş olmalıdır. Unudulan bir parolu sıfırlaya bilməyəcəksiniz və e-poçt ünvanı çıxarıldıqda bu vikidən e-poçt ala bilməyəcəksiniz.",
        "changeemail-none": "(yoxdur)",
+       "changeemail-password": "Sizin {{SITENAME}} parolunuz:",
        "changeemail-submit": "E-poçtu dəyiş",
+       "changeemail-throttled": "Sistemə daxil olmaq üçün həddən artıq cəhd etmisiniz.\nYeni cəhd etməzdən əvvəl $1 gözləyin.",
+       "changeemail-nochange": "Fərqli bir yeni e-poçt ünvanı daxil edin.",
+       "resettokens": "Jetonları sıfırla",
+       "resettokens-text": "Hesabınızla əlaqəli müəyyən şəxsi məlumatlara giriş imkanı verən jetonlar sıfırlana bilər.\n\nTəsadüfən kimsə ilə paylaşdığınız təqdirdə və ya hesabınız pozulduğu halda bunu etməlisiniz.",
+       "resettokens-no-tokens": "Sıfırlanacaq heç bir jeton yoxdur.",
+       "resettokens-tokens": "Jetonlar:",
+       "resettokens-token-label": "$1 (cari dəyər: $2)",
+       "resettokens-watchlist-token": "[[Special:Watchlist|İzləmə siyahınızdakı]] səhifələrdə dəyişikliklərin web feed-i (Atom / RSS) üçün jeton",
+       "resettokens-done": "Jetonlar sıfırlandı.",
+       "resettokens-resetbutton": "Seçilmiş jetonları sıfırla",
        "bold_sample": "Qalın mətn",
        "bold_tip": "Qalın mətn",
        "italic_sample": "Kursiv mətn",
        "publishchanges": "Dəyişiklikləri yayımla",
        "savearticle-start": "Səhifəni dərc et...",
        "savechanges-start": "Dəyişiklikləri yadda saxla...",
+       "publishpage-start": "Səhifəni yayımla...",
+       "publishchanges-start": "Dəyişiklikləri yayımla...",
        "preview": "Sınaq görüntüsü",
        "showpreview": "Sınaq göstərişi",
        "showdiff": "Dəyişiklikləri göstər",
+       "blankarticle": "<strong>Xəbərdarlıq:</strong> Yaratdığınız səhifə boşdur. Əgər bir daha \"$1\" düyməsinə klikləsəniz, səhifə heç bir məzmun olmadan yaradılacaq.",
        "anoneditwarning": "<strong>Diqqət:</strong> Siz sistemə daxil olmamısınız. Hər hansı dəyişiklik etsəniz, sizin IP-ünvanınız hamıya görünəcək. Əgər <strong>[$1 daxil olsanız]</strong> və ya <strong>[$2 hesab yaratsanız]</strong>, redaktələriniz sizin istifadəçi adınıza yazılacaq və digər üstünlüklər də qazanacaqsınız.",
        "anonpreviewwarning": "Sistemə daxil olmamısınız. \"Səhifəni qeyd et\" düyməsini bassanız IP ünvanınız səhifənin tarixçəsində qeyd olunacaq.",
        "missingsummary": "'''Xatırlatma.''' Siz dəyişikliklərin qısa şərhini verməmisiniz. \"Səhifəni qeyd et\" düyməsinə təkrar basandan sonra sizin dəyişiklikləriniz şərhsiz qeyd olunacaq.",
+       "selfredirect": "<strong>Xəbərdarlıq:</strong> Bu səhifəni özünüzə istiqamətləndirirsiniz.\nİstiqamətləndirmə üçün yanlış hədəf göstərə bilərsiniz və ya səhv səhifəni redaktə edə bilərsiniz.\nYenidən \"$1\" düyməsinə bassanız, yenidən istiqamətləndirmə yaradılacaq.",
        "missingcommenttext": "Zəhmət olmasa, şərh yazın.",
+       "missingcommentheader": "<strong>Xatırlatma:</strong> Bu şərh üçün bir mövzu vermədiniz.\nYenidən \"$1\" düyməsinə basarsanız, düzəlişiniz heçnəsiz saxlanacaq.",
        "summary-preview": "Dəyişikliyin izahının görünüşü:",
        "subject-preview": "Sərlövhə belə olacaq:",
+       "previewerrortext": "Redaktələrinizin sınaq görüntüsü göstərilərkən bir səhv baş verdi.",
        "blockedtitle": "İstifadəçi bloklanıb",
+       "blocked-email-user": "<strong>İstifadəçi adınız e-poçt göndərməkdən bloklanmışdır. Siz hələ də bu vikidə redaktə edə bilərsiniz.</strong> Tam blok detallarını [[Special:MyContributions|istifadəçi fəaliyyətləri]] səhifəsində görə bilərsiniz.\n\nBloklayan: $1\nVerilmiş səbəb:<em>$2</em>\n\n*Blokun başlaması: $8\n*Blokun bitməsi: $6\n*Blok məqsədi: $7\n*Blok ID:#$5",
+       "blockedtext-partial": "<strong>İstifadəçi adınız bu səhifəni redaktə etməkdən bloklanmışdır. Siz bu vikidə digər səhifələrdə redaktə edə bilərsiniz.</strong> Tam blok detallarını [[Special:MyContributions|istifadəçi fəaliyyətləri]] səhifəsində görə bilərsiniz.\n\nBloklayan: $1\nVerilmiş səbəb:<em>$2</em>\n\n*Blokun başlaması: $8\n*Blokun bitməsi: $6\n*Blok məqsədi: $7\n*Blok ID:#$5",
+       "blockedtext": "<strong>Sizin istifadəçi adınız və ya IP ünvanınız bloklanmışdır.</strong>\n\nBloklayan: $1\nSəbəb: <em>$2</em>\n\n*Blokun başlaması: $8\n*Blokun bitməsi: $6\n*Blok məqsədi:$7\n\nSiz $1 ilə və ya  [[{{MediaWiki:Grouppage-sysop}}|digər idarəçilərlə]] bloku müzakirə edə bilərsiniz.\n[[Special:Preferences|Nizamlamalarda]] etibarlı bir e-poçt ünvanı göstərilmədikcə və onu istifadə etməmisinizsə, \"{{int: emailuser}}\" funksiyasından istifadə edə bilməzsiniz.\nSizin IP ünvanınız: $3\nBlok ID: #$5\nXahiş etdiyiniz hər hansı bir sorğuda yuxarıda göstərilən məlumatları daxil edin.",
+       "autoblockedtext": "Sizin IP ünvanınız avtomatik olaraq bloklanıb, çünki digər bloklanmış istifadəçi tərəfindən istifadə edilib.\n\nBloklayan: $1\nSəbəb: <em>$2</em>\n\n*Blokun başlaması: $8\n*Blokun bitməsi: $6\n*Blok məqsədi:$7\n\nSiz $1 ilə və ya  [[{{MediaWiki:Grouppage-sysop}}|digər idarəçilərlə]] bloku müzakirə edə bilərsiniz.\n[[Special:Preferences|Nizamlamalarda]] etibarlı bir e-poçt ünvanı göstərilmədikcə və onu istifadə etməmisinizsə, \"{{int: emailuser}}\" funksiyasından istifadə edə bilməzsiniz.\nSizin IP ünvanınız: $3\nBlok ID: #$5\nXahiş etdiyiniz hər hansı bir sorğuda yuxarıda göstərilən məlumatları daxil edin.",
+       "systemblockedtext": "Sizin istifadəçi adınız və ya IP ünvanınız MediaWiki tərəfindən avtomatik olaraq bloklanıb.\n\nSəbəb: <em>$2</em>\n\n*Blokun başlaması: $8\n*Blokun bitməsi: $6\n*Blok məqsədi:$7\n\n\nSizin IP ünvanınız: $3\nXahiş etdiyiniz hər hansı bir sorğuda yuxarıda göstərilən məlumatları daxil edin.",
        "blockednoreason": "səbəb göstərilməyib",
        "whitelistedittext": "Dəyişiklik edə bilmək üçün $1.",
        "confirmedittext": "Siz elektron ünvanınızı səhifədə dəyişiklik etməzdən əvvəl göstərməlisiniz.\nZəhmət olmasa elektron ünvanınızı [[Special:Preferences|istifadəçi nizamlaması]] səhifənizdə göstərib təsdiq ediniz.",
        "accmailtext": "[[User talk:$1|$1]] üçün təsadüfi yolla yaradılmış parol $2 ünvanına göndərildi.\nHesabınıza daxil olduqdan sonra, parolunuzu ''[[Special:ChangePassword|parolu dəyiş]]'' səhifəsində dəyişdirə bilərsiniz.",
        "newarticle": "(Yeni)",
        "newarticletext": "Mövcud olmayan səhifəyə olan keçidi izlədiniz. Aşağıdakı sahəyə məzmununu yazaraq bu səhifəni '''siz''' yarada bilərsiniz. (əlavə məlumat üçün [$1 kömək səhifəsinə] baxın). Əgər bu səhifəyə səhvən gəlmisinizsə sadəcə olaraq brauzerin '''geri''' düyməsinə vurun.",
-       "anontalkpagetext": "----\n<em>Bu səhifə qeydiyyatdan keçməmiş və ya daxil olmamış anonim istifadəçiyə aid müzakirə səhifəsidir.</em>\nOna görə bu istifadəçini rəqəmlərdən ibarət IP ünvanı ilə müəyyən etmək məcburiyyətindəyik.\nBelə IP-ünvan bir neçə fərd tərəfindən istifadədə ola bilər.\nƏgər siz anonim istifadəçisinizsə və bu mesajın sizə aid olmadığını düşünürsünüzsə, onda [[Special:CreateAccount|qeydiyyatdan keçin]] və ya [[Special:UserLogin|daxil olun]] ki, digər anonim istifadəçilərlə qarışıqlıq yaşamayasınız.",
+       "anontalkpagetext": "----\n<em>Bu səhifə qeydiyyatdan keçməmiş və ya daxil olmamış anonim istifadəçiyə aid müzakirə səhifəsidir.</em>\nOna görə bu istifadəçini rəqəmlərdən ibarət IP ünvanı ilə müəyyən etmək məcburiyyətindəyik.\nBelə IP ünvan bir neçə fərd tərəfindən istifadədə ola bilər.\nƏgər siz anonim istifadəçisinizsə və bu mesajın sizə aid olmadığını düşünürsünüzsə, onda [[Special:CreateAccount|qeydiyyatdan keçin]] və ya [[Special:UserLogin|daxil olun]] ki, digər anonim istifadəçilərlə qarışıqlıq yaşamayasınız.",
        "noarticletext": "Hal-hazırda bu səhifə boşdur. Başqa səhifələrdə eyni adda səhifəni [[Special:Search/{{PAGENAME}}|axtara]], əlaqəli qeydlərə\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} baxa] və ya [{{fullurl:{{FULLPAGENAME}}|action=edit}} bu adda səhifəni yarada]</span> bilərsiniz.",
        "noarticletext-nopermission": "Hal-hazırda bu səhifə boşdur. Başqa səhifələrdə eyni adlı səhifəni [[Special:Search/{{PAGENAME}}| axtara]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} əlaqəli qeydlərə baxa] və ya səhifəni [{{fullurl:{{FULLPAGENAME}}|action=edit}} redaktə edə bilərsiniz]</span>, lakin sizin bu məqaləni yaratmaq hüququnuz yoxdur.",
+       "missing-revision": "\"{{FULLPAGENAME}}\" adlı səhifənin #$1 versiyası mövcud deyil.\n\nBu adətən silinmiş bir səhifəyə köhnəlmiş keçid bağlantısı ilə bağlıdır. Detallar üçün [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} silmə qeydlərinə] baxın.",
        "userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" istifadəçi adı qeydiyyata alınmayıb.\nƏgər siz bu səhifəni yaratmaq/redaktə etmək istəyirsinizsə, xahiş edirik bunu yoxlayın.",
        "userpage-userdoesnotexist-view": "\"$1\" istifadəçi hesabı qeydiyyatda deyil",
        "blocked-notice-logextract": "Bu istifadəçi hal-hazırda bloklanmışdır.\nBloklama qeydlərinin sonuncusu aşağıda göstərilmişdir:",
index f5f5c7f..1d04cc6 100644 (file)
        "alllogstext": "Сумесны паказ усіх журналаў падзеяў {{GRAMMAR:родны|{{SITENAME}}}}.\nВы можаце адфільтраваць вынікі па тыпе журналу, удзельніку (улічваецца рэгістар) ці старонцы (таксама ўлічваецца рэгістар).",
        "logempty": "Падобных запісаў у журнале няма.",
        "log-title-wildcard": "Шукаць назвы, якія пачынаюцца з гэтага тэксту",
-       "showhideselectedlogentries": "Ð\9fаказаÑ\86Ñ\8c\81Ñ\85аваÑ\86Ñ\8c Ð²Ñ\8bбÑ\80анÑ\8bÑ\8f Ð·Ð°Ð¿Ñ\96Ñ\81Ñ\8b Ñ\9e журнале",
+       "showhideselectedlogentries": "Ð\97Ñ\8cмÑ\8fнÑ\96Ñ\86Ñ\8c Ð±Ð°Ñ\87наÑ\81Ñ\8cÑ\86Ñ\8c Ð°Ð±Ñ\80анÑ\8bÑ\85 Ð·Ð°Ð¿Ñ\96Ñ\81аÑ\9e Ñ\83 журнале",
        "log-edit-tags": "Рэдагаваць меткі да абраных запісаў у журнале падзеяў",
        "checkbox-select": "Выбраць: $1",
        "checkbox-all": "усе",
index afe6fa4..18327aa 100644 (file)
        "histfirst": "সবচেয়ে পুরনো",
        "histlast": "সবচেয়ে নতুন",
        "historysize": "({{PLURAL:$1|১ বাইট|$1 বাইট}})",
-       "historyempty": "(খালি)",
+       "historyempty": "খালি",
        "history-feed-title": "সংশোধনের ইতিহাস",
        "history-feed-description": "এই উইকিতে এই পাতার সংশোধনের ইতিহাস",
        "history-feed-item-nocomment": "$2-এ $1",
index 91fede1..a39d2be 100644 (file)
        "brokenredirectstext": "Tato přesměrování vedou na neexistující stránky:",
        "brokenredirects-edit": "editovat",
        "brokenredirects-delete": "smazat",
-       "withoutinterwiki": "Stránky bez mezijazykových odkazů (interwiki)",
+       "withoutinterwiki": "Stránky bez mezijazykových odkazů",
        "withoutinterwiki-summary": "Tyto stránky neobsahují žádný mezijazykový odkaz:",
        "withoutinterwiki-legend": "Prefix",
        "withoutinterwiki-submit": "Zobrazit",
index 64344d7..9612ca7 100644 (file)
        "pageinfo-robot-index": "Erlaubt",
        "pageinfo-robot-noindex": "Nicht erlaubt",
        "pageinfo-watchers": "Anzahl der Beobachter dieser Seite",
-       "pageinfo-visiting-watchers": "Anzahl der Beobachter dieser Seite, die die letzten Bearbeitungen besucht haben",
+       "pageinfo-visiting-watchers": "Anzahl der Beobachter dieser Seite, welche die letzten Bearbeitungen besucht haben",
        "pageinfo-few-watchers": "Weniger als {{PLURAL:$1|ein|$1}} Beobachter",
        "pageinfo-few-visiting-watchers": "Es könnte einen beobachtenden Benutzer geben oder nicht, der die letzten Bearbeitungen besucht hat",
        "pageinfo-redirects-name": "Anzahl der Weiterleitungen zu dieser Seite",
index eb0d1f4..686ea02 100644 (file)
        "deleting-subpages-warning": "<strong>Oharra:</strong> Ezabatuko duzun orrialdeak [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|a subpage|$1 subpages|51=over 50 subpages}}]] dauka.",
        "rollback": "Desegin aldaketak",
        "rollback-confirmation-confirm": "Mesedez baieztatu:",
+       "rollback-confirmation-yes": "Desegin",
        "rollback-confirmation-no": "Utzi",
        "rollbacklink": "desegin",
        "rollbacklinkcount": "desegin {{PLURAL:$1|edizio bat|$1 edizio}}",
        "confirm-unwatch-top": "Orrialde hau zure jarraipen-zerrendatik kendu?",
        "confirm-rollback-button": "Ados",
        "confirm-rollback-top": "Orrialde honen edizioak leheneratu?",
+       "confirm-rollback-bottom": "Ekintza honek orrialde honetan hautatutako aldaketak zuzenean desegingo ditu.",
        "confirm-mcrrestore-title": "Errebisio bat berritu",
        "confirm-mcrundo-title": "Aldaketa bat desegin",
        "mcrundofailed": "Desegiteak akatsa",
index 9ba8e44..a323e26 100644 (file)
        "exif-compression-6": "JPEG (vecchio)",
        "exif-copyrighted-true": "Protetto da copyright",
        "exif-copyrighted-false": "Status del copyright non impostato",
+       "exif-photometricinterpretation-0": "Bianco e nero (bianco è 0)",
        "exif-photometricinterpretation-1": "Bianco e nero (nero è 0)",
+       "exif-photometricinterpretation-3": "Tavolozza",
+       "exif-photometricinterpretation-4": "Maschera di trasparenza",
+       "exif-photometricinterpretation-5": "Separato (probabilmente CMYK)",
+       "exif-photometricinterpretation-8": "CIE L*a*b*",
+       "exif-photometricinterpretation-9": "CIE L*a*b* (codifica ICC)",
+       "exif-photometricinterpretation-10": "CIE L*a*b* (codifica ITU)",
        "exif-unknowndate": "Data sconosciuta",
        "exif-orientation-1": "Normale",
        "exif-orientation-2": "Capovolto orizzontalmente",
index 5253e8d..89a5d4b 100644 (file)
        "exif-gpsspeed-n": "Јазли",
        "exif-gpsdestdistance-k": "Километри",
        "exif-gpsdestdistance-m": "Милји",
-       "exif-gpsdestdistance-n": "Ð\9dаÑ\83Ñ\82иÑ\87ки милји",
+       "exif-gpsdestdistance-n": "Ð\9cоÑ\80Ñ\81ки милји",
        "exif-gpsdop-excellent": "Одлична ($1)",
        "exif-gpsdop-good": "Добра ($1)",
        "exif-gpsdop-moderate": "Умерена ($1)",
index ee2b147..da07076 100644 (file)
        "createacct-loginerror": "Tunnus luotiin onnistuneesti, mutta automaattista sisäänkirjautumista ei voitu tehdä. Siirry [[Special:UserLogin|manuaaliseen kirjautumiseen]].",
        "noname": "Et ole määritellyt kelvollista käyttäjänimeä.",
        "loginsuccesstitle": "Olet kirjautunut sisään",
-       "loginsuccess": "'''Olet kirjautunut sivustolle {{SITENAME}} käyttäjänä $1.'''",
+       "loginsuccess": "<strong>Olet kirjautunut {{GRAMMAR:illative|{{SITENAME}}}} käyttäjänä \"$1\".</strong>",
        "nosuchuser": "Käyttäjää ”$1” ei ole olemassa.\nNimet ovat kirjainkoosta riippuvaisia. \nTarkista, kirjoititko nimen oikein, tai [[Special:CreateAccount|luo uusi käyttäjätunnus]].",
        "nosuchusershort": "Käyttäjää nimeltä ”$1” ei ole. Kirjoititko nimen oikein?",
        "nouserspecified": "Käyttäjätunnusta ei ole määritelty.",
        "upload-form-label-own-work": "Tämä on oma työni",
        "upload-form-label-infoform-categories": "Luokat",
        "upload-form-label-infoform-date": "Päivämäärä",
-       "upload-form-label-own-work-message-generic-local": "Vakuutan, että tallennan tämän tiedoston noudattaen sivustolla {{SITENAME}} voimassa olevia käyttöehtoja sekä lisenssejä koskevia käytäntöjä.",
+       "upload-form-label-own-work-message-generic-local": "Vakuutan, että tallennan tämän tiedoston noudattaen {{GRAMMAR:inessive|{{SITENAME}}}} voimassa olevia käyttöehtoja sekä lisenssejä koskevia käytäntöjä.",
        "upload-form-label-not-own-work-message-generic-local": "Jos et kykene tallentamaan tätä tiedostoa noudattaen niitä käytäntöjä, jotka ovat voimassa sivustolla {{SITENAME}}, sulje tämä dialogi ja kokeile jotain toista menetelmää.",
        "upload-form-label-not-own-work-local-generic-local": "Voit myös kokeilla [[Special:Upload|yleistä tallentamista]].",
        "upload-form-label-own-work-message-generic-foreign": "Ymmärrän, että olen tallentamassa tätä tiedostoa yhteiseen mediasäilöön. Vakuutan, että teen tämän noudattaen asiaankuuluvia käyttöehtoja ja lisenssejä koskevia käytäntöjä.",
        "emailuser-title-target": "Lähetä sähköpostia tälle {{GENDER:$1|käyttäjälle}}",
        "emailuser-title-notarget": "Lähetä sähköpostia käyttäjälle",
        "emailpagetext": "Jos tämä {{GENDER:$1|käyttäjä}} on antanut asetuksissaan kelvollisen sähköpostiosoitteen, alla olevalla lomakkeella voit lähettää hänelle viestin. [[Special:Preferences|Omissa asetuksissasi]] annettu sähköpostiosoite näkyy sähköpostin lähettäjän osoitteena, jotta vastaanottaja voi suoraan vastata viestiin.",
-       "defemailsubject": "Sähköpostia käyttäjältä $1 sivustolta {{SITENAME}}",
+       "defemailsubject": "Sähköpostia käyttäjältä $1 {{GRAMMAR:elative|{{SITENAME}}}}",
        "usermaildisabled": "Käyttäjien sähköposti poistettu käytöstä",
        "usermaildisabledtext": "Et voi lähettää sähköpostia muille käyttäjille tässä wikissä",
        "noemailtitle": "Ei sähköpostiosoitetta",
        "confirmemail_body_set": "Joku, todennäköisesti sinä, IP-osoitteesta $1 on vaihtanut {{GRAMMAR:inessive|{{SITENAME}}}} tunnuksen $2 sähköpostiosoitteeksi tämän osoitteen.\n\nVarmenna, että tämä tunnus kuuluu sinulle ja aktivoi sähköpostitoiminnot uudelleen avaamalla seuraava linkki selaimellasi:\n\n$3\n\nJos tunnus ei kuulu sinulle, peruuta sähköpostiosoitteen varmennus avaamalla seuraava linkki:\n\n$5\n\nVarmennuskoodi vanhenee $4.",
        "confirmemail_invalidated": "Sähköpostiosoitteen varmennus peruutettiin",
        "invalidateemail": "Sähköpostiosoitteen varmennuksen peruuttaminen",
-       "notificationemail_subject_changed": "Sivuston {{SITENAME}} rekisteröity sähköpostiosoite on vaihdettu",
-       "notificationemail_subject_removed": "Sivuston {{SITENAME}} rekisteröity sähköpostiosoite on poistettu",
+       "notificationemail_subject_changed": "{{GRAMMAR:genitive|{{SITENAME}}}} rekisteröity sähköpostiosoite on vaihdettu",
+       "notificationemail_subject_removed": "{{GRAMMAR:genitive|{{SITENAME}}}} rekisteröity sähköpostiosoite on poistettu",
        "notificationemail_body_changed": "Joku, todennäköisesti sinä, IP-osoitteesta $1 on vaihtanut tunnuksen ”$2” sähköpostiosoitteeksi ”$3” sivustolla {{SITENAME}}.\n\nJos se et ollut sinä, ota yhteyttä sivuston ylläpitäjään välittömästi.",
        "notificationemail_body_removed": "Joku, todennäköisesti sinä, IP-osoitteesta $1 on poistanut tunnuksen ”$2” sähköpostiosoitteen sivustolla {{SITENAME}}.\n\nJos se et ollut sinä, ota yhteyttä sivuston ylläpitäjään välittömästi.",
        "scarytranscludedisabled": "[Wikienvälinen sisällytys ei ole käytössä]",
index 6126782..af36afc 100644 (file)
@@ -37,6 +37,7 @@
        "tog-watchdefault": "Sides dy't jo feroare hawwe folgje",
        "tog-watchmoves": "Siden dy't jo werneamd hawwe folgje",
        "tog-watchdeletion": "Siden dy't jo wiske hawwe folgje",
+       "tog-watchrollback": "Siden dêr't ik wizigings weromdraaid haw oan myn folchlist taheakje",
        "tog-minordefault": "Markearje alle feroarings standert as fan lytse betsjutting",
        "tog-previewontop": "By it neisjen, bewurkingsfjild ûnderoan sette",
        "tog-previewonfirst": "Lit foarbyld sjen by earste wiziging",
@@ -59,6 +60,7 @@
        "tog-diffonly": "Side-ynhâld dy't feroare wurdt net sjen litte",
        "tog-showhiddencats": "Ferburgen kategoryen werjaan",
        "tog-norollbackdiff": "Gjin ferskillen sjen litte nei it útfieren fan weromdraaien",
+       "tog-showrollbackconfirmation": "Befêstigingsdialooch sjen litte by it klikken op 'weromdraaie'",
        "underline-always": "Altyd",
        "underline-never": "Nea",
        "underline-default": "Webblêder-standert",
        "accmailtitle": "Wachtwurd ferstjoerd.",
        "accmailtext": "Samar in wachtwurd foar [[User talk:$1|$1]] is ferstjoerd nei $2. It kin wizige wurde op 'e side \n<em>[[Special:ChangePassword|Wachtwurd feroarje]]</em> nei oanmelden.",
        "newarticle": "(Nij)",
-       "newarticletext": "Jo hawwe in keppeling folge nei in side dêr't noch gjin tekst op stiet.\nOm sels tekst te meistjsen kinne jo dy gewoan yntype in dit bewurkingsfjild\n([$1 Mear ynformaasje oer bewurkjen].)\nOars kinne jo tebek mei de tebek-knop fan jo blêder.",
+       "newarticletext": "Jo hawwe in keppeling folge nei in side dêr't noch gjin tekst op stiet.\nBegjin mei skriuwen yn it fjild hjirûnder om de side oan te meitsjen (sjoch de [$1 helpside] foar mear ynformaasje).\nKlik op de <strong>tebek</strong>-knop fan jo webblêder at jo hjir by ûngelok telâne kommen binne.",
        "anontalkpagetext": "----\n<em>Dit is de oerlisside fan in ûnbekende meidogger; in meidogger dy't him/har net oanmeld hat.</em>\nOm't der gjin namme bekend is, wurdt it ynternet-adres brûkt om oan te jaan om wa't it giet.\nMar faak is it sa dat sa'n adres net altyd troch deselde persoan brûkt wurdt.\nAs jo it idee hawwe dat jo as ûnbekende meidogger opmerkings foar in oar krije, dan kinne jo jo [[Special:CreateAccount|registrearje]], of jo [[Special:UserLogin|oanmelde]]. Fan in oanmelde meidogger is it ynternet-adres net sichtber, en as oanmelde meidogger krije jo allinnich opmerkings dy't foar josels bedoeld binne.",
        "noarticletext": "Der stiet noch gjin tekst op dizze side.\nJo kinne [[Special:Search/{{PAGENAME}}|nei dizze sidenamme sykje]] yn oare siden,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} de besibbe lochs trochsykje]\nof [{{fullurl:{{FULLPAGENAME}}|action=edit}} dizze side oanmeitsje]</span>.",
        "userpage-userdoesnotexist": "Jo bewurkje in meidoggerside fan in meidogger dy't net bestiet (meidogger \"<nowiki>$1</nowiki>\").\nKontrolearje oft jo dizze side wol oanmeitsje/bewurkje wolle.",
        "right-siteadmin": "De database blokkearje en wer frij jaan",
        "right-override-export-depth": "Alle siden oant en mei in keppelingsdjipte fan fiif fuortskriuwe",
        "grant-group-email": "E-mail stjoere",
+       "grant-rollback": "Wizigings oan siden weromdraaie",
        "newuserlogpage": "Ynskriuwingsloch",
        "newuserlogpagetext": "Dit is in loch fan meidoggers dy't de lêste tiid ynskreaun binne.",
        "rightslog": "Rjochtenloch",
        "rcfilters-legend-heading": "<strong>List fan ôfkoartings:</strong>",
        "rcnotefrom": "Dit binne de feroarings sûnt <b>$2</b> (maksimaal <b>$1</b>).",
        "rclistfrom": "Jou nije feroarings, begjinnende mei $3 $2",
-       "rcshowhideminor": "lytse feroarings $1",
+       "rcshowhideminor": "Lytse feroarings $1",
        "rcshowhideminor-show": "werjaan",
        "rcshowhideminor-hide": "ferbergje",
-       "rcshowhidebots": "bots $1",
+       "rcshowhidebots": "Bots $1",
        "rcshowhidebots-show": "werjaan",
        "rcshowhidebots-hide": "ferbergje",
        "rcshowhideliu": "Registrearre meidoggers $1",
        "rcshowhideliu-show": "werjaan",
        "rcshowhideliu-hide": "ferbergje",
-       "rcshowhideanons": "$1 anonimen",
+       "rcshowhideanons": "Anonime meidoggers $1",
        "rcshowhideanons-show": "werjaan",
        "rcshowhideanons-hide": "ferbergje",
        "rcshowhidepatr": "kontrolearre bewurkings $1",
        "rcshowhidepatr-show": "werjaan",
        "rcshowhidepatr-hide": "ferbergje",
-       "rcshowhidemine": "$1 eigen bewurkings",
+       "rcshowhidemine": "Myn bewurkings $1",
        "rcshowhidemine-show": "werjaan",
        "rcshowhidemine-hide": "ferbergje",
        "rclinks": "Jou $1 nije feroarings yn de lêste $2 dagen",
        "deletereasonotherlist": "Oare reden",
        "deletereason-dropdown": "*Faak-brûkte redenen\n** Frege troch de skriuwer\n** Skeining fan auteursrjocht\n** Fandalisme",
        "rollback": "Wizigings weromdraaie",
+       "rollback-confirmation-yes": "Weromdraaie",
        "rollbacklink": "weromdraaie",
        "rollbacklinkcount": "$1 {{PLURAL:$1|bewurking|bewurkings}} weromdraaie",
        "rollbacklinkcount-morethan": "mear as $1 {{PLURAL:$1|bewurking|bewurkings}} weromdraaie",
        "tooltip-ca-talk": "Oerlis oer de ynhâldlike side",
        "tooltip-ca-edit": "Dizze side bewurkje",
        "tooltip-ca-addsection": "In opmerking tafoegje oan de oerlis-side.",
-       "tooltip-ca-viewsource": "Dizze side is befeilige, mar jo kinne de boarne wol besjen.",
+       "tooltip-ca-viewsource": "Dizze side is skoattele, mar jo kinne de boarne wol besjen.",
        "tooltip-ca-history": "Eardere ferzjes fan dizze side",
        "tooltip-ca-protect": "Dizze side befeiligje",
        "tooltip-ca-delete": "Dizze side weidwaan",
        "markedaspatrollederror-noautopatrol": "Jo meie jo eigen bewurkings net sels markearre.",
        "previousdiff": "← Eardere ferskillen",
        "nextdiff": "Neikommende ferskillen →",
-       "imagemaxsize": "Behein ôfmjittings fan ôfbyld op beskriuwingsside ta:",
-       "thumbsize": "Mjitte fan miniatueren:",
+       "imagemaxsize": "Beheining fan 'e ôfbyldingsgrutte op bestânsbeskriuwingssiden:",
+       "thumbsize": "Miniatuergrutte:",
        "widthheight": "$1 × $2",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|side|siden}}",
        "file-info": "bestânsgrutte: $1, MIME-type: $2",
        "noimages": "Neat te sjen.",
        "ilsubmit": "Sykje",
        "bydate": "datum",
+       "sp-newimages-showfrom": "Nije bestannen besjen fan $2, $1 ôf",
        "video-dims": "$1, $2 × $3",
        "seconds-abbrev": "$1 s",
        "minutes-abbrev": "$1 min",
        "confirm-watch-button": "OK",
        "confirm-unwatch-button": "OK",
        "confirm-unwatch-top": "Dizze side fan myn folchlist ôfhelje",
+       "confirm-rollback-bottom": "Dizze hanneling sil de oanjûne sidewizigings fuortdaliks weromdraaie.",
        "semicolon-separator": ";&#32;",
        "comma-separator": ",&#32;",
        "colon-separator": ":&#32;",
        "tag-mw-blank": "Leech meitsjen",
        "tag-mw-replace": "Ferfongen",
        "tag-mw-rollback": "Weromdraaid",
+       "tag-mw-rollback-description": "Bewurkings mei de keppeling 'weromdraaie', dy't foargeande wizigings ûngedien makke hawwe",
        "tag-mw-undo": "Ungedien meitsjen",
        "tags-source-header": "Boarne",
        "tags-active-header": "Aktyf?",
index 5cb261c..3a9e31c 100644 (file)
        "edit-already-exists": "Հրարավոր չէ նոր էջ ստեղծել․ այն արդեն գոյություն ունի։",
        "defaultmessagetext": "Լռելյան տեքստը",
        "editwarning-warning": "Այս էջը լքելով դուք կարող եք կորցնել ձեր կատարած փոփոխությունները։\nԵթե դուք գրանցված եք համակարգում, կարող եք անջատել այս նախազգուշացումը ձեր նախընրությունների «{{int:prefs-editing}}» բաժնում։",
+       "slot-name-main": "Հիմնական",
        "content-model-wikitext": "վիքիտեքստ",
        "content-model-text": "պարզ տեքստ",
        "content-model-javascript": "ՋավաՍկրիպտ",
        "rcfilters-other-review-tools": "Վերանայման այլ գործիքներ",
        "rcfilters-group-results-by-page": "Արդյունքները խմբավորել էջերով",
        "rcfilters-activefilters": "Ակտիվ զտիչներ",
+       "rcfilters-activefilters-hide": "Թաքցնել",
+       "rcfilters-activefilters-show": "Ցուցադրել",
        "rcfilters-advancedfilters": "Ընդլայնված ֆիլտրեր",
        "rcfilters-limit-title": "Ցուցադրվող արդյունքներ",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|փոփոխություն|փոփոխություններ}}, $2",
        "upload-misc-error-text": "Տեղի ունեցավ անհայտ սխալ բեռնման ընթացքում։ Խնդրում ենք ստուգել URL-հասցեի ճշտությունն ու հասանելիությունը և փորձել կրկին։ Սխալի կրկնման դեպքում կապնվեք համակարգային ադմինիստրատորի հետ։",
        "upload-dialog-title": "Բեռնել նիշք",
        "upload-dialog-button-cancel": "Չեղարկել",
+       "upload-dialog-button-back": "Հետ",
        "upload-dialog-button-done": "Արված է",
        "upload-dialog-button-save": "Հիշել",
        "upload-dialog-button-upload": "Բեռնել",
        "license-nopreview": "(Նախադիտումը մատչելի չէ)",
        "upload_source_url": " (գործուն, հանրամատչելի URL-հասցե)",
        "upload_source_file": " (նիշք ձեր համակարգչի վրա)",
+       "listfiles-delete": "ջնջել",
        "listfiles_search_for": "Որոնել պատկերի անվամբ.",
        "imgfile": "նիշք",
        "listfiles": "Նիշքերի ցանկ",
        "protectedpages": "Պաշտպանված էջեր",
        "protectedpages-noredirect": "Թաքցնել վերահղումները",
        "protectedpagesempty": "Ներկայումս չկան պաշտպանված էջեր նշված պարամետրերով։",
+       "protectedpages-page": "Էջ",
+       "protectedpages-expiry": "Լրանում է",
        "protectedpages-submit": "Ցույց տալ էջերը",
+       "protectedpages-unknown-timestamp": "Անհայտ",
        "protectedtitles": "Պաշտպանված անվանումներ",
        "protectedtitles-submit": "Ցույց տալ վերնագրերը",
        "listusers": "Մասնակիցների ցանկ",
        "notargettext": "Դուք չեք նշել նպատակային էջ կամ մասնակից այս ֆունկցիայի գործածման համար։",
        "pager-newer-n": "{{PLURAL:$1|ավելի թարմ 1|ավելի թարմ $1}}",
        "pager-older-n": "{{PLURAL:$1|ավելի հին 1|ավելի հին $1}}",
+       "apisandbox-reset": "Մաքրել",
+       "apisandbox-retry": "Կրկնել",
+       "apisandbox-examples": "Օրինակներ",
+       "apisandbox-add-multi": "Ավելացնել",
+       "apisandbox-results": "Արդյունք",
+       "apisandbox-continue": "Շարունակել",
+       "apisandbox-continue-clear": "Մաքրել",
        "booksources": "Գրքային աղբյուրներ",
        "booksources-search-legend": "Գրքի մասին տեղեկությունների որոնում",
        "booksources-search": "Որոնել",
        "alllogstext": "{{SITENAME}} կայքի տեղեկամատյանների համընդհանուր ցանկ։\nԴուք կարող եք սահմանափակել արդյունքները ըստ տեղեկամատյանի տեսակի, մասնակցի անունի կամ համապատասխան էջի։",
        "logempty": "Տեղեկամատյանում չկան համընկնող տարրեր։",
        "log-title-wildcard": "Որոնել այս տեքստով սկսվող անվանումներ",
+       "checkbox-all": "Բոլորը",
+       "checkbox-none": "Ոչ մեկը",
        "allpages": "Բոլոր էջերը",
        "nextpage": "Հաջորդ էջը ($1)",
        "prevpage": "Նախորդ էջը ($1)",
        "activeusers": "Ակտիվ մասնակիցների ցանկ",
        "activeusers-noresult": "Այդպիսի մասնակիցներ չեն գտնվել։",
        "activeusers-submit": "Ցույց տալ ակտիվ մասնակիցներին",
+       "listgrouprights-group": "Խումբ",
        "listgrouprights-members": "(անդամների ցանկ)",
        "listgrouprights-addgroup": "Ավելացնեել {{PLURAL:$2|խումբ|խմբեր}}՝  $1",
        "mailnologin": "Ուղարկման հասցե չկա",
        "delete-edit-reasonlist": "Խմբագրել ջնջման պատճառները",
        "deleting-backlinks-warning": "'''Զգուշացում''', ձեր կողմից ջնջվող էջին հղվում են [[Special:WhatLinksHere/{{FULLPAGENAME}}|այլ հոդվածներ]]:",
        "rollback": "Հետ գլորել խմբագրումները",
+       "rollback-confirmation-no": "Չեղարկել",
        "rollbacklink": "հետ գլորել",
        "rollbacklinkcount": "հետ գլորել $1 {{PLURAL:$1|խմբագրում}}",
        "rollbacklinkcount-morethan": "հետ գլորել ավելի քան $1 {{PLURAL:$1|խմբագրում|խմբագրում}}",
        "rollback-success": "Հետ են շրջվել $1 մասնակցի խմբագրումները. վերադարձվել է $2 մասնակցի վերջին տարբերակին։",
        "sessionfailure-title": "Սեսիայի խափանում",
        "sessionfailure": "Կարծես խնդիր է առաջացել կապված ձեր ընթացիկ աշխատանքային սեսիայի հետ.\nայս գործողությունը բեկանվել է սեսիայի հափշտակման կանխման նպատակով։\nԽնդրում ենք սեղմել «back» կոճակը և վերբեռնել այն էջը որտեղից եկել եք ու փորձել կրկին։",
+       "changecontentmodel-submit": "Փոխել",
        "protectlogpage": "Պաշտպանման տեղեկամատյան",
        "protectlogtext": "Ստորև բերված է պաշտպանված և պաշտպանումից հանված էջերի ցանկը։ Տես նաև [[Special:ProtectedPages|ներկայումս պաշտպանված էջերի ցանկը]]։",
        "protectedarticle": "պաշտպանվեց «[[$1]]» էջը",
        "createaccountblock": "մասնակցային հաշվի ստեղծումը արգելափակված է",
        "emailblock": "էլ-փոստը արգելափակված",
        "blocklist-nousertalk": "չի կարող խմբագրել իր քննարկման էջը",
+       "blocklist-editing-page": "էջեր",
+       "blocklist-editing-ns": "անվանատարածքներ",
        "ipblocklist-empty": "Արգելափակումների ցանկը դատարկ է։",
        "ipblocklist-no-results": "Նշված IP-հասցեն կամ մասնակցի անունը արգելափակված չէ։",
        "blocklink": "արգելափակել",
        "allmessages-filter-all": "Բոլորը",
        "allmessages-language": "Լեզու",
        "allmessages-filter-submit": "Անցնել",
+       "allmessages-filter-translate": "Թարգմանել",
        "thumbnail-more": "Ընդարձակել",
        "filemissing": "Նման նիշք չկա",
        "thumbnail_error": "Պատկերիկի ստեղծման սխալ. $1",
        "pageinfo-display-title": "Վերնագիր",
        "pageinfo-default-sort": "Լռելյայն տեսակավորման բանալի",
        "pageinfo-length": "Ծավալ (բայթերով)",
+       "pageinfo-namespace": "Անվանատարածք",
        "pageinfo-article-id": "Էջի N",
        "pageinfo-language": "Բովանդակության լեզու",
        "pageinfo-language-change": "փոխել",
        "pageinfo-content-model": "Էջի բովանդակության մոդելը",
+       "pageinfo-content-model-change": "փոխել",
        "pageinfo-robot-policy": "Կարգավիճակը որոնողական համակարգերում",
        "pageinfo-robot-index": "ինդեքսավորվող",
        "pageinfo-robot-noindex": "ինդեքսավորվող չէ",
        "confirm-watch-top": "Ավելացնե՞լ ձեր հսկացանկին",
        "confirm-unwatch-button": "Լավ",
        "confirm-unwatch-top": "Հեռացնե՞լ Ձեր հսկացանկից։",
+       "confirm-rollback-button": "Լավ",
        "imgmultipageprev": "← նախորդ էջ",
        "imgmultipagenext": "հաջորդ էջ →",
        "imgmultigo": "Անցնե՛լ",
index b14ea23..15d49ef 100644 (file)
        "histfirst": "le plus ancian",
        "histlast": "le plus nove",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
-       "historyempty": "(vacue)",
+       "historyempty": "vacue",
        "history-feed-title": "Historia de versiones",
        "history-feed-description": "Historia del versiones de iste pagina in le wiki",
        "history-feed-item-nocomment": "$1 a $2",
        "right-reupload-own": "Superscriber un file anteriormente incargate per uno mesme",
        "right-reupload-shared": "Supplantar localmente le files del respositorio commun de media",
        "right-upload_by_url": "Incargar un file ab un adresse URL",
-       "right-purge": "Purgar le cache de un pagina in le sito sin confirmation",
+       "right-purge": "Purgar le cache de un pagina in le sito",
        "right-autoconfirmed": "Non esser subjecte al limites de frequentia a base de adresse IP",
        "right-bot": "Esser tractate como processo automatic",
        "right-nominornewtalk": "Non reciper notification de nove messages quando se face modificationes minor in le pagina de discussion",
        "mycontris": "Contributiones",
        "anoncontribs": "Contributiones",
        "contribsub2": "Pro {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Pro {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Le conto de usator \"$1\" non es registrate.",
        "negative-namespace-not-supported": "Le spatios de nomines con valores negative non es supportate.",
        "nocontribs": "Nulle modification correspondente a iste criterios ha essite trovate.",
index d77ab4c..1c6b41b 100644 (file)
        "botpasswords-label-cancel": "Hætta við",
        "botpasswords-label-delete": "Eyða",
        "botpasswords-label-resetpassword": "Endurstilla lykilorðið",
+       "botpasswords-label-grants": "Tiltækar heimildir:",
        "botpasswords-bad-appid": "Vélmennanafnið „$1“ er ógilt.",
        "botpasswords-created-title": "Vélmennalykilorð var búið til",
        "botpasswords-updated-title": "Vélmennalykilorð var uppfært",
        "prefs-help-prefershttps": "Þessi stilling tekur gildi í næsta skiptið sem þú skráir þig inn.",
        "prefswarning-warning": "Þú hefur gert breytingar á kjörstillingum þínum sem ekki er búið að vista.\nEf þú ferð af þessari síðu án þess að smella á \"$1\" verða kjörstillingar þínar ekki uppfærðar.",
        "prefs-tabs-navigation-hint": "Ábending: Þú getur notað vinstri og hægri örvalyklana til að flakka á milli flipa í flipalistanum.",
-       "userrights": "Notandaréttindi",
+       "userrights": "Réttindi notenda",
        "userrights-lookup-user": "Velja notanda",
        "userrights-user-editname": "Skráðu notandanafn:",
        "editusergroup": "Hlaða inn notanda hópum",
        "speciallogtitlelabel": "Beinist að (titill eða {{ns:user}}:notandanafn fyrir notanda):",
        "log": "Aðgerðaskrár",
        "logeventslist-submit": "Birta",
+       "logeventslist-patrol-log": "Yfirferðarskrá",
+       "logeventslist-tag-log": "Aðgerðaskrá yfir merki",
        "all-logs-page": "Allar aðgerðir",
        "alllogstext": "Safn allra aðgerðaskráa {{SITENAME}}.\nÞú getur takmarkað listann með því að velja tegund aðgerðaskráar, notandanafn, eða síðu.",
        "logempty": "Engin slík aðgerð fannst.",
        "listgrouprights-namespaceprotection-header": "Takmarkanir nafnrýmis",
        "listgrouprights-namespaceprotection-namespace": "Nafnrými",
        "listgrouprights-namespaceprotection-restrictedto": "Réttindi sem leyfa notanda að breyta",
+       "listgrants": "Veittar heimildir",
        "listgrants-rights": "Réttindi",
        "listgrants-grant-display": "$1 <code>($2)</code>",
        "trackingcategories-name": "Heiti skilaboða",
        "specialpages-group-highuse": "Mest notuðu síðurnar",
        "specialpages-group-pages": "Listar yfir síður",
        "specialpages-group-pagetools": "Síðuverkfæri",
-       "specialpages-group-wiki": "Gögn og tól",
+       "specialpages-group-wiki": "Gögn og verkfæri",
        "specialpages-group-redirects": "Tilvísaðar kerfissíður",
        "specialpages-group-spam": "Amasendingasíur",
        "specialpages-group-developer": "Forritaratól",
index bfec830..70afeed 100644 (file)
        "histfirst": "ഏറ്റവും പഴയവ",
        "histlast": "ഏറ്റവും പുതിയവ",
        "historysize": "({{PLURAL:$1|1 ബൈറ്റ്|$1 ബൈറ്റുകൾ}})",
-       "historyempty": "(ശൂന്യം)",
+       "historyempty": "ശൂന്യം",
        "history-feed-title": "നാൾവഴി",
        "history-feed-description": "വിക്കിയിൽ ഈ താളിന്റെ നാൾവഴി",
        "history-feed-item-nocomment": "$2 സമയത്ത് $1",
        "right-reupload-own": "സ്വയം അപ്‌ലോഡ് ചെയ്ത പ്രമാണങ്ങൾക്കു മുകളിലേയ്ക്ക് പ്രമാണങ്ങൾ അപ്‌ലോഡ് ചെയ്യുക",
        "right-reupload-shared": "പങ്ക് വെയ്ക്കപ്പെട്ട മീഡിയ സംഭരണിയെ പ്രാദേശികമായി അതിലംഘിക്കുക",
        "right-upload_by_url": "യു.ആർ.എല്ലിൽ നിന്നും പ്രമാണങ്ങൾ അപ്‌ലോഡ് ചെയ്യുക",
-       "right-purge": "à´¸àµ\8dഥിരàµ\80à´\95à´°à´£à´\82 à´\92à´¨àµ\8dà´¨àµ\81à´\82 à´\87à´²àµ\8dലാതàµ\86 à´¸àµ\88à´±àµ\8dറിനàµ\8dà´±àµ\86 à´\95ാഷàµ\86 à´\92à´°àµ\81 à´¤à´¾à´³à´¿à´¨à´¾à´¯à´¿ à´ªàµ¼à´\9càµ\8d à´\9aàµ\86à´¯àµ\8dà´¯àµ\81à´\95",
+       "right-purge": "സൈറ്റിന്റെ കാഷെ ഒരു താളിനായി പർജ് ചെയ്യുക",
        "right-autoconfirmed": "ഐ.പി. അധിഷ്ഠിത പരിധികൾ ബാധകമല്ല",
        "right-bot": "യാന്ത്രിക പ്രവൃത്തിയായി കണക്കാക്കപ്പെടുന്നു",
        "right-nominornewtalk": "സംവാദം താളുകളിലെ ചെറുതിരുത്തലുകൾ പുതിയ സന്ദേശങ്ങളുണ്ടെന്ന അറിയിപ്പിനു കാരണമാകരുത്",
index 7f03be9..dfaf649 100644 (file)
        "histfirst": "oudste",
        "histlast": "nieuwste",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
-       "historyempty": "(leeg)",
+       "historyempty": "leeg",
        "history-feed-title": "Bewerkingsoverzicht",
        "history-feed-description": "Bewerkingsoverzicht voor deze pagina op de wiki",
        "history-feed-item-nocomment": "$1 op $3 om $4",
index 09ed79b..213ce6d 100644 (file)
        "previewerrortext": "Wystąpił błąd podczas próby podglądu Twoich zmian.",
        "blockedtitle": "Użytkownik jest zablokowany",
        "blocked-email-user": "<strong>Twoje konto zostało wyłączone z wysyłania wiadomości emaili innym użytkownikom. Wciąż możesz edytować inne strony na wiki.</strong> Więcej szczegółów na temat blokady znajdziesz na swojej [[Special:MyContributions|stroni wkładu]].\n\nBlokada została nałożona przez $1.\n\nPodany powód to: <em>$2</em>.\n\n* Początek blokady: $8\n* Wygaśnięcie blokady: $6\n* Zablokowany został: $7\n* Identyfikator blokady: #$5",
-       "blockedtext-partial": "<strong>Twoje konto lub adres IP zostało wyłączone z dokonywania zmian na tej stronie. Wciąż możesz edytować inne strony na wiki.</strong> Więcej szczegółów na temat blokady znajdziesz na swojej [[Special:MyContributions|stroni wkładu]].\n\nBlokada została nałożona przez $1.\n\nPodany powód to: <em>$2</em>.\n\n* Początek blokady: $8\n* Wygaśnięcie blokady: $6\n* Zablokowany został: $7\n* Identyfikator blokady: #$5",
+       "blockedtext-partial": "<strong>Twoje konto lub adres IP zostało wyłączone z dokonywania zmian na tej stronie. Wciąż możesz edytować inne strony na wiki.</strong> Więcej szczegółów na temat blokady znajdziesz na swojej [[Special:MyContributions|stronie swojego wkładu]].\n\nBlokada została nałożona przez $1.\n\nPodany powód to: <em>$2</em>.\n\n* Początek blokady: $8\n* Wygaśnięcie blokady: $6\n* Zablokowany został: $7\n* Identyfikator blokady: #$5",
        "blockedtext": "<strong>Twoje konto lub adres IP zostały zablokowane.</strong>\n\nBlokada została nałożona przez $1.\nPodany powód to: <em>$2</em>.\n\n* Początek blokady: $8\n* Wygaśnięcie blokady: $6\n* Zablokowany został: $7\n\nW celu wyjaśnienia przyczyny zablokowania możesz się skontaktować z $1 lub innym [[{{MediaWiki:Grouppage-sysop}}|administratorem]].\nNie możesz użyć funkcji „{{int:emailuser}}”, jeśli brak jest poprawnego adresu e‐mail w Twoich [[Special:Preferences|preferencjach]] lub jeśli taka możliwość została Ci zablokowana.\nTwój obecny adres IP to $3, a numer identyfikacyjny blokady to #$5.\nProsimy o podanie obu tych informacji przy wyjaśnianiu blokady.",
        "autoblockedtext": "Ten adres IP został zablokowany automatycznie, gdyż korzysta z niego inny użytkownik, zablokowany przez administratora $1.\nPowód blokady:\n\n:<em>$2</em>\n\n* Początek blokady: $8\n* Wygaśnięcie blokady: $6\n* Zablokowany został: $7\n\nMożesz skontaktować się z $1 lub jednym z pozostałych [[{{MediaWiki:Grouppage-sysop}}|administratorów]] w celu uzyskania informacji o blokadzie.\n\nNie możesz użyć funkcji „{{int:emailuser}}”, jeśli brak jest poprawnego adresu e‐mail w Twoich [[Special:Preferences|preferencjach]] lub jeśli taka możliwość została Ci zablokowana.\n\nTwój obecny adres IP to $3, a numer identyfikacyjny blokady to #$5.\nProsimy o podanie obu tych numerów przy wyjaśnianiu blokady.",
        "systemblockedtext": "Twoja nazwa użytkownika lub adres IP zostały automatycznie zablokowane przez MediaWiki.\nPodany powód to:\n\n:<em>$2</em>\n\n* Początek blokady: $8\n* Wygaśnięcie blokady: $6\n* Zamierzano zablokować: $7\n\nTwój obecny adres IP to $3.\nProsimy o dołączenie powyższych szczegółów w jakichkolwiek zadawanych pytaniach.",
index 9768a57..f6a73cc 100644 (file)
        "histfirst": "ᱢᱟᱨᱮᱱᱟᱜ",
        "histlast": "ᱱᱟᱣᱟᱱᱟᱜ",
        "historysize": "({{PLURAL:$1 1 ᱵᱟᱭᱤᱴ $1 ᱵᱟᱭᱤᱴᱥ}})",
-       "historyempty": "(ᱠᱷᱟᱹᱞᱤ)",
+       "historyempty": "ᱠᱷᱟᱹᱞᱤ",
        "history-feed-title": "ᱥᱩᱫᱷᱨᱟᱹᱣ ᱱᱟᱜᱟᱢ",
        "history-feed-description": "ᱣᱤᱠᱤᱨᱮ ᱱᱤᱭᱟᱹ ᱥᱟᱦᱴᱟ ᱵᱚᱫᱚᱞ ᱨᱮᱱᱟᱜ ᱱᱟᱜᱟᱢ",
        "history-feed-item-nocomment": "$2 ᱨᱮ $1",
        "enhancedrc-history": "ᱱᱟᱜᱟᱢ",
        "recentchanges": "ᱨᱚᱠᱟ ᱵᱚᱫᱚᱞᱠᱚ",
        "recentchanges-legend": "ᱱᱟᱣᱟᱱᱟ ᱵᱚᱫᱚᱞ ᱛᱮᱭᱟᱜᱠᱚ",
-       "recentchanges-summary": "á±±á±\9aá±£á±\9f á±¥á±\9fᱦᱴá±\9fᱨᱮ á±©á±­á± á±¤ á±¨á±®á±­á±\9fá±\9c á±¡á±\9aá±\9bá±\9a á± á±·á±\9aá±± á±±á±\9fá±£á±\9f á±µá±\9aᱫá±\9aá±\9eá± á±\9a á±¯á±\9fᱸᱡá±\9fᱸᱭᱢᱮ᱾",
+       "recentchanges-summary": "á±±á±\9aᱶá±\9f á±¥á±\9fᱦᱴá±\9fᱨᱮ á±£á±¤á± á±¤ á±¨á±®á±­á±\9fá±\9c á±¡á±\9aá±\9bá±\9a á± á±·á±\9aá±± á±¨á±\9aá± á±\9f á±µá±\9aᱫá±\9aá±\9eá± á±\9a á±¯á±\9fᱸᱡá±\9fᱸᱭᱢᱮ ᱾",
        "recentchanges-noresult": "ᱮᱢᱞᱮᱱ ᱥᱚᱢᱚᱭ ᱵᱷᱤᱛᱤᱨ ᱨᱮ ᱵᱚᱫᱚᱞᱟᱜ ᱠᱚ ᱵᱟᱭ ᱢᱤᱫᱩᱜ ᱠᱟᱱᱟ ᱾",
-       "recentchanges-feed-description": "ᱱᱚᱣᱟ feed ᱨᱮ ᱩᱭᱠᱤ ᱨᱮᱭᱟᱜ ᱡᱚᱛᱚ ᱠᱷᱚᱱ ᱱᱟᱣᱟ ᱵᱚᱫᱚᱞᱠᱚ ᱯᱟᱸᱡᱟᱸᱭᱢᱮ᱾",
+       "recentchanges-feed-description": "ᱱᱚᱣᱟ ᱯᱷᱤᱰ ᱨᱮ ᱣᱤᱠᱤ ᱨᱮᱭᱟᱜ ᱡᱚᱛᱚ ᱠᱷᱚᱱ ᱱᱟᱣᱟ ᱵᱚᱫᱚᱞᱠᱚ ᱯᱟᱸᱡᱟᱸᱭᱢᱮ᱾",
        "recentchanges-label-newpage": "ᱱᱚᱣᱟ ᱥᱟᱯᱲᱟᱣ ᱢᱤᱫᱴᱮᱱ ᱱᱟᱣᱟ ᱥᱟᱦᱴᱟᱭ ᱛᱮᱭᱟᱨᱠᱮᱫᱟ",
        "recentchanges-label-minor": "ᱱᱚᱣᱟ ᱫᱚ ᱦᱩᱰᱤᱧ ᱥᱟᱯᱲᱟᱣ ᱠᱟᱱᱟ",
        "recentchanges-label-bot": "ᱱᱚᱣᱟ ᱥᱟᱯᱲᱟᱣ ᱫᱚ ᱵᱚᱴ ᱮ ᱠᱚᱨᱟᱣᱠᱟᱫᱟ",
index e500f94..92f4efd 100644 (file)
        "mergehistory-comment": "Spojeno [[:$1]] u [[:$2]]: $3",
        "mergehistory-same-destination": "Izvorne i odredišne stranice ne mogu biti iste",
        "mergehistory-reason": "Razlog:",
-       "mergelog": "Registar spajanja",
+       "mergelog": "Evidencija spajanja",
        "revertmerge": "Ukini spajanje",
        "mergelogpagetext": "Ispod je spisak nedavnih spajanja historija stranica.",
        "history-title": "Historija izmjena stranice \"$1\"",
        "grant-viewdeleted": "Pregled obrisanih datoteka i stranica",
        "grant-viewmywatchlist": "Pregled vaših praćenja",
        "grant-viewrestrictedlogs": "Pregledanje ograničenih unosa u zapisniku",
-       "newuserlogpage": "Registar novih korisnika",
+       "newuserlogpage": "Evidencija novih korisnika",
        "newuserlogpagetext": "Ovo je evidencija registracije novih korisnika.",
        "rightslog": "Evidencija korisničkih prava",
        "rightslogtext": "Ovo je evidencija izmjene korisničkih prava.",
        "upload-permitted": "{{PLURAL:$2|Podržana vrsta|Podržane vrste}} datoteka: $1.",
        "upload-preferred": "{{PLURAL:$2|Preferirana vrsta|Preferirane vrste}} datoteka: $1.",
        "upload-prohibited": "{{PLURAL:$2|Zabranjena vrsta|Zabranjene vrste}} datoteka: $1.",
-       "uploadlogpage": "Registar postavljanja",
+       "uploadlogpage": "Evidencija postavljanja",
        "uploadlogpagetext": "Ispod je popis najnovijih postavljanja datoteka.\nVidi [[Special:NewFiles|galeriju novih datoteka]] za slikovitiji pregled.",
        "filename": "Ime fajla / Име датотеке",
        "filedesc": "Sažetak - Опис",
        "changecontentmodel-nodirectediting": "Model sadržaja $1 ne podržava izravno uređivanje",
        "changecontentmodel-emptymodels-title": "Nema dostupnih modela sadržaja",
        "changecontentmodel-emptymodels-text": "Model sadržaja stranice [[:$1]] se ne može pretvoriti ni u jedan drugi tip.",
-       "log-name-contentmodel": "Zapisnik promjene modela sadržaja",
+       "log-name-contentmodel": "Evidencija promjene modela sadržaja",
        "log-description-contentmodel": "Ova stranica navodi promjene u modelu sadržaja stranica, kao i stranice stvorene s modelom sadržaja koji se razlikuje od predodređenog.",
        "logentry-contentmodel-new": "$1 {{GENDER:$2|napravio je|napravila je}} stranicu $3 s nestandardnim modelom sadržaja \"$5\"",
        "logentry-contentmodel-change": "$1 {{GENDER:$2|promijenio|promijenila}} je model sadržaja stranice $3 iz \"$4\" u \"$5\"",
index 337d978..1adcdf5 100644 (file)
        "mainpage": "پہلا پرت",
        "mainpage-description": "پہلا پرت",
        "policy-url": "Project:پالیسی",
-       "portal": "بیٹھک",
+       "portal": "برادری دا پھاٹک",
        "portal-url": "Project:دیوان عام",
        "privacy": "پرائیویسی پالیسی",
        "privacypage": "Project:پرائیویسی پالیسی",
index 17b6511..64ec265 100644 (file)
        "moredotdotdot": "ดูเพิ่ม...",
        "morenotlisted": "รายการนี้อาจไม่สมบูรณ์",
        "mypage": "หน้า",
-       "mytalk": "à¸\9eูà¸\94à¸\84ุย",
-       "anontalk": "à¸\9eูà¸\94à¸\84ุย",
+       "mytalk": "คุย",
+       "anontalk": "คุย",
        "navigation": "การนำทาง",
        "and": "&#32;และ",
        "faq": "คำถามที่พบบ่อย",
        "protect_change": "เปลี่ยน",
        "unprotect": "เปลี่ยนการล็อก",
        "newpage": "หน้าใหม่",
-       "talkpagelinktext": "à¸\9eูà¸\94à¸\84ุย",
+       "talkpagelinktext": "คุย",
        "specialpage": "หน้าพิเศษ",
        "personaltools": "เครื่องมือส่วนตัว",
        "talk": "อภิปราย",
        "cannotchangeemail": "ไม่สามารถเปลี่ยนที่อยู่อีเมลบนวิกินี้",
        "emaildisabled": "เว็บไซต์นี้ไม่สามารถส่งอีเมล",
        "accountcreated": "สร้างบัญชีแล้ว",
-       "accountcreatedtext": "สรà¹\89าà¸\87à¸\9aัà¸\8dà¸\8aีà¸\9cูà¹\89à¹\83à¸\8aà¹\89สำหรัà¸\9a [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|à¸\9eูà¸\94à¸\84ุย]]) à¹\81ลà¹\89ว",
+       "accountcreatedtext": "สร้างบัญชีผู้ใช้สำหรับ [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|คุย]]) แล้ว",
        "createaccount-title": "การสร้างบัญชีสำหรับ {{SITENAME}}",
        "createaccount-text": "มีบางคนสร้างบัญชีโดยใช้ที่อยู่อีเมลของคุณบน {{SITENAME}} ($4) โดยใช้ชื่อ \"$2\" และรหัสผ่าน \"$3\" \nคุณควรเข้าสู่ระบบและเปลี่ยนรหัสผ่านทันที\n\nคุณอาจเพิกเฉยข้อความนี้ หากการสร้างบัญชีนี้เป็นความผิดพลาด",
        "login-throttled": "ที่ผ่านมาคุณพยายามล็อกอินมากครั้งเกินไป\nกรุณารอ $1 ก่อนลองอีกครั้ง",
        "categoriesfrom": "แสดงหมวดหมู่เริ่มจาก:",
        "deletedcontributions": "การเข้ามีส่วนร่วมของผู้ใช้ที่ถูกลบ",
        "deletedcontributions-title": "การเข้ามีส่วนร่วมของผู้ใช้ที่ถูกลบ",
-       "sp-deletedcontributions-contribs": "à¹\80รืà¹\88อà¸\87à¸\97ีà¹\88มีส่วนร่วม",
+       "sp-deletedcontributions-contribs": "à¸\81ารà¹\80à¸\82à¹\89ามีส่วนร่วม",
        "linksearch": "ค้นหาลิงก์ภายนอก",
        "linksearch-pat": "รูปแบบการค้นหา:",
        "linksearch-ns": "เนมสเปซ:",
index 6cd17f6..fd4f1bd 100644 (file)
@@ -80,6 +80,7 @@
        "tog-norollbackdiff": "進行反轉之後唔睇差異",
        "tog-useeditwarning": "當我離開未保存好嘅修改嗰陣警告我",
        "tog-prefershttps": "簽到後繼續用加密連線",
+       "tog-showrollbackconfirmation": "撳「反轉」掣嘅時候要撳確認",
        "underline-always": "全部",
        "underline-never": "永不",
        "underline-default": "瀏覽器或瀏覽器膚色預設",
        "grant-editprotected": "改保護咗嘅版",
        "grant-highvolume": "大量編輯",
        "grant-oversight": "收埋用戶同禁止顯示修訂",
+       "grant-rollback": "反轉一啲版面嘅修改",
        "grant-sendemail": "寄電郵畀其他用戶",
        "grant-uploadeditmovefile": "上載、𠖫同搬檔",
        "grant-uploadfile": "上載新檔案",
        "deleteprotected": "你唔可以刪呢版,因為佢畀人保護咗。",
        "deleting-backlinks-warning": "<strong>警告:</strong>有[[Special:WhatLinksHere/{{FULLPAGENAME}}|其他版]]連過來或嵌咗你準備刪嘅呢版。",
        "rollback": "反轉修改",
+       "rollback-confirmation-yes": "反轉",
        "rollbacklink": "反轉",
        "rollbacklinkcount": "反轉 $1 次修改",
        "rollbacklinkcount-morethan": "反轉超過$1次嘅{{PLURAL:$1|edit|修改}}",
        "confirm-unwatch-button": "好",
        "confirm-unwatch-top": "喺你嘅監視清單度刪走呢一版?",
        "confirm-rollback-button": "好",
+       "confirm-rollback-bottom": "呢個動作會立即反轉晒揀咗嘅修改。",
+       "confirm-mcrundo-title": "還原一個改動",
        "comma-separator": "、",
        "word-separator": "",
        "parentheses": "($1)",
        "tag-mw-blank": "清空",
        "tag-mw-replace": "換咗",
        "tag-mw-rollback": "反轉",
+       "tag-mw-rollback-description": "用「反轉」掣將之前修改打回頭嘅修改",
+       "tag-mw-undo": "還原",
+       "tag-mw-undo-description": "用「還原」掣還原之前修改嘅修改",
        "tags-title": "標籤",
        "tags-intro": "呢一版列示咗個軟件標示嘅編輯,同埋佢哋嘅解釋。",
        "tags-tag": "標籤名",
        "tags-hitcount": "$1次更改",
        "tags-create-reason": "原因:",
        "tags-create-submit": "開",
+       "tags-delete-explanation-warning": "呢個動作<strong>冇得返轉頭</strong>,係<strong>還原唔到</strong>嘅,就算資料庫管理員都還原唔到。唔該諗清楚你係咪想刪走呢個標籤。",
        "tags-delete-reason": "原因:",
        "tags-activate-title": "啟用標籤",
        "tags-activate-reason": "原因:",
index 0caf584..33ce701 100644 (file)
        "histfirst": "最舊",
        "histlast": "最新",
        "historysize": "($1 位元組)",
-       "historyempty": "(空)",
+       "historyempty": "",
        "history-feed-title": "修訂歷史",
        "history-feed-description": "本 Wiki 上此頁面的修訂歷史",
        "history-feed-item-nocomment": "$1 於 $2",
        "print.css": "/* 此處的 CSS 會影響列印輸出 */",
        "noscript.css": "/* 此 CSS 會影響沒有啟用 JavaScript 的使用者 */",
        "group-autoconfirmed.css": "/* 此 CSS 會影響自動確認的使用者 */",
+       "group-user.css": "/* 置於此處的CSS只會影響已註冊使用者 */",
        "group-bot.css": "/* 此 CSS 會影響機器人 */",
        "group-sysop.css": "/* 這裡的 CSS 會影響管理員 */",
        "group-bureaucrat.css": "/* 此 CSS 會影響行政員 */",
        "common.json": "/* 在此的任一 JavaScript 會為全部使用者在所有頁面裡載入。 */",
        "common.js": "/* 此 JavaScript 會用於使用者載入的每一個頁面。 */",
+       "group-autoconfirmed.js": "/* 這裡的任何JavaScript只會為自動確認的使用者載入 */",
+       "group-user.js": "/* 這裡的任何JavaScript只會為已註冊使用者載入 */",
+       "group-bot.js": "/* 這裡的任何JavaScript只會為機器人載入 */",
        "group-sysop.js": "/* 這裡的 JavaScript 會影響管理員 */",
+       "group-bureaucrat.js": "/* 這裡的任何JavaScript只會為行政員載入 */",
        "anonymous": "{{SITENAME}} 的匿名{{PLURAL:$1|使用者}}",
        "siteuser": "{{SITENAME}}使用者 $1",
        "anonuser": "{{SITENAME}} 匿名使用者 $1",
index f325641..86ac01a 100644 (file)
@@ -438,7 +438,7 @@ $specialPageAliases = [
        'Listgrants'                => [ 'ListGrants' ],
        'Listredirects'             => [ 'ListRedirects' ],
        'ListDuplicatedFiles'       => [ 'ListDuplicatedFiles', 'ListFileDuplicates' ],
-       'Listusers'                 => [ 'ListUsers', 'UserList' ],
+       'Listusers'                 => [ 'ListUsers', 'UserList', 'Users' ],
        'Lockdb'                    => [ 'LockDB' ],
        'Log'                       => [ 'Log', 'Logs' ],
        'Lonelypages'               => [ 'LonelyPages', 'OrphanedPages' ],
index 1ba7054..591fbd4 100644 (file)
@@ -93,6 +93,7 @@ class PopulatePPSortKey extends LoggedUpdateMaintenance {
                }
 
                $this->output( "Populating page_props.pp_sortkey complete.\n" );
+               return true;
        }
 
        protected function getUpdateKey() {
index d5d27ad..8df01e6 100644 (file)
@@ -239,7 +239,7 @@ class PPFuzzTest {
 class PPFuzzUser extends User {
        public $ppfz_test, $mDataLoaded;
 
-       function load() {
+       function load( $flags = null ) {
                if ( $this->mDataLoaded ) {
                        return;
                }
index 7f36442..7f89ce9 100644 (file)
@@ -274,7 +274,9 @@ class RecompressTracked {
        function dispatch( /*...*/ ) {
                $args = func_get_args();
                $pipes = $this->replicaPipes;
-               $numPipes = stream_select( $x = [], $pipes, $y = [], 3600 );
+               $x = [];
+               $y = [];
+               $numPipes = stream_select( $x, $pipes, $y, 3600 );
                if ( !$numPipes ) {
                        $this->critical( "Error waiting to write to replica DBs. Aborting" );
                        exit( 1 );
index ef9e46e..00046d3 100644 (file)
@@ -114,7 +114,7 @@ class WrapOldPasswords extends Maintenance {
 
                        // Clear memcached so old passwords are wiped out
                        foreach ( $updateUsers as $user ) {
-                               $user->clearSharedCache();
+                               $user->clearSharedCache( 'refresh' );
                        }
                } while ( $res->numRows() );
        }
index cc01c7d..4291bcc 100644 (file)
@@ -307,11 +307,16 @@ class LoadBalancerTest extends MediaWikiTestCase {
 
                $i = $lb->getWriterIndex();
                $this->assertEquals( null, $lb->getAnyOpenConnection( $i ) );
+
                $conn1 = $lb->getConnection( $i );
                $this->assertNotEquals( null, $conn1 );
                $this->assertEquals( $conn1, $lb->getAnyOpenConnection( $i ) );
+               $this->assertFalse( $conn1->getFlag( DBO_TRX ) );
+
                $conn2 = $lb->getConnection( $i, [], false, $lb::CONN_TRX_AUTOCOMMIT );
                $this->assertNotEquals( null, $conn2 );
+               $this->assertFalse( $conn2->getFlag( DBO_TRX ) );
+
                if ( $lb->getServerAttributes( $i )[Database::ATTR_DB_LEVEL_LOCKING] ) {
                        $this->assertEquals( null,
                                $lb->getAnyOpenConnection( $i, $lb::CONN_TRX_AUTOCOMMIT ) );
@@ -355,7 +360,7 @@ class LoadBalancerTest extends MediaWikiTestCase {
                                'type' => $wgDBtype,
                                'dbDirectory' => $wgSQLiteDataDir,
                                'load' => 0,
-                               'flags' => DBO_TRX // REPEATABLE-READ for consistency
+                               'flags' => DBO_TRX // simulate a web request with DBO_TRX
                        ],
                ];
 
@@ -428,4 +433,60 @@ class LoadBalancerTest extends MediaWikiTestCase {
                $conn1->close();
                $conn2->close();
        }
+
+       public function testDBConnRefReadsMasterAndReplicaRoles() {
+               $lb = $this->newSingleServerLocalLoadBalancer();
+
+               $rConn = $lb->getConnectionRef( DB_REPLICA );
+               $wConn = $lb->getConnectionRef( DB_MASTER );
+               $wConn2 = $lb->getConnectionRef( 0 );
+
+               $v = [ 'value' => '1', '1' ];
+               $sql = 'SELECT MAX(1) AS value';
+               foreach ( [ $rConn, $wConn, $wConn2 ] as $conn ) {
+                       $conn->clearFlag( $conn::DBO_TRX );
+
+                       $res = $conn->query( $sql, __METHOD__ );
+                       $this->assertEquals( $v, $conn->fetchRow( $res ) );
+
+                       $res = $conn->query( $sql, __METHOD__, $conn::QUERY_REPLICA_ROLE );
+                       $this->assertEquals( $v, $conn->fetchRow( $res ) );
+               }
+
+               $wConn->getScopedLockAndFlush( 'key', __METHOD__, 1 );
+               $wConn2->getScopedLockAndFlush( 'key2', __METHOD__, 1 );
+       }
+
+       /**
+        * @expectedException \Wikimedia\Rdbms\DBReadOnlyRoleError
+        */
+       public function testDBConnRefWritesReplicaRole() {
+               $lb = $this->newSingleServerLocalLoadBalancer();
+
+               $rConn = $lb->getConnectionRef( DB_REPLICA );
+
+               $rConn->query( 'DELETE FROM sometesttable WHERE 1=0' );
+       }
+
+       /**
+        * @expectedException \Wikimedia\Rdbms\DBReadOnlyRoleError
+        */
+       public function testDBConnRefWritesReplicaRoleIndex() {
+               $lb = $this->newMultiServerLocalLoadBalancer();
+
+               $rConn = $lb->getConnectionRef( 1 );
+
+               $rConn->query( 'DELETE FROM sometesttable WHERE 1=0' );
+       }
+
+       /**
+        * @expectedException \Wikimedia\Rdbms\DBReadOnlyRoleError
+        */
+       public function testDBConnRefWritesReplicaRoleInsert() {
+               $lb = $this->newMultiServerLocalLoadBalancer();
+
+               $rConn = $lb->getConnectionRef( DB_REPLICA );
+
+               $rConn->insert( 'test', [ 't' => 1 ], __METHOD__ );
+       }
 }
index 9b72b95..33e5c3b 100644 (file)
@@ -75,12 +75,12 @@ class DBConnRefTest extends PHPUnit\Framework\TestCase {
         */
        private function getDBConnRef( ILoadBalancer $lb = null ) {
                $lb = $lb ?: $this->getLoadBalancerMock();
-               return new DBConnRef( $lb, $this->getDatabaseMock() );
+               return new DBConnRef( $lb, $this->getDatabaseMock(), DB_MASTER );
        }
 
        public function testConstruct() {
                $lb = $this->getLoadBalancerMock();
-               $ref = new DBConnRef( $lb, $this->getDatabaseMock() );
+               $ref = new DBConnRef( $lb, $this->getDatabaseMock(), DB_MASTER );
 
                $this->assertInstanceOf( ResultWrapper::class, $ref->select( 'whatever', '*' ) );
        }
@@ -99,10 +99,19 @@ class DBConnRefTest extends PHPUnit\Framework\TestCase {
 
                $ref = new DBConnRef(
                        $lb,
-                       [ DB_MASTER, [ 'test' ], 'dummy', ILoadBalancer::CONN_TRX_AUTOCOMMIT ]
+                       [ DB_MASTER, [ 'test' ], 'dummy', ILoadBalancer::CONN_TRX_AUTOCOMMIT ],
+                       DB_MASTER
                );
 
                $this->assertInstanceOf( ResultWrapper::class, $ref->select( 'whatever', '*' ) );
+               $this->assertEquals( DB_MASTER, $ref->getReferenceRole() );
+
+               $ref2 = new DBConnRef(
+                       $lb,
+                       [ DB_MASTER, [ 'test' ], 'dummy', ILoadBalancer::CONN_TRX_AUTOCOMMIT ],
+                       DB_REPLICA
+               );
+               $this->assertEquals( DB_REPLICA, $ref2->getReferenceRole() );
        }
 
        public function testDestruct() {
@@ -124,7 +133,7 @@ class DBConnRefTest extends PHPUnit\Framework\TestCase {
                $this->setExpectedException( InvalidArgumentException::class, '' );
 
                $lb = $this->getLoadBalancerMock();
-               new DBConnRef( $lb, 17 ); // bad constructor argument
+               new DBConnRef( $lb, 17, DB_REPLICA ); // bad constructor argument
        }
 
        /**
@@ -137,7 +146,7 @@ class DBConnRefTest extends PHPUnit\Framework\TestCase {
                $lb->expects( $this->never() )
                        ->method( 'getConnection' );
 
-               $ref = new DBConnRef( $lb, [ DB_REPLICA, [], 'dummy', 0 ] );
+               $ref = new DBConnRef( $lb, [ DB_REPLICA, [], 'dummy', 0 ], DB_REPLICA );
 
                $this->assertSame( 'dummy', $ref->getDomainID() );
        }
@@ -156,7 +165,7 @@ class DBConnRefTest extends PHPUnit\Framework\TestCase {
                $this->assertInternalType( 'string', $ref->__toString() );
 
                $lb = $this->getLoadBalancerMock();
-               $ref = new DBConnRef( $lb, [ DB_MASTER, [], 'test', 0 ] );
+               $ref = new DBConnRef( $lb, [ DB_MASTER, [], 'test', 0 ], DB_MASTER );
                $this->assertInternalType( 'string', $ref->__toString() );
        }
 
@@ -166,7 +175,49 @@ class DBConnRefTest extends PHPUnit\Framework\TestCase {
         */
        public function testClose() {
                $lb = $this->getLoadBalancerMock();
-               $ref = new DBConnRef( $lb, [ DB_REPLICA, [], 'dummy', 0 ] );
+               $ref = new DBConnRef( $lb, [ DB_REPLICA, [], 'dummy', 0 ], DB_MASTER );
                $ref->close();
        }
+
+       /**
+        * @covers Wikimedia\Rdbms\DBConnRef::getReferenceRole
+        */
+       public function testGetReferenceRole() {
+               $lb = $this->getLoadBalancerMock();
+               $ref = new DBConnRef( $lb, [ DB_REPLICA, [], 'dummy', 0 ], DB_REPLICA );
+               $this->assertSame( DB_REPLICA, $ref->getReferenceRole() );
+
+               $ref = new DBConnRef( $lb, [ DB_MASTER, [], 'dummy', 0 ], DB_MASTER );
+               $this->assertSame( DB_MASTER, $ref->getReferenceRole() );
+
+               $ref = new DBConnRef( $lb, [ 1, [], 'dummy', 0 ], DB_REPLICA );
+               $this->assertSame( DB_REPLICA, $ref->getReferenceRole() );
+
+               $ref = new DBConnRef( $lb, [ 0, [], 'dummy', 0 ], DB_MASTER );
+               $this->assertSame( DB_MASTER, $ref->getReferenceRole() );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\DBConnRef::getReferenceRole
+        * @expectedException Wikimedia\Rdbms\DBReadOnlyRoleError
+        * @dataProvider provideRoleExceptions
+        */
+       public function testRoleExceptions( $method, $args ) {
+               $lb = $this->getLoadBalancerMock();
+               $ref = new DBConnRef( $lb, [ DB_REPLICA, [], 'dummy', 0 ], DB_REPLICA );
+               $ref->$method( ...$args );
+       }
+
+       function provideRoleExceptions() {
+               return [
+                       [ 'insert', [ 'table', [ 'a' => 1 ] ] ],
+                       [ 'update', [ 'table', [ 'a' => 1 ], [ 'a' => 2 ] ] ],
+                       [ 'delete', [ 'table', [ 'a' => 1 ] ] ],
+                       [ 'replace', [ 'table', [ 'a' ], [ 'a' => 1 ] ] ],
+                       [ 'upsert', [ 'table', [ 'a' => 1 ], [ 'a' ], [ 'a = a + 1' ] ] ],
+                       [ 'lock', [ 'k', 'method' ] ],
+                       [ 'unlock', [ 'k', 'method' ] ],
+                       [ 'getScopedLockAndFlush', [ 'k', 'method', 1 ] ]
+               ];
+       }
 }