Merge "rcfilters: Simplify FormWrapperWidget submit code by reducing jQuery use"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 3 Jul 2019 21:58:35 +0000 (21:58 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 3 Jul 2019 21:58:35 +0000 (21:58 +0000)
59 files changed:
.phpcs.xml
includes/ActorMigration.php
includes/CommentStore.php
includes/DefaultSettings.php
includes/Title.php
includes/api/ApiBase.php
includes/api/ApiMessageTrait.php
includes/api/i18n/zh-hans.json
includes/deferred/UserEditCountUpdate.php
includes/export/XmlDumpWriter.php
includes/filerepo/ForeignDBRepo.php
includes/installer/i18n/pt.json
includes/installer/i18n/qqq.json
includes/installer/i18n/ru.json
includes/libs/filebackend/filejournal/FileJournal.php
includes/libs/lockmanager/NullLockManager.php
includes/libs/lockmanager/QuorumLockManager.php
includes/libs/mime/MimeAnalyzer.php
includes/libs/mime/XmlTypeCheck.php
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/database/DatabaseMysqlBase.php
includes/libs/rdbms/database/DatabaseSqlite.php
includes/libs/rdbms/database/domain/DatabaseDomain.php
includes/logging/LogFormatter.php
includes/objectcache/ObjectCache.php
includes/title/NamespaceInfo.php
includes/user/User.php
languages/LanguageConverter.php
languages/i18n/ban.json
languages/i18n/bcc.json
languages/i18n/be-tarask.json
languages/i18n/ca.json
languages/i18n/diq.json
languages/i18n/es.json
languages/i18n/exif/pt.json
languages/i18n/exif/qqq.json
languages/i18n/fr.json
languages/i18n/he.json
languages/i18n/hyw.json
languages/i18n/is.json
languages/i18n/lv.json
languages/i18n/mk.json
languages/i18n/nqo.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/ru.json
languages/i18n/sdc.json
languages/i18n/zh-hans.json
languages/i18n/zh-hant.json
resources/Resources.php
resources/src/mediawiki.action/mediawiki.action.edit.preview.css [new file with mode: 0644]
resources/src/mediawiki.action/mediawiki.action.edit.preview.js
tests/phpunit/MediaWikiIntegrationTestCase.php
tests/phpunit/documentation/ReleaseNotesTest.php
tests/phpunit/includes/TitleTest.php
tests/phpunit/includes/logging/LogFormatterTest.php
tests/phpunit/includes/parser/CoreParserFunctionsTest.php
tests/phpunit/includes/title/NamespaceInfoTest.php

index 76234a2..8f3bd8c 100644 (file)
@@ -60,6 +60,7 @@
                <exclude-pattern>maintenance/doMaintenance\.php</exclude-pattern>
                <exclude-pattern>maintenance/mergeMessageFileList\.php</exclude-pattern>
                <exclude-pattern>maintenance/commandLine\.inc</exclude-pattern>
+               <exclude-pattern>tests/phpunit/MediaWikiIntegrationTestCase\.php</exclude-pattern>
        </rule>
        <rule ref="Generic.Files.LineLength">
                <exclude-pattern>*/languages/messages/Messages*\.php</exclude-pattern>
index 597b8e7..5dde8a0 100644 (file)
@@ -144,11 +144,12 @@ class ActorMigration {
         *
         * @param string $key A key such as "rev_user" identifying the actor
         *  field being fetched.
-        * @return array With three keys:
+        * @return array[] With three keys:
         *   - tables: (string[]) to include in the `$table` to `IDatabase->select()`
         *   - fields: (string[]) to include in the `$vars` to `IDatabase->select()`
         *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
         *  All tables, fields, and joins are aliased, so `+` is safe to use.
+        * @phan-return array{tables:string[],fields:string[],joins:array}
         */
        public function getJoin( $key ) {
                if ( !isset( $this->joinCache[$key] ) ) {
index 4a673c4..994a064 100644 (file)
@@ -197,7 +197,7 @@ class CommentStore {
         * @since 1.31 Method signature changed, $key parameter added (with deprecated back compat)
         * @param string|null $key A key such as "rev_comment" identifying the comment
         *  field being fetched.
-        * @return array With three keys:
+        * @return array[] With three keys:
         *   - tables: (string[]) to include in the `$table` to `IDatabase->select()`
         *   - fields: (string[]) to include in the `$vars` to `IDatabase->select()`
         *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
index a32af36..9b5a38b 100644 (file)
@@ -1958,7 +1958,8 @@ $wgSearchTypeAlternatives = null;
 
 /**
  * Table name prefix.
- * This should be alphanumeric, contain neither spaces nor hyphens, and end in "_"
+ * Should be alphanumeric plus underscores, and not contain spaces nor hyphens.
+ * Suggested format ends with an underscore.
  */
 $wgDBprefix = '';
 
index b27baa8..6e75102 100644 (file)
@@ -1145,14 +1145,16 @@ class Title implements LinkTarget, IDBAccessObject {
        /**
         * Can this title have a corresponding talk page?
         *
-        * @see NamespaceInfo::hasTalkNamespace
+        * False for relative section links (with getText() === ''),
+        * interwiki links (with getInterwiki() !== ''), and pages in NS_SPECIAL.
+        *
+        * @see NamespaceInfo::canHaveTalkPage
         * @since 1.30
         *
         * @return bool True if this title either is a talk page or can have a talk page associated.
         */
        public function canHaveTalkPage() {
-               return MediaWikiServices::getInstance()->getNamespaceInfo()->
-                       hasTalkNamespace( $this->mNamespace );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->canHaveTalkPage( $this );
        }
 
        /**
@@ -1167,11 +1169,15 @@ class Title implements LinkTarget, IDBAccessObject {
        /**
         * Can this title be added to a user's watchlist?
         *
+        * False for relative section links (with getText() === ''),
+        * interwiki links (with getInterwiki() !== ''), and pages in NS_SPECIAL.
+        *
         * @return bool
         */
        public function isWatchable() {
-               return !$this->isExternal() && MediaWikiServices::getInstance()->getNamespaceInfo()->
-                       isWatchable( $this->mNamespace );
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               return $this->getText() !== '' && !$this->isExternal() &&
+                       $nsInfo->isWatchable( $this->mNamespace );
        }
 
        /**
@@ -1532,8 +1538,11 @@ class Title implements LinkTarget, IDBAccessObject {
        /**
         * Get a Title object associated with the talk page of this article
         *
-        * @deprecated since 1.34, use NamespaceInfo::getTalkPage
+        * @deprecated since 1.34, use getTalkPageIfDefined() or NamespaceInfo::getTalkPage()
+        *             with NamespaceInfo::canHaveTalkPage().
         * @return Title The object for the talk page
+        * @throws MWException if $target doesn't have talk pages, e.g. because it's in NS_SPECIAL
+        *         or because it's a relative link, or an interwiki link.
         */
        public function getTalkPage() {
                return self::castFromLinkTarget(
index e798414..63d8b18 100644 (file)
@@ -280,9 +280,10 @@ abstract class ApiBase extends ContextSource {
        /** $var array Map of web UI block messages to corresponding API messages and codes */
        private static $blockMsgMap = [
                'blockedtext' => [ 'apierror-blocked', 'blocked' ],
-               'blockedtext-partial' => [ 'apierror-blocked', 'blocked' ],
+               'blockedtext-partial' => [ 'apierror-blocked-partial', 'blocked' ],
                'autoblockedtext' => [ 'apierror-autoblocked', 'autoblocked' ],
                'systemblockedtext' => [ 'apierror-systemblocked', 'blocked' ],
+               'blockedtext-composite' => [ 'apierror-blocked', 'blocked' ],
        ];
 
        /** @var ApiMain */
index 6894d28..73e4ac2 100644 (file)
@@ -37,6 +37,8 @@ trait ApiMessageTrait {
                'badipaddress' => 'invalidip',
                'blankpage' => 'emptypage',
                'blockedtext' => 'blocked',
+               'blockedtext-composite' => 'blocked',
+               'blockedtext-partial' => 'blocked',
                'cannotdelete' => 'cantdelete',
                'cannotundelete' => 'cantundelete',
                'cantmove-titleprotected' => 'protectedtitle',
index 13b22b1..cf80ac0 100644 (file)
@@ -28,7 +28,8 @@
                        "Wxyveronica",
                        "WhitePhosphorus",
                        "科劳",
-                       "SolidBlock"
+                       "SolidBlock",
+                       "神樂坂秀吉"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|文档]]\n* [[mw:Special:MyLanguage/API:FAQ|常见问题]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 邮件列表]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 程序错误与功能请求]\n</div>\n<strong>状态信息:</strong>MediaWiki API是一个成熟稳定的,不断受到支持和改进的界面。尽管我们尽力避免,但偶尔也需要作出重大更新;请订阅[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce 邮件列表]以便获得更新通知。\n\n<strong>错误请求:</strong>当API收到错误请求时,HTTP header将会返回一个包含\"MediaWiki-API-Error\"的值,随后header的值与error code将会送回并设置为相同的值。详细信息请参阅[[mw:Special:MyLanguage/API:Errors_and_warnings|API:错误与警告]]。\n\n<p class=\"mw-apisandbox-link\"><strong>测试中:</strong>测试API请求的易用性,请参见[[Special:ApiSandbox]]。</p>",
        "apihelp-opensearch-param-warningsaserror": "如果警告通过<kbd>format=json</kbd>提升,返回一个API错误而不是忽略它们。",
        "apihelp-opensearch-example-te": "查找以<kbd>Te</kbd>开头的页面。",
        "apihelp-options-summary": "更改当前用户的参数设置。",
-       "apihelp-options-extended-description": "只有注册在核心或者已安装扩展中的选项,或者具有<code>userjs-</code>键值前缀(旨在被用户脚本使用)的选项可被设置。",
+       "apihelp-options-extended-description": "只有注册在核心或者已安装扩展中的选项,或者具有<code>userjs-</code>键值前缀(旨在使用于用户脚本)的选项可设置。",
        "apihelp-options-param-reset": "将参数设置重置为网站默认值。",
        "apihelp-options-param-resetkinds": "当<var>$1reset</var>选项被设置时,要重置的选项类型列表。",
        "apihelp-options-param-change": "更改列表,以name=value格式化(例如skin=vector)。如果没提供值(甚至没有等号),例如optionname|otheroption|...,选项将重置为默认值。如果任何传递的值包含管道字符(<kbd>|</kbd>),请改用[[Special:ApiHelp/main#main/datatypes|替代多值分隔符]]以正确操作。",
index 3ccb4a8..ed7e00c 100644 (file)
@@ -82,16 +82,15 @@ class UserEditCountUpdate implements DeferrableUpdate, MergeableUpdate {
                                $affectedInstances = $info['instances'];
                                // Lazy initialization check...
                                if ( $dbw->affectedRows() == 0 ) {
-                                       // No rows will be "affected" if user_editcount is NULL.
-                                       // Check if the generic "replica" connection is not the master.
+                                       // The user_editcount is probably NULL (e.g. not initialized).
+                                       // Since this update runs after the new revisions were committed,
+                                       // wait for the replica DB to catch up so they will be counted.
                                        $dbr = $lb->getConnection( DB_REPLICA );
-                                       if ( $dbr !== $dbw ) {
-                                               // This method runs after the new revisions were committed.
-                                               // Wait for the replica to catch up so they will all be counted.
-                                               $dbr->flushSnapshot( $fname );
-                                               $lb->waitForMasterPos( $dbr );
-                                       }
-                                       $affectedInstances[0]->initEditCountInternal();
+                                       // If $dbr is actually the master DB, then clearing the snapshot is
+                                       // is harmless and waitForMasterPos() will just no-op.
+                                       $dbr->flushSnapshot( $fname );
+                                       $lb->waitForMasterPos( $dbr );
+                                       $affectedInstances[0]->initEditCountInternal( $dbr );
                                }
                                $newCount = (int)$dbw->selectField(
                                        'user',
index bedfe13..f71b0d5 100644 (file)
@@ -337,9 +337,11 @@ class XmlDumpWriter {
                if ( $rev->isDeleted( Revision::DELETED_COMMENT ) ) {
                        $out .= "      " . Xml::element( 'comment', [ 'deleted' => 'deleted' ] ) . "\n";
                } else {
-                       $out .= "      "
-                               . Xml::elementClean( 'comment', [], strval( $rev->getComment()->text ) )
-                               . "\n";
+                       if ( $rev->getComment()->text != '' ) {
+                               $out .= "      "
+                                       . Xml::elementClean( 'comment', [], strval( $rev->getComment()->text ) )
+                                       . "\n";
+                       }
                }
 
                $contentMode = $rev->isDeleted( Revision::DELETED_TEXT ) ? self::WRITE_STUB_DELETED
index 4b33138..a44d3ed 100644 (file)
@@ -107,8 +107,7 @@ class ForeignDBRepo extends LocalRepo {
                        'password' => $this->dbPassword,
                        'dbname' => $this->dbName,
                        'flags' => $this->dbFlags,
-                       'tablePrefix' => $this->tablePrefix,
-                       'foreign' => true,
+                       'tablePrefix' => $this->tablePrefix
                ];
 
                return function ( $index ) use ( $type, $params ) {
index 8768afc..6acd866 100644 (file)
@@ -21,7 +21,8 @@
                        "Seb35",
                        "MokaAkashiyaPT",
                        "Athena in Wonderland",
-                       "CaiusSPQR"
+                       "CaiusSPQR",
+                       "Waldyrious"
                ]
        },
        "config-desc": "O instalador do MediaWiki",
index 639262e..ceb7586 100644 (file)
@@ -22,7 +22,8 @@
                        "Metalhead64",
                        "Tacsipacsi",
                        "Zoranzoki21",
-                       "BadDog"
+                       "BadDog",
+                       "Waldyrious"
                ]
        },
        "config-desc": "Short description of the installer.",
index 8297dd8..82923e5 100644 (file)
@@ -28,7 +28,8 @@
                        "Movses",
                        "Vlad5250",
                        "Athena Atterdag",
-                       "Diralik"
+                       "Diralik",
+                       "Alexander Istomin"
                ]
        },
        "config-desc": "Инсталлятор MediaWiki",
@@ -74,8 +75,8 @@
        "config-env-bad": "Была проведена проверка внешней среды.\nВы не можете установить MediaWiki.",
        "config-env-php": "Установленная версия PHP: $1.",
        "config-env-hhvm": "HHVM $1 установлена.",
-       "config-unicode-using-intl": "Будет использовано [https://pecl.php.net/intl расширение «intl» для PECL] для нормализации Юникода.",
-       "config-unicode-pure-php-warning": "'''Внимание!''': [https://pecl.php.net/intl расширение intl из PECL] недоступно для нормализации Юникода, будет использоваться медленная реализация на чистом PHP.\nЕсли ваш сайт работает под высокой нагрузкой, вам следует больше узнать о [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations нормализации Юникода].",
+       "config-unicode-using-intl": "Будет использовано [https://php.net/manual/en/book.intl.php PHP intl расширение] для нормализации Юникода.",
+       "config-unicode-pure-php-warning": "'''Внимание!''': [https://php.net/manual/en/book.intl.php PHP intl расширение] недоступно для нормализации Юникода, будет использоваться медленная реализация на чистом PHP.\nЕсли ваш сайт работает под высокой нагрузкой, вам следует больше узнать о [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations нормализации Юникода].",
        "config-unicode-update-warning": "'''Предупреждение''': установленная версия обёртки нормализации Юникода использует старую версию библиотеки [http://site.icu-project.org/ проекта ICU].\nВы должны [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations обновить версию], если хотите полноценно использовать Юникод.",
        "config-no-db": "Не удалось найти подходящие драйвера баз данных! Вам необходимо установить драйвера базы данных для PHP.\n{{PLURAL:$2|Поддерживается следующий тип|Поддерживаются следующие типы}} баз данных: $1.\n\nЕсли вы скомпилировали PHP сами, перенастройте его с включением клиента баз данных, например, с помощью <code>./configure --with-mysqli</code>.\nЕсли вы установили PHP из пакетов Debian или Ubuntu, то вам также необходимо установить, например, пакет <code>php-mysql</code>.",
        "config-outdated-sqlite": "'''Предупреждение''': у Вас установлен SQLite  $1, версия которого ниже требуемой $2 . SQLite будет недоступен.",
index 999594b..dc007a0 100644 (file)
@@ -26,6 +26,8 @@
  * @ingroup FileJournal
  */
 
+use Wikimedia\Timestamp\ConvertibleTimestamp;
+
 /**
  * @brief Class for handling file operation journaling.
  *
@@ -37,7 +39,6 @@
 abstract class FileJournal {
        /** @var string */
        protected $backend;
-
        /** @var int */
        protected $ttlDays;
 
@@ -63,7 +64,7 @@ abstract class FileJournal {
                $class = $config['class'];
                $jrn = new $class( $config );
                if ( !$jrn instanceof self ) {
-                       throw new InvalidArgumentException( "Class given is not an instance of FileJournal." );
+                       throw new InvalidArgumentException( "$class is not an instance of " . __CLASS__ );
                }
                $jrn->backend = $backend;
 
@@ -82,7 +83,9 @@ abstract class FileJournal {
                }
                $s = Wikimedia\base_convert( sha1( $s ), 16, 36, 31 );
 
-               return substr( Wikimedia\base_convert( wfTimestamp( TS_MW ), 10, 36, 9 ) . $s, 0, 31 );
+               $timestamp = ConvertibleTimestamp::convert( TS_MW, time() );
+
+               return substr( Wikimedia\base_convert( $timestamp, 10, 36, 9 ) . $s, 0, 31 );
        }
 
        /**
index b83462c..339a7ee 100644 (file)
  */
 
 /**
- * Simple version of LockManager that does nothing
+ * Simple version of LockManager that only does lock reference counting
  * @since 1.19
  */
 class NullLockManager extends LockManager {
        protected function doLock( array $paths, $type ) {
+               foreach ( $paths as $path ) {
+                       if ( isset( $this->locksHeld[$path][$type] ) ) {
+                               ++$this->locksHeld[$path][$type];
+                       } else {
+                               $this->locksHeld[$path][$type] = 1;
+                       }
+               }
+
                return StatusValue::newGood();
        }
 
        protected function doUnlock( array $paths, $type ) {
-               return StatusValue::newGood();
+               $status = StatusValue::newGood();
+
+               foreach ( $paths as $path ) {
+                       if ( isset( $this->locksHeld[$path][$type] ) ) {
+                               if ( --$this->locksHeld[$path][$type] <= 0 ) {
+                                       unset( $this->locksHeld[$path][$type] );
+                                       if ( !$this->locksHeld[$path] ) {
+                                               unset( $this->locksHeld[$path] ); // clean up
+                                       }
+                               }
+                       } else {
+                               $status->warning( 'lockmanager-notlocked', $path );
+                       }
+               }
+
+               return $status;
        }
 }
index 1ef4642..950b283 100644 (file)
@@ -35,15 +35,7 @@ abstract class QuorumLockManager extends LockManager {
        /** @var array Map of degraded buckets */
        protected $degradedBuckets = []; // (bucket index => UNIX timestamp)
 
-       final protected function doLock( array $paths, $type ) {
-               return $this->doLockByType( [ $type => $paths ] );
-       }
-
-       final protected function doUnlock( array $paths, $type ) {
-               return $this->doUnlockByType( [ $type => $paths ] );
-       }
-
-       protected function doLockByType( array $pathsByType ) {
+       final protected function doLockByType( array $pathsByType ) {
                $status = StatusValue::newGood();
 
                $pathsToLock = []; // (bucket => type => paths)
@@ -278,4 +270,12 @@ abstract class QuorumLockManager extends LockManager {
         * @return StatusValue
         */
        abstract protected function releaseAllLocks();
+
+       final protected function doLock( array $paths, $type ) {
+               throw new LogicException( __METHOD__ . ': proxy class does not need this method.' );
+       }
+
+       final protected function doUnlock( array $paths, $type ) {
+               throw new LogicException( __METHOD__ . ': proxy class does not need this method.' );
+       }
 }
index e7dc926..f493769 100644 (file)
@@ -755,7 +755,9 @@ EOT;
                /**
                 * look for XML formats (XHTML and SVG)
                 */
+               Wikimedia\suppressWarnings();
                $xml = new XmlTypeCheck( $file );
+               Wikimedia\restoreWarnings();
                if ( $xml->wellFormed ) {
                        $xmlTypes = $this->xmlTypes;
                        return $xmlTypes[$xml->getRootElement()] ?? 'application/xml';
index 0b52391..65cc54b 100644 (file)
 
 class XmlTypeCheck {
        /**
-        * Will be set to true or false to indicate whether the file is
+        * @var bool|null Will be set to true or false to indicate whether the file is
         * well-formed XML. Note that this doesn't check schema validity.
         */
        public $wellFormed = null;
 
        /**
-        * Will be set to true if the optional element filter returned
+        * @var bool Will be set to true if the optional element filter returned
         * a match at some point.
         */
        public $filterMatch = false;
@@ -46,30 +46,30 @@ class XmlTypeCheck {
        public $filterMatchType = false;
 
        /**
-        * Name of the document's root element, including any namespace
+        * @var string Name of the document's root element, including any namespace
         * as an expanded URL.
         */
        public $rootElement = '';
 
        /**
-        * A stack of strings containing the data of each xml element as it's processed. Append
-        * data to the top string of the stack, then pop off the string and process it when the
+        * @var string[] A stack of strings containing the data of each xml element as it's processed.
+        * Append data to the top string of the stack, then pop off the string and process it when the
         * element is closed.
         */
        protected $elementData = [];
 
        /**
-        * A stack of element names and attributes, as we process them.
+        * @var array A stack of element names and attributes, as we process them.
         */
        protected $elementDataContext = [];
 
        /**
-        * Current depth of the data stack.
+        * @var int Current depth of the data stack.
         */
        protected $stackDepth = 0;
 
        /**
-        * Additional parsing options
+        * @var array Additional parsing options
         */
        private $parserOptions = [
                'processing_instruction_handler' => null,
@@ -308,7 +308,7 @@ class XmlTypeCheck {
 
        /**
         * @param string $name
-        * @param string $attribs
+        * @param array $attribs
         */
        private function elementOpen( $name, $attribs ) {
                $this->elementDataContext[] = [ $name, $attribs ];
index 760d137..dfad922 100644 (file)
@@ -1068,7 +1068,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        protected function isTransactableQuery( $sql ) {
                return !in_array(
                        $this->getQueryVerb( $sql ),
-                       [ 'BEGIN', 'ROLLBACK', 'COMMIT', 'SET', 'SHOW', 'CREATE', 'ALTER', 'USE' ],
+                       [ 'BEGIN', 'ROLLBACK', 'COMMIT', 'SET', 'SHOW', 'CREATE', 'ALTER', 'USE', 'SHOW' ],
                        true
                );
        }
@@ -3626,7 +3626,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         * Actually run any "atomic section cancel" callbacks.
         *
         * @param int $trigger IDatabase::TRIGGER_* constant
-        * @param AtomicSectionIdentifier[]|null $sectionId Section IDs to cancel,
+        * @param AtomicSectionIdentifier[]|null $sectionIds Section IDs to cancel,
         *  null on transaction rollback
         */
        private function runOnAtomicSectionCancelCallbacks(
index e3c2268..b3af8ad 100644 (file)
@@ -601,7 +601,8 @@ abstract class DatabaseMysqlBase extends Database {
         */
        public function fieldInfo( $table, $field ) {
                $table = $this->tableName( $table );
-               $res = $this->query( "SELECT * FROM $table LIMIT 1", __METHOD__, true );
+               $flags = self::QUERY_SILENCE_ERRORS;
+               $res = $this->query( "SELECT * FROM $table LIMIT 1", __METHOD__, $flags );
                if ( !$res ) {
                        return false;
                }
@@ -722,7 +723,8 @@ abstract class DatabaseMysqlBase extends Database {
         * @return bool|int
         */
        protected function getLagFromSlaveStatus() {
-               $res = $this->query( 'SHOW SLAVE STATUS', __METHOD__ );
+               $flags = self::QUERY_SILENCE_ERRORS | self::QUERY_IGNORE_DBO_TRX;
+               $res = $this->query( 'SHOW SLAVE STATUS', __METHOD__, $flags );
                $row = $res ? $res->fetchObject() : false;
                // If the server is not replicating, there will be no row
                if ( $row && strval( $row->Seconds_Behind_Master ) !== '' ) {
@@ -824,7 +826,8 @@ abstract class DatabaseMysqlBase extends Database {
 
                                // Connect to and query the master; catch errors to avoid outages
                                try {
-                                       $res = $conn->query( 'SELECT @@server_id AS id', $fname );
+                                       $flags = self::QUERY_SILENCE_ERRORS | self::QUERY_IGNORE_DBO_TRX;
+                                       $res = $conn->query( 'SELECT @@server_id AS id', $fname, $flags );
                                        $row = $res ? $res->fetchObject() : false;
                                        $id = $row ? (int)$row->id : 0;
                                } catch ( DBError $e ) {
@@ -854,7 +857,8 @@ abstract class DatabaseMysqlBase extends Database {
                        // percision field is not supported in MySQL <= 5.5.
                        $res = $this->query(
                                "SELECT ts FROM heartbeat.heartbeat WHERE $whereSQL ORDER BY ts DESC LIMIT 1",
-                               __METHOD__
+                               __METHOD__,
+                               self::QUERY_SILENCE_ERRORS | self::QUERY_IGNORE_DBO_TRX
                        );
                        $row = $res ? $res->fetchObject() : false;
                } finally {
@@ -1032,7 +1036,9 @@ abstract class DatabaseMysqlBase extends Database {
                        $this->srvCache->makeGlobalKey( 'mysql-server-id', $this->getServer() ),
                        self::SERVER_ID_CACHE_TTL,
                        function () use ( $fname ) {
-                               $res = $this->query( "SELECT @@server_id AS id", $fname );
+                               $flags = self::QUERY_IGNORE_DBO_TRX;
+                               $res = $this->query( "SELECT @@server_id AS id", $fname, $flags );
+
                                return intval( $this->fetchObject( $res )->id );
                        }
                );
@@ -1042,11 +1048,13 @@ abstract class DatabaseMysqlBase extends Database {
         * @return string|null
         */
        protected function getServerUUID() {
+               $fname = __METHOD__;
                return $this->srvCache->getWithSetCallback(
                        $this->srvCache->makeGlobalKey( 'mysql-server-uuid', $this->getServer() ),
                        self::SERVER_ID_CACHE_TTL,
-                       function () {
-                               $res = $this->query( "SHOW GLOBAL VARIABLES LIKE 'server_uuid'" );
+                       function () use ( $fname ) {
+                               $flags = self::QUERY_IGNORE_DBO_TRX;
+                               $res = $this->query( "SHOW GLOBAL VARIABLES LIKE 'server_uuid'", $fname, $flags );
                                $row = $this->fetchObject( $res );
 
                                return $row ? $row->Value : null;
@@ -1060,13 +1068,15 @@ abstract class DatabaseMysqlBase extends Database {
         */
        protected function getServerGTIDs( $fname = __METHOD__ ) {
                $map = [];
+
+               $flags = self::QUERY_IGNORE_DBO_TRX;
                // Get global-only variables like gtid_executed
-               $res = $this->query( "SHOW GLOBAL VARIABLES LIKE 'gtid_%'", $fname );
+               $res = $this->query( "SHOW GLOBAL VARIABLES LIKE 'gtid_%'", $fname, $flags );
                foreach ( $res as $row ) {
                        $map[$row->Variable_name] = $row->Value;
                }
                // Get session-specific (e.g. gtid_domain_id since that is were writes will log)
-               $res = $this->query( "SHOW SESSION VARIABLES LIKE 'gtid_%'", $fname );
+               $res = $this->query( "SHOW SESSION VARIABLES LIKE 'gtid_%'", $fname, $flags );
                foreach ( $res as $row ) {
                        $map[$row->Variable_name] = $row->Value;
                }
@@ -1080,11 +1090,14 @@ abstract class DatabaseMysqlBase extends Database {
         * @return string[] Latest available server status row
         */
        protected function getServerRoleStatus( $role, $fname = __METHOD__ ) {
-               return $this->query( "SHOW $role STATUS", $fname )->fetchRow() ?: [];
+               $flags = self::QUERY_IGNORE_DBO_TRX;
+
+               return $this->query( "SHOW $role STATUS", $fname, $flags )->fetchRow() ?: [];
        }
 
        public function serverIsReadOnly() {
-               $res = $this->query( "SHOW GLOBAL VARIABLES LIKE 'read_only'", __METHOD__ );
+               $flags = self::QUERY_IGNORE_DBO_TRX;
+               $res = $this->query( "SHOW GLOBAL VARIABLES LIKE 'read_only'", __METHOD__, $flags );
                $row = $this->fetchObject( $res );
 
                return $row ? ( strtolower( $row->Value ) === 'on' ) : false;
@@ -1149,9 +1162,10 @@ abstract class DatabaseMysqlBase extends Database {
         */
        public function setSessionOptions( array $options ) {
                if ( isset( $options['connTimeout'] ) ) {
+                       $flags = self::QUERY_IGNORE_DBO_TRX;
                        $timeout = (int)$options['connTimeout'];
-                       $this->query( "SET net_read_timeout=$timeout" );
-                       $this->query( "SET net_write_timeout=$timeout" );
+                       $this->query( "SET net_read_timeout=$timeout", __METHOD__, $flags );
+                       $this->query( "SET net_write_timeout=$timeout", __METHOD__, $flags );
                }
        }
 
@@ -1184,8 +1198,10 @@ abstract class DatabaseMysqlBase extends Database {
                }
 
                $encName = $this->addQuotes( $this->makeLockName( $lockName ) );
-               $result = $this->query( "SELECT IS_FREE_LOCK($encName) AS lockstatus", $method );
-               $row = $this->fetchObject( $result );
+
+               $flags = self::QUERY_IGNORE_DBO_TRX;
+               $res = $this->query( "SELECT IS_FREE_LOCK($encName) AS lockstatus", $method, $flags );
+               $row = $this->fetchObject( $res );
 
                return ( $row->lockstatus == 1 );
        }
@@ -1198,8 +1214,10 @@ abstract class DatabaseMysqlBase extends Database {
         */
        public function lock( $lockName, $method, $timeout = 5 ) {
                $encName = $this->addQuotes( $this->makeLockName( $lockName ) );
-               $result = $this->query( "SELECT GET_LOCK($encName, $timeout) AS lockstatus", $method );
-               $row = $this->fetchObject( $result );
+
+               $flags = self::QUERY_IGNORE_DBO_TRX;
+               $res = $this->query( "SELECT GET_LOCK($encName, $timeout) AS lockstatus", $method, $flags );
+               $row = $this->fetchObject( $res );
 
                if ( $row->lockstatus == 1 ) {
                        parent::lock( $lockName, $method, $timeout ); // record
@@ -1221,8 +1239,10 @@ abstract class DatabaseMysqlBase extends Database {
         */
        public function unlock( $lockName, $method ) {
                $encName = $this->addQuotes( $this->makeLockName( $lockName ) );
-               $result = $this->query( "SELECT RELEASE_LOCK($encName) as lockstatus", $method );
-               $row = $this->fetchObject( $result );
+
+               $flags = self::QUERY_IGNORE_DBO_TRX;
+               $res = $this->query( "SELECT RELEASE_LOCK($encName) as lockstatus", $method, $flags );
+               $row = $this->fetchObject( $res );
 
                if ( $row->lockstatus == 1 ) {
                        parent::unlock( $lockName, $method ); // record
@@ -1258,13 +1278,13 @@ abstract class DatabaseMysqlBase extends Database {
                }
 
                $sql = "LOCK TABLES " . implode( ',', $items );
-               $this->query( $sql, $method );
+               $this->query( $sql, $method, self::QUERY_IGNORE_DBO_TRX );
 
                return true;
        }
 
        protected function doUnlockTables( $method ) {
-               $this->query( "UNLOCK TABLES", $method );
+               $this->query( "UNLOCK TABLES", $method, self::QUERY_IGNORE_DBO_TRX );
 
                return true;
        }
@@ -1285,7 +1305,7 @@ abstract class DatabaseMysqlBase extends Database {
                                (bool)$this->selectField( false, '@@sql_big_selects', '', __METHOD__ );
                }
                $encValue = $value ? '1' : '0';
-               $this->query( "SET sql_big_selects=$encValue", __METHOD__ );
+               $this->query( "SET sql_big_selects=$encValue", __METHOD__, self::QUERY_IGNORE_DBO_TRX );
        }
 
        /**
@@ -1468,7 +1488,8 @@ abstract class DatabaseMysqlBase extends Database {
         * @return array
         */
        private function getMysqlStatus( $which = "%" ) {
-               $res = $this->query( "SHOW STATUS LIKE '{$which}'" );
+               $flags = self::QUERY_IGNORE_DBO_TRX;
+               $res = $this->query( "SHOW STATUS LIKE '{$which}'", __METHOD__, $flags );
                $status = [];
 
                foreach ( $res as $row ) {
index 17f12d3..c1a3ab5 100644 (file)
@@ -23,6 +23,7 @@
  */
 namespace Wikimedia\Rdbms;
 
+use NullLockManager;
 use PDO;
 use PDOException;
 use Exception;
@@ -39,7 +40,7 @@ class DatabaseSqlite extends Database {
        /** @var bool Whether full text is enabled */
        private static $fulltextEnabled = null;
 
-       /** @var string Directory */
+       /** @var string|null Directory */
        protected $dbDir;
        /** @var string File name for SQLite database file */
        protected $dbPath;
@@ -91,10 +92,16 @@ class DatabaseSqlite extends Database {
                        $this->queryLogger->warning( "Invalid SQLite transaction mode provided." );
                }
 
-               $this->lockMgr = new FSLockManager( [
-                       'domain' => $lockDomain,
-                       'lockDirectory' => "{$this->dbDir}/locks"
-               ] );
+               if ( $this->hasProcessMemoryPath() ) {
+                       $this->lockMgr = new NullLockManager( [ 'domain' => $lockDomain ] );
+               } else {
+                       $this->lockMgr = new FSLockManager( [
+                               'domain' => $lockDomain,
+                               'lockDirectory' => is_string( $this->dbDir )
+                                       ? "{$this->dbDir}/locks"
+                                       : dirname( $this->dbPath ) . "/locks"
+                       ] );
+               }
 
                parent::__construct( $p );
        }
@@ -186,7 +193,7 @@ class DatabaseSqlite extends Database {
         * @throws DBConnectionError
         */
        protected function openFile( $fileName, $dbName, $tablePrefix ) {
-               if ( !$this->hasMemoryPath() && !is_readable( $fileName ) ) {
+               if ( !$this->hasProcessMemoryPath() && !is_readable( $fileName ) ) {
                        $error = "SQLite database file not readable";
                        $this->connLogger->error(
                                "Error connecting to {db_server}: {error}",
@@ -772,13 +779,13 @@ class DatabaseSqlite extends Database {
        }
 
        public function serverIsReadOnly() {
-               return ( !$this->hasMemoryPath() && !is_writable( $this->dbPath ) );
+               return ( !$this->hasProcessMemoryPath() && !is_writable( $this->dbPath ) );
        }
 
        /**
         * @return bool
         */
-       private function hasMemoryPath() {
+       private function hasProcessMemoryPath() {
                return ( strpos( $this->dbPath, ':memory:' ) === 0 );
        }
 
@@ -974,17 +981,19 @@ class DatabaseSqlite extends Database {
        }
 
        public function lock( $lockName, $method, $timeout = 5 ) {
-               if ( !is_dir( "{$this->dbDir}/locks" ) ) { // create dir as needed
-                       if ( !is_writable( $this->dbDir ) || !mkdir( "{$this->dbDir}/locks" ) ) {
-                               throw new DBError( $this, "Cannot create directory \"{$this->dbDir}/locks\"." );
-                       }
+               // Give better error message for permission problems than just returning false
+               if (
+                       !is_dir( "{$this->dbDir}/locks" ) &&
+                       ( !is_writable( $this->dbDir ) || !mkdir( "{$this->dbDir}/locks" ) )
+               ) {
+                       throw new DBError( $this, "Cannot create directory \"{$this->dbDir}/locks\"." );
                }
 
                return $this->lockMgr->lock( [ $lockName ], LockManager::LOCK_EX, $timeout )->isOK();
        }
 
        public function unlock( $lockName, $method ) {
-               return $this->lockMgr->unlock( [ $lockName ], LockManager::LOCK_EX )->isOK();
+               return $this->lockMgr->unlock( [ $lockName ], LockManager::LOCK_EX )->isGood();
        }
 
        /**
index 5dd4b49..c1eceb0 100644 (file)
@@ -53,9 +53,7 @@ class DatabaseDomain {
                }
                $this->schema = $schema;
                if ( !is_string( $prefix ) ) {
-                       throw new InvalidArgumentException( 'Prefix must be a string.' );
-               } elseif ( $prefix !== '' && substr( $prefix, -1, 1 ) !== '_' ) {
-                       throw new InvalidArgumentException( 'A non-empty prefix must end with "_".' );
+                       throw new InvalidArgumentException( "Prefix must be a string." );
                }
                $this->prefix = $prefix;
        }
index 3e942ae..e8dd898 100644 (file)
@@ -613,9 +613,13 @@ class LogFormatter {
                                $this->setShowUserToolLinks( false );
 
                                $user = User::newFromName( $value );
-                               $value = Message::rawParam( $this->makeUserLink( $user ) );
 
-                               $this->setShowUserToolLinks( $saveLinkFlood );
+                               if ( !$user ) {
+                                       $value = $this->msg( 'empty-username' )->text();
+                               } else {
+                                       $value = Message::rawParam( $this->makeUserLink( $user ) );
+                                       $this->setShowUserToolLinks( $saveLinkFlood );
+                               }
                                break;
                        case 'title':
                                $title = Title::newFromText( $value );
index c0adb51..e9853b1 100644 (file)
@@ -382,6 +382,7 @@ class ObjectCache {
         * @deprecated Since 1.28 Use MediaWikiServices::getInstance()->getMainObjectStash()
         */
        public static function getMainStashInstance() {
+               wfDeprecated( __METHOD__, '1.28' );
                return MediaWikiServices::getInstance()->getMainObjectStash();
        }
 
index cdb8f25..2ed8729 100644 (file)
@@ -142,6 +142,8 @@ class NamespaceInfo {
         *
         * @param int $index Namespace index
         * @return int
+        * @throws MWException if the given namespace doesn't have an associated talk namespace
+        *         (e.g. NS_SPECIAL).
         */
        public function getTalk( $index ) {
                $this->isMethodValidFor( $index, __METHOD__ );
@@ -151,15 +153,52 @@ class NamespaceInfo {
        }
 
        /**
+        * Get a LinkTarget referring to the talk page of $target.
+        *
+        * @see canHaveTalkPage
         * @param LinkTarget $target
         * @return LinkTarget Talk page for $target
-        * @throws MWException if $target's namespace doesn't have talk pages (e.g., NS_SPECIAL)
+        * @throws MWException if $target doesn't have talk pages, e.g. because it's in NS_SPECIAL,
+        *         because it's a relative section-only link, or it's an an interwiki link.
         */
        public function getTalkPage( LinkTarget $target ) : LinkTarget {
+               if ( $target->getText() === '' ) {
+                       throw new MWException( 'Can\'t determine talk page associated with relative section link' );
+               }
+
+               if ( $target->getInterwiki() !== '' ) {
+                       throw new MWException( 'Can\'t determine talk page associated with interwiki link' );
+               }
+
                if ( $this->isTalk( $target->getNamespace() ) ) {
                        return $target;
                }
-               return new TitleValue( $this->getTalk( $target->getNamespace() ), $target->getDbKey() );
+
+               // NOTE: getTalk throws on bad namespaces!
+               return new TitleValue( $this->getTalk( $target->getNamespace() ), $target->getDBkey() );
+       }
+
+       /**
+        * Can the title have a corresponding talk page?
+        *
+        * False for relative section-only links (with getText() === ''),
+        * interwiki links (with getInterwiki() !== ''), and pages in NS_SPECIAL.
+        *
+        * @see getTalkPage
+        *
+        * @param LinkTarget $target
+        * @return bool True if this title either is a talk page or can have a talk page associated.
+        */
+       public function canHaveTalkPage( LinkTarget $target ) {
+               if ( $target->getText() === '' || $target->getInterwiki() !== '' ) {
+                       return false;
+               }
+
+               if ( $target->getNamespace() < NS_MAIN ) {
+                       return false;
+               }
+
+               return true;
        }
 
        /**
@@ -188,7 +227,7 @@ class NamespaceInfo {
                if ( $this->isSubject( $target->getNamespace() ) ) {
                        return $target;
                }
-               return new TitleValue( $this->getSubject( $target->getNamespace() ), $target->getDbKey() );
+               return new TitleValue( $this->getSubject( $target->getNamespace() ), $target->getDBkey() );
        }
 
        /**
@@ -216,8 +255,16 @@ class NamespaceInfo {
         * @throws MWException if $target's namespace doesn't have talk pages (e.g., NS_SPECIAL)
         */
        public function getAssociatedPage( LinkTarget $target ) : LinkTarget {
+               if ( $target->getText() === '' ) {
+                       throw new MWException( 'Can\'t determine talk page associated with relative section link' );
+               }
+
+               if ( $target->getInterwiki() !== '' ) {
+                       throw new MWException( 'Can\'t determine talk page associated with interwiki link' );
+               }
+
                return new TitleValue(
-                       $this->getAssociated( $target->getNamespace() ), $target->getDbKey() );
+                       $this->getAssociated( $target->getNamespace() ), $target->getDBkey() );
        }
 
        /**
index f7dcb93..d0d8351 100644 (file)
@@ -3463,7 +3463,7 @@ class User implements IDBAccessObject, UserIdentity {
 
                        if ( $count === null ) {
                                // it has not been initialized. do so.
-                               $count = $this->initEditCountInternal();
+                               $count = $this->initEditCountInternal( $dbr );
                        }
                        $this->mEditCount = $count;
                }
@@ -5023,14 +5023,13 @@ class User implements IDBAccessObject, UserIdentity {
        /**
         * Initialize user_editcount from data out of the revision table
         *
-        * This method should not be called outside User/UserEditCountUpdate
-        *
+        * @internal This method should not be called outside User/UserEditCountUpdate
+        * @param IDatabase $dbr Replica database
         * @return int Number of edits
         */
-       public function initEditCountInternal() {
+       public function initEditCountInternal( IDatabase $dbr ) {
                // Pull from a replica DB to be less cruel to servers
                // Accuracy isn't the point anyway here
-               $dbr = wfGetDB( DB_REPLICA );
                $actorWhere = ActorMigration::newMigration()->getWhere( $dbr, 'rev_user', $this );
                $count = (int)$dbr->selectField(
                        [ 'revision' ] + $actorWhere['tables'],
index c5ff9d6..9fc7d73 100644 (file)
@@ -391,27 +391,30 @@ class LanguageConverter {
                   IMPORTANT: Beware of failure from pcre.backtrack_limit (T124404).
                   Minimize use of backtracking where possible.
                */
-               $marker = '|' . Parser::MARKER_PREFIX . '[^\x7f]++\x7f';
-
-               // this one is needed when the text is inside an HTML markup
-               $htmlfix = '|<[^>\004]++(?=\004$)|^[^<>]*+>';
-
-               // Optimize for the common case where these tags have
-               // few or no children. Thus try and possesively get as much as
-               // possible, and only engage in backtracking when we hit a '<'.
-
-               // disable convert to variants between <code> tags
-               $codefix = '<code>[^<]*+(?:(?:(?!<\/code>).)[^<]*+)*+<\/code>|';
-               // disable conversion of <script> tags
-               $scriptfix = '<script[^>]*+>[^<]*+(?:(?:(?!<\/script>).)[^<]*+)*+<\/script>|';
-               // disable conversion of <pre> tags
-               $prefix = '<pre[^>]*+>[^<]*+(?:(?:(?!<\/pre>).)[^<]*+)*+<\/pre>|';
-               // The "|.*+)" at the end, is in case we missed some part of html syntax,
-               // we will fail securely (hopefully) by matching the rest of the string.
-               $htmlFullTag = '<(?:[^>=]*+(?>[^>=]*+=\s*+(?:"[^"]*"|\'[^\']*\'|[^\'">\s]*+))*+[^>=]*+>|.*+)|';
-
-               $reg = '/' . $codefix . $scriptfix . $prefix . $htmlFullTag .
-                       '&[a-zA-Z#][a-z0-9]++;' . $marker . $htmlfix . '|\004$/s';
+               static $reg;
+               if ( $reg === null ) {
+                       $marker = '|' . Parser::MARKER_PREFIX . '[^\x7f]++\x7f';
+
+                       // this one is needed when the text is inside an HTML markup
+                       $htmlfix = '|<[^>\004]++(?=\004$)|^[^<>]*+>';
+
+                       // Optimize for the common case where these tags have
+                       // few or no children. Thus try and possesively get as much as
+                       // possible, and only engage in backtracking when we hit a '<'.
+
+                       // disable convert to variants between <code> tags
+                       $codefix = '<code>[^<]*+(?:(?:(?!<\/code>).)[^<]*+)*+<\/code>|';
+                       // disable conversion of <script> tags
+                       $scriptfix = '<script[^>]*+>[^<]*+(?:(?:(?!<\/script>).)[^<]*+)*+<\/script>|';
+                       // disable conversion of <pre> tags
+                       $prefix = '<pre[^>]*+>[^<]*+(?:(?:(?!<\/pre>).)[^<]*+)*+<\/pre>|';
+                       // The "|.*+)" at the end, is in case we missed some part of html syntax,
+                       // we will fail securely (hopefully) by matching the rest of the string.
+                       $htmlFullTag = '<(?:[^>=]*+(?>[^>=]*+=\s*+(?:"[^"]*"|\'[^\']*\'|[^\'">\s]*+))*+[^>=]*+>|.*+)|';
+
+                       $reg = '/' . $codefix . $scriptfix . $prefix . $htmlFullTag .
+                                '&[a-zA-Z#][a-z0-9]++;' . $marker . $htmlfix . '|\004$/s';
+               }
                $startPos = 0;
                $sourceBlob = '';
                $literalBlob = '';
@@ -426,8 +429,9 @@ class LanguageConverter {
 
                // We add a marker (\004) at the end of text, to ensure we always match the
                // entire text (Otherwise, pcre.backtrack_limit might cause silent failure)
+               $textWithMarker = $text . "\004";
                while ( $startPos < strlen( $text ) ) {
-                       if ( preg_match( $reg, $text . "\004", $markupMatches, PREG_OFFSET_CAPTURE, $startPos ) ) {
+                       if ( preg_match( $reg, $textWithMarker, $markupMatches, PREG_OFFSET_CAPTURE, $startPos ) ) {
                                $elementPos = $markupMatches[0][1];
                                $element = $markupMatches[0][0];
                                if ( $element === "\004" ) {
index 1bc2f18..bf8f203 100644 (file)
        "help-mediawiki": "Pitulung MediaWiki",
        "search": "Rereh",
        "searchbutton": "Rereh",
+       "go": "Lanturang",
        "searcharticle": "Rereh",
        "history": "Babad kaca",
        "history_short": "Babad",
index d47aaec..dbd4460 100644 (file)
        "protect": "ساتیتین",
        "protect_change": "بدل کورتین",
        "unprotect": "پروتکشنء ٹگل بدئ",
-       "newpage": "نوکین دیم",
+       "newpage": "نۏکݔں تاک",
        "talkpagelinktext": "گپ کن",
        "specialpage": "هاسین دیم",
        "personaltools": "شخصی وسایل",
        "currentevents-url": "Project:هنوکین رویداد",
        "disclaimers": "بے میاری",
        "disclaimerpage": "Project:عمومی بی میاریگان",
-       "edithelp": "کمک اصلاح",
+       "edithelp": "ٹگلݔنگء پئیم",
        "helppage-top-gethelp": "کومک",
        "mainpage": "بُنیادی دیم",
        "mainpage-description": "بُنیادی دیم",
        "editold": "ایڈیٹ",
        "viewsourceold": "به گند منبع ا",
        "editlink": "ایڈیٹ",
-       "viewsourcelink": "چارگ منبع",
+       "viewsourcelink": "سرچمّگء چارگ",
        "editsectionhint": ": $1اصلاح انتخاب",
        "toc": "محتوا",
        "showtoc": "پیش دار",
        "virus-unknownscanner": "ناشناسین آنتی ویروس:",
        "logouttext": "''' شما انیگء در شُت ات'''\nبزان که تانکه شمئی بروزرء چیرداتگین هافظه پهک مبیت، لهتئ چه تاکان ممکن انت رندا هم هنچوش پیش دارگ ببنت که انگار شما لاگین کتگ ات.",
        "welcomeuser": "وشاتک ات $1!",
-       "welcomecreation-msg": "انیگء شمئی اکانت اڈ بیتگ انت.\nمشموش ات که وتی [[Special:Preferences|ترجیحات {{SITENAME}}]] رء ٹگل دئیت.",
+       "welcomecreation-msg": "نۏکی شمئی ساب جۏڈ کنگ بیتہ.\nمہ شمۏش اِت کہ وتی [[Special:Preferences|واھشتاں {{SITENAME}}]] ٹگل بہ دئ اِت.",
        "yourname": "کار زوروکی نام:",
        "userlogin-yourname": "کار زوروکی نام",
        "userlogin-yourname-ph": "وتی یوزرنامء بلک ات",
        "createacct-submit": "وتی اکانتء اڈ کن ات",
        "createacct-another-submit": "سابے جۏڈݔن",
        "createacct-benefit-heading": "{{SITENAME}} شهسانی واسته هنچوش که شمئیء اڈ بیتگ",
-       "createacct-benefit-body1": "$1 {{PLURAL:$1|اصلاح|اصلاح کتگان}}",
+       "createacct-benefit-body1": "$1 {{PLURAL:$1|ٹگل|ٹگلاں}}",
        "createacct-benefit-body2": "{{PLURAL:$1|تاک|تاکان}}",
        "createacct-benefit-body3": "{{PLURAL:$1|هوار بیتگ}} نوکین",
        "badretype": "کلماتی رمزی که شما وارد کتگیت یک نهنت.",
        "session_fail_preview_html": "'''شرمنده! ما نه تونست شمی اصلاحء په خاطر گار کتن دیتا دیوان پردازش کنین.'''\n\n''په چی که {{SITENAME}} HTML هام فعالنت، بازبین په خاطر حملات JavaScript پناهنت.''\n\n''' اگر شی یک قانونی تلاش اصلاحنت، دگه کوشش کنیت. اگر هنگت کار نکنت یک بری [[Special:UserLogout|دربیت]] و دگه وارد بیت.'''",
        "token_suffix_mismatch": "''' شمی اصلاح رد بوت په چی که شمی کلاینت نویسگ کاراکترانی په هم جتت.\nاصلاح رد بوت داں چه هراب بیگ متن صفحه جلوگیری بیت.\nشی لهتی وهد پیش کت که شما چه یک هرابین سرویس پروکسی وبی استفاده کنیت.'''",
        "edit_form_incomplete": "<strong>لهتی چه ادیت فرمء بهران پر سرورء نرستگ انت؛ پکا بزان ات که شمئی ادیتان پکا انت و رندء چدوبارگ جهد کن ات</strong>",
-       "editing": "اصلاح $1",
+       "editing": "$1 ء ٹگلݔنگ",
        "creating": "اڈ کتن $1",
        "editingsection": "اصلاح $1(بخش)",
-       "editingcomment": "اصلاح $1 (نوکین بخش)",
+       "editingcomment": "$1 (نۏکݔن چُنڈ) تگلݔنگ",
        "editconflict": "جنگ ورگ اصلاح: $1",
        "explainconflict": "کسی دگه ای صفحه یا عوض کتت چه وهدی که شما اصلاح آیء شروع کتء.\nبالادی ناحیه متن شامل متن صفحه همی داب که هنگت هست.\nشمی تغییرات ته جهلیگین ناحیه متن جاه کیت.\nشما بایدن وتی تغییرات آن گون هنوکین متن چن و بند کنیت.\n'''فقط''' ناحیه بالادی متن وهدی که شما دکمه  \"$1\" ذخیره بنت.",
        "yourtext": "شمی متن",
        "search-external": "حارجی گردگ",
        "searchdisabled": "{{SITENAME}} گردگ غیر فعالنت.\nشما نونیت بگردیت چه طرق گوگل هم زمان.\nتوجه که اندیکس آن {{SITENAME}} محتوا شاید تاریح گوستگین بنت.",
        "search-error": "ارور مان شوهازء درگت: $1",
-       "preferences": "ترجیحات",
-       "mypreferences": "ترجیحات",
+       "preferences": "واھشتاں",
+       "mypreferences": "واھشتاں",
        "prefs-edits": "تعداد اصلاحات:",
        "prefsnologintext2": "منتوارون شمی که په ٹگل داتین تنزیماتانی هاتبرا لوگین بئیت .",
        "prefs-skin": "پوست",
        "prefs-user-pages": "کاربریگین تاکان",
        "prefs-personal": "نمایه کاربر",
        "prefs-rc": "نۏکݔں ٹگلاں",
-       "prefs-watchlist": "لیست چارگ",
+       "prefs-watchlist": "چارگء لیست",
        "prefs-editwatchlist": "چارگ لیستءِ ٹگلݔنگ",
        "prefs-watchlist-days": "روچان په پیش دارگ ته لیست چارگ",
        "prefs-watchlist-days-max": "(مکسیمم $1 {{PLURAL:$1|روچ|روچ}})",
        "prefs-rendering": "شکل صفحه",
        "saveprefs": "ذخیره",
        "restoreprefs": "پهکین پیش‌ پرزین تنظیمانء واتر بکن (مان پهکین بهران)",
-       "prefs-editing": "اصلاح",
+       "prefs-editing": "ٹگلݔنگ",
        "searchresultshead": "گردگ",
        "stub-threshold": "سرحد په  <a href=\"#\" class=\"stub\">چنڈ لینک</a> فرمت (بایت):",
        "stub-threshold-disabled": "نافعال",
        "recentchangescount": "تعداد اصلاحات به پیش دارگ به طور پیش فرض :",
        "prefs-help-recentchangescount": "شی هور گون نوکین تغییرات تاریح صفحات و سیاهگان انت.",
        "prefs-help-watchlist-token2": "ائ سکرٹ کلیت پر ویب فید چه شمئی چارگ لیست انت.\nهرشهسء که آئرء بزانت توان انت که شمئی چارگ لیستء بوان ات، پمیشکا آئرا شیر مکن ات. [[Special:ResetTokens|اگان آئیء ٹگلء لوٹ ات ادان کلیک بکن ات]].",
-       "savedprefs": "شمی ترجیحات ذخیره بوتن",
+       "savedprefs": "شمئی واھشت ٹگل دیگ بیت اَنت",
        "timezonelegend": "وهد ملک:",
        "localtime": "ملکی وهد:",
        "timezoneuseserverdefault": "پیش فرضین ویکیء کارمرز بکن ($1)",
        "prefs-dateformat": "تاریح داب",
        "prefs-timeoffset": "بنگیج بوتینِ وهد",
        "prefs-advancedediting": "عمومی تنظیمات",
-       "prefs-editor": "اصلاح کنوک",
+       "prefs-editor": "ٹگلݔنۏک",
        "prefs-preview": "پیشچارگ",
        "prefs-advancedrc": "پیشرفتگین گزینه",
        "prefs-advancedrendering": "پیشرفتگین گزینه",
        "listfiles-summary": "این صفحهٔ ویژه تمام پرونده‌های بارگذاری‌شده را نمایش می‌دهد.",
        "listfiles_search_for": "گردگ په  مدیا:",
        "imgfile": "فایل",
-       "listfiles": "Ù\84Û\8cست Ù\81اÛ\8cÙ\84",
+       "listfiles": "پائÙ\84Ø¡ Ù\84Û\8cستاں",
        "listfiles_thumb": "نائونی",
        "listfiles_date": "تاریح",
        "listfiles_name": "نام",
        "randomredirect-nopages": "\"$1\"هچ غیر مستقیمی ته ای نام فضا نیست.",
        "statistics": "آمار",
        "statistics-header-pages": "صفحه ی آمار",
-       "statistics-header-edits": "اصÙ\84اح Ø¢Ù\85ار",
+       "statistics-header-edits": "Ø¢Ù\85ارء Ù¹Ú¯Ù\84Ý\94Ù\86Ú¯",
        "statistics-header-users": "آمار کاربر",
        "statistics-header-hooks": "دیگرین آمار",
        "statistics-articles": "صفحات محتوا",
        "categoriesfrom": "پیشدار دسته جات که شروع بنت گون:",
        "deletedcontributions": "مشارکتان کابر حذف بوتء",
        "deletedcontributions-title": "مشارکتان کابر حذف بوتء",
-       "sp-deletedcontributions-contribs": "مشارکتان",
+       "sp-deletedcontributions-contribs": "امبنٚداں",
        "linksearch": "دراین لینک ان",
        "linksearch-pat": "گردگ الگو:",
        "linksearch-ns": "نام فضا:",
        "removedwatchtext": "صفحه\"[[:$1]]\"  چه [[Special:Watchlist|شمی لیست چارگ]]. دربیت.",
        "watch": "چار",
        "watchthispage": "ای تاکدیما بگیند",
-       "unwatch": "نه چارگ",
+       "unwatch": "نہ چارگ",
        "unwatchthispage": "چارگ بند کن",
        "notanarticle": "یک صفحه محتوا نهت",
        "notvisiblerev": "بازبینی حذف بوتت",
        "wlheader-showupdated": "صفحات که عوض بوتگنت چه شمی آهری چارتن '''پررنگ''' پیش دراگ بنت.",
        "wlnote": "جهلء {{PLURAL:$1|آهرین تغییر هست|آهرین هست'''$1''' تغییرات}} ته آهرین {{PLURAL:$2|ساعت|'''$2''' ساعات}}.",
        "wlshowlast": "پیش دار آهرین $1  ساعات $2 روچان",
-       "watchlist-options": "گزÛ\8cÙ\86Ù\87 Û\8cاÙ\86 Ù\84Û\8cست Ú\86ارگ",
-       "watching": "چارگ بین",
-       "unwatching": "نه چارگ بیت",
+       "watchlist-options": "Ú\86ارگء Ù\84Û\8cستء Ú¯Ø²Û\8cÙ\86Û\81â\80\8cئاں",
+       "watching": "چارگئں",
+       "unwatching": "چارگ نہ بیتگ",
        "enotif_reset": "نشان کن کل صفحات په داب چارتگین",
        "enotif_impersonal_salutation": "{{SITENAME}} کاربر",
        "enotif_lastvisited": "بچار  $1 په کلین تغییرات چه شمی آهری چارگ.",
        "minimum-size": "هوردی اندازه",
        "maximum-size": "مزنی اندازه",
        "pagesize": "(بایت)",
-       "restriction-edit": "اصلاح",
+       "restriction-edit": "ٹگلݔنگ",
        "restriction-move": "جاه په جاه کن",
        "restriction-create": "شرکتن",
        "restriction-upload": "آپلود",
        "blocklink": "محدود",
        "unblocklink": "رفع محدودیت",
        "change-blocklink": "عوض کتن کبل",
-       "contribslink": "مشارکتان",
+       "contribslink": "امبنٚداں",
        "autoblocker": "اتوماتیک کبلت په چی که شمی آدرس آی پی نوکی استفاده بوتت گون  \"[[User:$1|$1]]\".\nداتگین دلیل په محدود کتن $1 شی انت: \"$2\"",
        "blocklogpage": "بلاک ورود",
        "blocklogentry": "محدود بوته [[$1]] گون یک زمان انقاضای $2 $3",
        "tooltip-ca-nstab-project": "بچار صفحه پروژه یا",
        "tooltip-ca-nstab-image": "صفحه فایل بگند",
        "tooltip-ca-nstab-mediawiki": "به گند کوله سیستمء",
-       "tooltip-ca-nstab-template": "چارگ تمپلت",
+       "tooltip-ca-nstab-template": "تیٚمپلئتء چارگ",
        "tooltip-ca-nstab-help": "صفحه کمک بچار",
        "tooltip-ca-nstab-category": "دسته صفحه ی بچار",
        "tooltip-minoredit": "شی آ په داب یک اصلاح جزی نشان بل",
        "spam_reverting": "عوض کتن په آهری نسحه که شامل لینکان می بیت په $1",
        "spam_blanking": "کل بازبینی آن شامل لینکان په $1, بوتت  هالیکی",
        "simpleantispam-label": "کنترل ضد اسپم.\nای شیء پر ''مکن''",
-       "pageinfo-firstuser": "تاکدÛ\8cÙ\85Û\8c Ø¬Ù\88Ú\91 Ú©Ù\86Ù\88ک",
+       "pageinfo-firstuser": "تاکء Ø¬Û\8fÚ\88Ý\94Ù\86Û\8fک",
        "pageinfo-category-info": "تهرِ مئلومات",
        "markaspatrolleddiff": "نشان کن په داب نظارت بوتگین",
        "markaspatrolledtext": "ای صفحه نشان کن په داب نظارت بوتگین",
        "filedelete-old-unregistered": "بازبینی فایل مشخص بوتگین \"$1\" ته دیتابیس نیست.",
        "filedelete-current-unregistered": "مشخص بوتگین فایل \"$1\" ته دیتابیس نیست.",
        "filedelete-archive-read-only": "مسیر آرشیو \"$1\" چه طرف وب سرور نویسگ نه بیت.",
-       "previousdiff": "← پیشگین اصلاح",
-       "nextdiff": "نوکترین اصلاح→",
+       "previousdiff": "← پݔسری ٹگلاں",
+       "nextdiff": "گُڈی ٹگلاں→",
        "mediawarning": "''''هوژاری:'''' ای فایل شاید شامل بد واهین کد بوت،اجرای آیی ته وتی سیستم شاید توافقی بیت.",
        "imagemaxsize": "محدودیت تصاویر: <br />''(په صفحات توضیح فایل)''",
        "thumbsize": "اندازه پیج انگشتی",
        "size-gigabytes": "$1 گ.ب",
        "lag-warn-normal": "تغییرات نوکتر چه {{PLURAL:$1|ثانیه|ثانیه}} ثانیه انت شاید ته ای لیست پجاه می کاینت.",
        "lag-warn-high": "خاطر بازگین تاخیر سرور دیتابیس، تغییرات نوکتر چه  {{PLURAL:$1|ثانیه|ثانیه}} شایدن ته ای لیست پیش دارگمه بنت.",
-       "watchlistedit-normal-title": "اصلاح لیست چارگ",
+       "watchlistedit-normal-title": "چارگ لیستء ٹگلݔنگ",
        "watchlistedit-normal-legend": "بزور عناوینء چه لیست چارگ",
        "watchlistedit-normal-explain": "عناوین ته شمی لیست چارگ جهلء پیشدارگ بنت.\nپه زورتن یک عنوانی، جعبه کش آییء تیک زن، و کلیک کن زوگ عناوینء.\nشما تونیت هنچوش [[Special:EditWatchlist/raw|لیست هام اصلاح کنیت]].",
        "watchlistedit-normal-submit": "بزور عناوینء",
        "duplicate-defaultsort": "هژاری: ترتیب پیش فرض «$2» ترتیب پیش فرض پیشگین «$1» را باطل کنت.",
        "version": "نسخة",
        "version-extensions": "نصب بوتگیت الحاق آن",
-       "version-specialpages": "حاصین صفحات",
-       "version-parserhooks": "تجزیه کنوک گیر کت",
+       "version-specialpages": "وتیگی تاکاں",
+       "version-parserhooks": "تجزیہ کنۏک‌ئا گیر کُت",
        "version-variables": "متغییران",
        "version-other": "دگر",
        "version-mediahandlers": "دست گروک مدیا",
        "fileduplicatesearch-info": "$1 × $2 پیکسل<br />اندازه فایل: $3<br />نوع مایم: $4",
        "fileduplicatesearch-result-1": " \"$1\" فایل هچ مشحصین دوبلی نیست.",
        "fileduplicatesearch-result-n": "فایل \"$1\" has {{PLURAL:$2|1 identical duplication|$2 مشخصین کپی بوتن}}.",
-       "specialpages": "حاصین صفحات",
+       "specialpages": "وتیگی تاکاں",
        "specialpages-note-restricted": "* نرمال صفحات حاص.\n*  <strong class=\"mw-specialpagerestricted\">محدودین صفحات حاص.</strong>",
        "specialpages-group-maintenance": "گزارشات دارگ",
        "specialpages-group-other": "دگر حاصین صفحات",
        "tags-display-header": "ظاهر تعییر لیستان",
        "tags-description-header": "کاملین توضیح معنا",
        "tags-hitcount-header": "اصلاحات برچسپی",
-       "tags-edit": "اصلاح",
+       "tags-edit": "ٹگلݔنگ",
        "tags-hitcount": "$1 {{PLURAL:$1|تغییر|تغییرات}}",
        "diff-form": "یک '''فرم'''",
        "dberr-problems": "شرمنده! این سایت ءَ تکنیکی مشکل هستن.",
index c0467cc..49db072 100644 (file)
        "specialmute-submit": "Пацьвердзіць",
        "specialmute-label-mute-email": "Заглушыць лісты электроннай пошты ад гэтага ўдзельніка",
        "specialmute-header": "Калі ласка, абярыце вашыя налады заглушэньня для {{BIDI:[[User:$1]]}}.",
+       "specialmute-error-invalid-user": "Запытанае імя ўдзельніка ня можа быць знойдзенае.",
+       "specialmute-error-email-blacklist-disabled": "Заглушэньне ўдзельнікам магчымасьці дасылаць вам лісты электроннай поштай ня ўключанае.",
        "revid": "вэрсія $1",
        "pageid": "Ідэнтыфікатар старонкі $1",
        "interfaceadmin-info": "$1\n\nДазволы на рэдагаваньне агульнасайтавых CSS/JS/JSON-файлаў былі нядаўна вылучаныя з права <code>editinterface</code>. Калі вы не разумееце, чаму атрымліваеце гэтую памылку, глядзіце [[mw:MediaWiki_1.32/interface-admin]].",
index 765e5f0..faa4581 100644 (file)
        "createacct-another-submit": "Crea un compte",
        "createacct-continue-submit": "Continua amb la creació del compte",
        "createacct-another-continue-submit": "Continua amb la creació del compte",
-       "createacct-benefit-heading": "{{SITENAME}} és feta per gent com tu.",
+       "createacct-benefit-heading": "Gent com vós fa possible {{SITENAME}}.",
        "createacct-benefit-body1": "{{PLURAL:$1|edició|edicions}}",
        "createacct-benefit-body2": "{{PLURAL:$1|pàgina|pàgines}}",
        "createacct-benefit-body3": "{{PLURAL:$1|col·laborador recent|col·laboradors recents}}",
index 7b58d71..f25543d 100644 (file)
        "action-move-rootuserpages": "pelanê karberiyê bıngeyan bere",
        "action-move-categorypages": "Pera kategoriyer ber",
        "action-movefile": "ena dosya bere",
-       "action-upload": "ena dosya bar ke",
+       "action-upload": "ena dosya bar ke",
        "action-reupload": "dosyayê ke database de esto ser ey binuse",
        "action-reupload-shared": "dosyayê ki ho embarê medyayî de esto ser ay binusne",
        "action-upload_by_url": "na dosya yew URL ra bar ke",
        "brokenredirects-edit": "bıvurne",
        "brokenredirects-delete": "bestere",
        "withoutinterwiki": "Pelê ke zıwananê binan rê gıreyê cı çıniyo",
-       "withoutinterwiki-summary": "Enê pelî ke versiyonê ziwanî binî ra link nidano.",
+       "withoutinterwiki-summary": "Pelê kı cêr dı liste biyê zıwananê binan rê gıreya muhtewa kenê.",
        "withoutinterwiki-legend": "Verole",
        "withoutinterwiki-submit": "Bımocne",
        "fewestrevisions": "Pelê be senık çımraviyarnayışi",
index 87bee6d..232e0f0 100644 (file)
                        "Marcelo9987",
                        "Cuatro Remos",
                        "Ryo567",
-                       "Agusbou2015"
+                       "Agusbou2015",
+                       "Waldyrious"
                ]
        },
        "tog-underline": "Enlaces que se van a subrayar:",
index ecd3eec..757ca0c 100644 (file)
@@ -8,7 +8,8 @@
                        "Opraco",
                        "Vitorvicentevalente",
                        "Waldir",
-                       555
+                       555,
+                       "Waldyrious"
                ]
        },
        "exif-imagewidth": "Largura",
index c9afaa9..2a55eb3 100644 (file)
                        "Akapochtli",
                        "ديفيد",
                        "Daimona Eaytoy",
-                       "A2093064"
+                       "A2093064",
+                       "Waldyrious"
                ]
        },
        "exif-imagewidth": "{{exif-qqq}}\n{{Identical|Width}}",
index 3a79359..862e281 100644 (file)
        "mcrundo-parse-failed": "Echec dans l'analyse de la nouvelle version : $1",
        "semicolon-separator": "&nbsp;;&#32;",
        "colon-separator": "&nbsp;:&#32;",
-       "ellipsis": "...",
+       "ellipsis": "",
        "percent": "$1&#160;%",
        "parentheses": "($1)",
        "parentheses-start": "(",
        "specialmute-submit": "Confirmer",
        "specialmute-label-mute-email": "Mettre en sourdine les courriels de cet utilisateur",
        "specialmute-header": "Veuillez sélectionner vos préférences de mise en sourdine pour {{BIDI:[[User:$1]]}}.",
-       "specialmute-error-invalid-user": "Le nom d'utilisateur demandé n'a pu être trouvé.",
-       "specialmute-error-email-blacklist-disabled": "Mise en sourdine des utilisateurs pour vous envoyer des courriels, non activée.",
+       "specialmute-error-invalid-user": "Le nom d’utilisateur demandé n’a pu être trouvé.",
+       "specialmute-error-email-blacklist-disabled": "La mise en sourdine des utilisateurs pour vous envoyer des courriels n’est pas activée.",
        "specialmute-error-email-preferences": "Vous devez confirmer votre adresse courriel avant de pouvoir mettre en sourdine un utilisateur. Vous pouvez le faire depuis [[Special:Preferences]].",
-       "specialmute-email-footer": "Pour gérer les préférences courriel pour {{BIDI:$2}} voir <$1>.",
-       "specialmute-login-required": "Veuillez vous connecter pour mettre à jour vos préférences de mise en sourdine d'utilisateurs.",
+       "specialmute-email-footer": "Veuillez voir <$1> pour gérer les préférences courriel pour {{BIDI:$2}}.",
+       "specialmute-login-required": "Veuillez vous connecter pour mettre-à-jour vos préférences de mise en sourdine d’utilisateurs.",
        "revid": "version $1",
        "pageid": "ID de page $1",
        "interfaceadmin-info": "$1\n\nLes droits pour modifier les fichiers CSS/JS/JSON globaux au site ont été récemment séparés du droit <code>editinterface</code>. Si vous ne comprenez pas pourquoi vous avez cette erreur, voyez [[mw:MediaWiki_1.32/interface-admin]].",
index a2573b7..5389289 100644 (file)
        "restrictionsfield-help": "כתובת IP אחת או טווח CIDR אחד בשורה. כדי לאפשר את הכול, ניתן להשתמש ב:<pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "שגיאה: $1",
        "edit-error-long": "שגיאות:\n\n$1",
+       "specialmute": "השתקה",
        "revid": "גרסה $1",
        "pageid": "מזהה דף $1",
        "interfaceadmin-info": "$1\n\nההרשאות לעריכת קובצי CSS/JS/JSON של האתר כולו הופרדו לאחרונה מההרשאה <code>editinterface</code>. אם לא ברור לך מדוע קיבלת את הודעת השגיאה הזאת, ר' [[mw:MediaWiki_1.32/interface-admin]].",
index eaee1b5..b05a311 100644 (file)
        "otherlanguages": "Այլ լեզուներով",
        "redirectedfrom": "(Վերայղուած է $1-էն)",
        "redirectpagesub": "վերայղման էջ",
-       "redirectto": "Õ\8eÕ¥Ö\80Õ¡ÕµÕ²Õ¥Õ¬ դէպի՝",
+       "redirectto": "Õ\8eÕ¥Ö\80Õ¡ÕµÕ²Õ¸Ö\82Õ´ դէպի՝",
        "lastmodifiedat": "Այս էջը վերջին անգամ խմբագրուած է $1 թուականի ժամը $2ին:",
        "viewcount": "Այս էջը բացուած է {{PLURAL:$1|մէկ անգամ|$1 անգամ}}։",
        "protectedpage": "Պաշտպանուած էջ",
        "prefs-editor": "Խմբագրող",
        "prefs-preview": "Կանխաստուգել",
        "group": "Խումբ.",
+       "group-user": "Մասնակիցներ",
        "group-bot": "Մեքենայիկներ",
        "group-sysop": "Վարիչներ",
+       "group-interface-admin": "Թեքնիկական hամակարգողներ",
        "group-sysop-member": "{{GENDER:$1|վարիչ}}",
        "grouppage-bot": "{{ns:project}}:Մեքենայիկներ",
        "grouppage-sysop": "{{ns:project}}:Վարիչներ",
        "recentchanges-legend-heading": "<strong>Ծանօթ.՝</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (տե՛ս նաեւ՝  [[Special:NewPages|նոր էջերու ցանկ]])",
        "rcfilters-activefilters": "Աշխոյժ զտիչներ",
+       "rcfilters-activefilters-hide": "Թաքցնել",
+       "rcfilters-activefilters-show": "Ցուցնել",
        "rcfilters-limit-title": "Ցուցադրուող արդիւնքներ",
        "rcnotefrom": "Ներքեւ {{PLURAL:$5|փոփոխութիւնն է|փոփոխութիւններն են}} սկսեալ <strong>$3, $4</strong> (մինչեւ <strong>$1</strong> ցոյց տրուած).",
        "rclistfrom": "Ցոյց տալ նոր փոփոխութիւնները սկսած $3 $2",
        "rcshowhideanons-show": "Ցուցնել",
        "rcshowhideanons-hide": "Թաքցնել",
        "rcshowhidepatr": "$1 ստուգուած խմբագրումները",
+       "rcshowhidepatr-show": "Ցուցնել",
+       "rcshowhidepatr-hide": "Թաքցնել",
        "rcshowhidemine": "$1 իմ խմբագրումներս",
        "rcshowhidemine-show": "Ցուցնել",
        "rcshowhidemine-hide": "Թաքցնել",
+       "rcshowhidecategorization-show": "Ցուցնել",
+       "rcshowhidecategorization-hide": "Թաքցնել",
        "rclinks": "Ցոյց տալ վերջին $1 փոփոխութիւնները վերջին $2 օրուան ընթացքին",
        "diff": "տարբ.",
        "hist": "պատմ.",
        "recentchangeslinked-page": "Էջին անունը՝",
        "recentchangeslinked-to": "Փոխարէնը ցոյց տալ տուեալ էջին առնչուած էջերուն մէջ կատարուած փոփոխութիւնները։",
        "upload": "Վերբեռնել նիշք",
+       "uploadbtn": "Վերբեռնել նիշք",
        "uploadlogpage": "Վերբեռնումի տեղեկատետր",
        "filedesc": "Ամփոփում",
+       "filesource": "Աղբիւր.",
+       "upload-dialog-button-cancel": "Չեղարկել",
+       "upload-dialog-button-back": "Ետ",
+       "upload-dialog-button-done": "Եղած է",
+       "upload-dialog-button-save": "Յիշել",
+       "upload-dialog-button-upload": "Վերբեռնել",
        "license": "Արտօնագրութիւն՝",
        "license-header": "Արտօնագրում",
+       "listfiles-delete": "ջնջել",
        "imgfile": "Նիշք",
        "listfiles": "Նիշքերու ցանկ",
+       "listfiles-latestversion-yes": "Այո",
+       "listfiles-latestversion-no": "Ոչ",
        "file-anchor-link": "Նիշք",
        "filehist": "Նիշքի պատմութիւն",
        "filehist-help": "‎Սեղմել օրուան/ժամին վրայ նիշքի այդ պահուն ունեցած վիճակը տեսնելու համար",
        "statistics-header-pages": "Էջերու վիճակագրութիւն",
        "statistics-header-edits": "Խմբագրումներու վիճակագրութիւն",
        "statistics-header-users": "Մասնակիցներու վիճակագրութիւն",
+       "statistics-pages": "Էջեր",
        "statistics-pages-desc": "Ուիքիի բոլոր էջերը՝ ներառեալ քննարկման էջերը, վերայղումները եւ այլն",
        "statistics-files": "Բեռնուած նիշքեր",
        "statistics-edits-average": "Իւրաքանչիւր էջի խմբագրումներուն միջին թիւը",
        "statistics-users-active": "Աշխոյժ մասնակիցներ",
+       "pageswithprop-submit": "Յառաջ",
        "double-redirect-fixer": "Վերայղումներու շտկիչ",
+       "brokenredirects-edit": "խմբագրել",
+       "brokenredirects-delete": "ջնջել",
+       "withoutinterwiki": "Լեզւային յղումներ չպարունակող էջեր",
+       "withoutinterwiki-submit": "Ցուցնել",
        "nbytes": "$1 {{PLURAL:$1|պայթ}}",
        "nmembers": "$1 {{PLURAL:$1|անդամ|անդամներ}}",
        "prefixindex": "Բոլոր նախածանցներով էջերը",
+       "prefixindex-submit": "Ցուցնել",
+       "protectedpages-page": "Էջ",
        "listusers": "Մասնակիցներու ցանկ",
        "newpages": "Նոր էջեր",
+       "newpages-submit": "Ցուցնել",
+       "newpages-username": "Մասնակիցի անուն.",
        "move": "Տեղափոխել այս էջը",
        "pager-newer-n": "{{PLURAL:$1|նոր 1|աւելի նոր $1}}",
        "pager-older-n": "{{PLURAL:$1|աւելի հին 1|աւելի հին $1}}",
+       "apisandbox-reset": "Մաքրել",
+       "apisandbox-retry": "Նորէն փորձել",
+       "apisandbox-add-multi": "Աւելցնել",
        "apisandbox-results": "Արդիւնքներ",
+       "apisandbox-continue-clear": "Մաքրել",
        "booksources": "Գիրքի աղբիւրներ",
        "booksources-search-legend": "Որոնել գիրքի մասին",
        "booksources-search": "Որոնել",
        "specialloguserlabel": "Կատարող․",
        "speciallogtitlelabel": "Թիրախ (վերնագիր կամ {{ns:user}}:մասնակիցի մասնակցային անուն)՝",
        "log": "Տեղեկատետրեր",
+       "logeventslist-submit": "Ցուցնել",
        "all-logs-page": "Բոլոր հանրային տեղեկատետրերը",
        "alllogstext": "{{SITENAME}} կայքի տեղեկատետրերու միացեալ ցանկ։\nԿրնաք արդիւնքները սահմանափակել ըստ տեղեկատետրի տեսակին, մասնակիցի անունին կամ համապատասխան էջին։",
        "logempty": "Համապատասխան տարրեր չկան տեղեկատետերին մէջ։",
        "allpagessubmit": "‎Յառաջանալ",
        "allpages-hide-redirects": "Թաքցնել վերայղումները",
        "categories": "Ստորոգութիւններ",
+       "categories-submit": "Ցուցնել",
        "deletedcontributions": "Մասնակիցի ջնջուած ներդրում",
+       "linksearch-ok": "Որոնել",
+       "listusers-submit": "Ցուցնել",
        "activeusers": "Աշխոյժ մասնակիցներու ցանկ",
        "activeusers-submit": "Ցոյց տալ աշխոյժ մասնակիցները",
+       "listgrouprights-rights": "Իրաւունքներ",
        "listgrouprights-members": "(անդամներու ցանկ)",
+       "listgrants-rights": "Իրաւունքներ",
        "emailuser": "Ե-նամակ ուղարկել այս մասնակիցին",
+       "emailusername": "Մասնակիցի անուն՝",
        "usermessage-editor": "Համակարգային սուրհանդակի անուն",
        "watchlist": "Հսկողութեան ցանկ",
        "mywatchlist": "Հսկողութեան ցանկ",
        "wlheader-showupdated": "Ձեր վերջին այցելութենէն ետք փոփոխուած Էջերը տրուած են <strong>շեշտուած տառերով<strong>։",
        "wlnote": "Ներքեւ տրուած {{PLURAL:$1|է վերջին փոփոխութիւնը|են վերջին '''$1''' փոփոխութիւնները}} վերջին <strong>$2</strong> ժամուան ընթացքին՝ $3, $4ի դրութեամբ։",
        "wlshowlast": "Ցոյց տալ վերջին $1 ժամերը $2 օրերը",
+       "watchlist-hide": "Թաքցնել",
+       "watchlist-submit": "Ցուցնել",
        "watchlist-options": "Հսկողութեան ացանկի նախընտրութիւններ",
        "enotif_reset": "Նշել բոլոր  այցելուած էջերը",
+       "delete-legend": "Ջնջել",
        "dellogpage": "Ջնջումներու տեղեկատետր",
+       "rollback-confirmation-no": "Չեղարկել",
        "rollbacklink": "Նախորդ տարբերակը ետ բերել",
        "rollbacklinkcount": "Յետարկում $1 {{PLURAL:$1|խմբագրում|խմբագրումներ}}",
        "protectlogpage": "Պահպանման տեղեկատետր",
        "protect-default": "Թոյլատրել բոլոր մասնակիցներուն",
        "restriction-edit": "Խմբագրել",
        "restriction-move": "Տեղափոխել այս էջը",
+       "undelete-search-submit": "Որոնել",
+       "undelete-show-file-submit": "Այո",
        "namespace": "Անուանատարածք՝",
        "invert": "Ընտրութիւնը շրջել",
        "tooltip-invert": "Նշեցէ՛ք տուփիկը թաքցնելու համար տուեալ անուանատարածքի եւ կից անուանատարածքներու (եթէ նշուած է) էջերու վրայի փոփոխութիւնները ։",
        "sp-contributions-blocklog": "արգելակումներու տեղեկատետր",
        "sp-contributions-uploads": "վերբեռնումներ",
        "sp-contributions-logs": "Տեղեկատետրեր",
-       "sp-contributions-talk": "Քննարկում",
+       "sp-contributions-talk": "քննարկում",
        "sp-contributions-search": "Որոնել ներդրումները",
        "sp-contributions-username": "IP-հասցէ կամ մասնակիցի անուն.",
        "sp-contributions-toponly": "Ցոյց տալ միայն վերջին տարբերակի խմբագրումները",
        "whatlinkshere-filters": "Զտիչներ",
        "unblock": "Մասնակիցի արգելակումը վերցնել",
        "ipboptions": "2 ժամ:2 hours,1 օր:1 day,3 օր:3 days,1 շաբաթ:1 week,2 շաբաթ:2 weeks,1 ամիս:1 month,3 ամիս:3 months,6 ամիս:6 months,1 տարի:1 year,անժամկէտ:infinite",
+       "ipb-pages-label": "Էջեր",
+       "ipb-namespaces-label": "Անուանատարածքներ",
        "infiniteblock": "Միշտ",
+       "blocklist-editing-page": "էջեր",
+       "blocklist-editing-ns": "անուանատարածքներ",
        "blocklink": "‎Արգելակել",
        "contribslink": "Ներդրումներ",
        "blocklogpage": "արգելակումներու տեղեկատետր",
        "proxyblocker": "Փոխանորդի արգելակում",
        "movelogpage": "Տեղափոխութիւններու տեղեկատետր",
        "export": "Արտածել էջերը",
+       "allmessages-language": "Լեզու.",
        "thumbnail-more": "Մեծցնել",
        "importlogpage": "Ներմուծման տեղեկատետր",
        "tooltip-pt-userpage": "{{GENDER:|Ձեր մասնակիցի}} էջը",
        "pageinfo-display-title": "Վերնագիր",
        "pageinfo-default-sort": "Միախմբումի ակամայ բանալի",
        "pageinfo-length": "էջի երկայնք (պայթերով)",
+       "pageinfo-namespace": "Անւանատարածք",
        "pageinfo-article-id": "Էջի ինքնութեան համար",
        "pageinfo-language": "Բովանդակութեան լեզու",
        "pageinfo-content-model": "Էջի պարունակութեան բնատիպ",
        "pageinfo-toolboxlink": "‎Էջի մասին տեղեկութիւն",
        "pageinfo-contentpage": "Իբրեւ բովանդակութեան էջ հաշուըւած",
        "pageinfo-contentpage-yes": "Այո",
+       "pageinfo-protect-cascading-yes": "Այո",
        "patrol-log-page": "Հսկողութեան տեղեկատետր",
        "previousdiff": "← Նախորդ խմբագրում",
        "nextdiff": "Յաջորդ խմբագրում →",
        "tags-active-yes": "Այո",
        "tags-active-no": "Ոչ",
        "tags-hitcount": "{{PLURAL:$1|փոփոխութիւն}}",
+       "htmlform-no": "Ոչ",
+       "htmlform-yes": "Այո",
        "logentry-delete-delete": "$1 {{GENDER:$2|ջնջեց}} $3 էջը",
        "logentry-delete-restore": "$1 {{GENDER:$2|վերականգնեց}} $3 ($4) էջը",
        "logentry-delete-revision": "$1 {{GENDER:$2|փոխեց}} {{PLURAL:$5|1 խմբագրման|$5 խմբագրումներու}} տեսանելիութիւնը $3 էջին վրայ՝ $4",
        "logentry-upload-upload": "$1 {{GENDER:$2|ներբեռնուած է}} $3",
        "logentry-upload-overwrite": "$1 {{GENDER:$2|վերբեռնեց}} $3ի նոր տարբերակ",
        "rightsnone": "(ոչ մէկ)",
+       "feedback-back": "Ետ",
        "feedback-cancel": "Չեղարկել",
+       "feedback-close": "Եղած է",
+       "feedback-thanks-title": "Շնորհակալութի՜ւն",
        "searchsuggest-search": "Որոնել {{SITENAME}} կայքին մէջ",
        "duration-days": "$1 {{PLURAL:$1|օր}}",
        "expand_templates_preview": "Կանխաստուգել",
+       "pagelang-name": "Էջ",
+       "pagelang-language": "Լեզու",
        "special-characters-group-latin": "Լատիներէն",
        "special-characters-group-arabic": "Արաբերէն",
        "randomrootpage": "Պատահական արմատ էջ"
index 442287e..8fdd0d7 100644 (file)
        "mycontris": "Framlög",
        "anoncontribs": "Framlög",
        "contribsub2": "Eftir {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Fyrir {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Notandaaðgangurinn \"$1\" er ekki skráður.",
        "nocontribs": "Engar breytingar fundnar sem passa við þessa viðmiðun.",
        "uctop": "núverandi",
index 9c42c2a..4763645 100644 (file)
        "credentialsform-account": "Konta nosaukums:",
        "edit-error-short": "Kļūda: $1",
        "edit-error-long": "Kļūdas:\n\n$1",
+       "specialmute-submit": "Apstiprināt",
        "revid": "versija $1",
        "pageid": "lapas ID $1",
        "gotointerwiki-invalid": "Norādītais nosaukums ir nederīgs.",
index eb80f11..5dafc1a 100644 (file)
        "page_first": "прв",
        "page_last": "последен",
        "histlegend": "Разлика помеѓу преработките: Означете ги преработките што сакате да ги споредите и притиснете на Enter или копчето на дното од страницата.<br />\nЛегенда: '''({{int:cur}})''' = разлика со последна преработка, '''({{int:last}})''' = разлика со претходна преработка, '''{{int:minoreditletter}}''' = ситна промена.",
-       "history-fieldset-title": "ФилÑ\82Ñ\80иÑ\80аÑ\98 преработки",
+       "history-fieldset-title": "ФилÑ\82Ñ\80иÑ\80аÑ\9aе Ð½Ð° преработки",
        "history-show-deleted": "Само избришани преработки",
        "histfirst": "најстари",
        "histlast": "најнови",
        "specialmute-error-invalid-user": "Не можев да го најдам корисничкото име.",
        "specialmute-error-email-blacklist-disabled": "Исклучувањето на е-пошта од корисници не е овозможено.",
        "specialmute-error-email-preferences": "Ќе мора да ја потврдите вашата е-пошта пред да исклучите известувања од други. Тоа се прави на страницата [[Special:Preferences]].",
-       "specialmute-email-footer": "[$1 Раководење со поставки за е-пошта од {{BIDI:$2}}.]",
+       "specialmute-email-footer": "За нагодување на поставките за {{BIDI:$2}}, појдете на <$1>.",
        "specialmute-login-required": "Најавете се за да ги направите промените.",
        "revid": "преработка $1",
        "pageid": "назнака на страницата $1",
index fdab3b7..19511ff 100644 (file)
        "template-protected": "(ߊ߬ ߡߊߞߊ߲ߞߊ߲ߣߍ߲߫ ߠߋ߬)",
        "template-semiprotected": "(ߟߊ߬ߞߊ߲߬ߘߊ߬ߟߌ-ߝߊ߲߬ߞߋ߬ߟߋ߲߬ߡߊ)",
        "hiddencategories": "ߞߐߜߍ ߣߌ߲߬ ߦߋ߫ ߢߌ߲߬ ߠߎ߫ ߛߌ߲߬ߝߏ߲ ߠߋ߬ ߘߌ߫{{PLURAL:$1|}}",
+       "nocreate-loggedin": "ߞߐߜߍ߫ ߞߎߘߊ߫ ߛߌ߲ߘߌ߫ ߞߏ ߟߊߘߌ߬ߢߍ߬ߣߍ߲߬ ߕߴߌ ߦߋ߫.",
        "sectioneditnotsupported-text": "ߛߌ߰ߘߊ ߡߊߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߠߊߘߤߊ߬ߣߍ߲߬ ߕߍ߫ ߞߐߜߍ ߣߌ߲߬ ߠߊ߫ ߕߊ߲߬.",
        "permissionserrors": "ߝߌ߬ߟߌ߫ ߘߌ߬ߢߍ߬ߒߧߋ",
        "permissionserrorstext": "ߌ ߟߊߘߌ߬ߢߍ߬ߣߍ߲߬ ߕߍ߫ ߞߵߏ߬ ߞߍ߫߸ ߣߌ߲߬ ߠߊ߫ {{PLURAL:$1|ߛߊߓߎ|ߛߊߓߎ ߟߎ߬}}:",
        "rcfilters-savedqueries-already-saved": "ߛߍ߲ߛߍ߲ߟߊ߲ ߣߌ߲߬ ߓߘߊ߫ ߓߊ߲߫ ߠߊߞߎ߲߬ߘߎ߬ ߟߊ߫.ߌ ߟߊ߫ ߟߊ߬ߓߍ߲߬ߢߐ߲߰ߡߊ ߡߊߝߊ߬ߟߋ߲߬ ߞߊ߬ ߛߍ߲ߛߍ߲ߟߊ߲߫ ߟߊߞߎ߲߬ߘߎ߬ߣߍ߲ ߘߏ߫ ߛߌ߲ߘߌ߫.",
        "rcfilters-clear-all-filters": "ߛߍ߲ߛߍ߲ߟߊ߲ ߓߍ߯ ߛߊߣߌ߲ߧߊ߫",
        "rcfilters-show-new-changes": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߎߘߊ ߟߎ߬ ߦߋ߫ ߞߊ߬ߦߌ߯ $1",
+       "rcfilters-invalid-filter": "ߛߍ߲ߛߍ߲ߟߊ߲ ߓߍ߲߬ߓߊߟߌ",
+       "rcfilters-filterlist-title": "ߛߍ߲ߛߍ߲ߟߊ߲",
        "rcfilters-filterlist-whatsthis": "ߣߌ߲߬ ߦߋ߫ ߓߊ߯ߙߊ߫ ߟߊ߫ ߘߌ߬؟",
+       "rcfilters-filterlist-feedbacklink": "ߌ ߤߊߞߟߌߣߊ߲ ߝߐ߫ ߊ߲ ߧߋ߫ ߞߊ߬ ߓߍ߲߬ ߛߍ߲ߛߍ߲ߟߊ߲ ߖߐ߯ߙߊ߲ ߠߊ߫ ߞߏ ߡߊ߬.",
        "rcfilters-highlightbutton-title": "ߞߐߝߟߌ߫ ߡߊߦߋߙߋ߲ߣߍ߲ ߠߎ߬",
        "rcfilters-highlightmenu-title": "ߞߐ߬ߟߐ ߘߏ߫ ߓߊߓߌ߬ߟߊ߬",
        "rcfilters-filter-editsbyself-label": "ߡߍ߲ ߠߎ߬ ߡߊߦߟߍ߬ߡߊ߲߬ߣߍ߲߬ ߌ ߓߟߏ߫",
        "rcfilters-filter-user-experience-level-unregistered-label": "ߕߐ߯ߛߓߍߓߊߟߌ",
        "rcfilters-filter-user-experience-level-unregistered-description": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߊ ߡߍ߲ ߜߊ߲߬ߞߎ߲߬ߣߍ߲߬ ߕߍ߫.",
        "rcfilters-filter-user-experience-level-learner-label": "ߞߊ߬ߙߊ߲߬ߠߊ ߟߎ߬",
+       "rcfilters-filter-user-experience-level-experienced-description": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ߬ ߕߐ߯ߛߓߍߣߍ߲ ߡߍ߲ ߠߊ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߓߘߊ߫ ߕߊ߬ߡߌ߲߬ ߅߀߀ ߞߊ߲߬ ߕߟߋ߬ ߃߀ ߓߊ߯ߙߊ߫ ߣߐ.",
        "rcfilters-filter-bots-label": "ߓߏߕ",
        "rcfilters-filter-bots-description": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߡߍ߲ ߠߎ߬ ߛߌ߲ߘߌߣߍ߲߫ ߞߍߒߖߘߍߦߋ߫ ߖߐ߯ߙߊ߲ ߠߎ߬ ߘߐ߫.",
        "rcfilters-filter-humans-label": "ߡߐ߱ (ߓߏߕ  ߕߍ߫)",
        "rcfilters-filter-humans-description": "ߡߐ߱ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߊ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ ߣߐ.",
        "rcfilters-filter-reviewstatus-unpatrolled-label": "ߓߍ߬ߙߍ߲߬ߓߍ߬ߙߍ߲߬ߓߊߟߌ",
        "rcfilters-filter-minor-label": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߘߋ߬ߣߍ߲ ߠߎ߬",
+       "rcfilters-filter-major-label": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߘߋ߬ߣߍ߲ ߕߍ߫",
+       "rcfilters-filter-major-description": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߕߍ߫ ߘߎ߲ߛߓߍߡߊ߫ ߘߋߣߍ߲ ߝߋ߲߫ ߘߌ߫.",
        "rcfilters-filtergroup-watchlist": "ߜߋ߬ߟߎ߲߬ߠߌ߲߬ ߛߙߍߘߍ ߞߐߜߍ ߟߎ߬",
        "rcfilters-filter-watchlist-watched-label": "ߜߋ߬ߟߎ߲߬ߠߌ߲߬ ߛߙߍߘߍ ߘߐ߫",
+       "rcfilters-filter-watchlist-watched-description": "ߊ߬ ߡߊߝߊ߬ߟߋ߲߬ ߌ ߟߊ߫ ߜߋ߬ߟߎ߲߬ߠߌ߲߬ ߛߙߍߘߍ ߞߐߜߍ ߟߎ߬ ߘߐ߫.",
+       "rcfilters-filter-watchlist-watchednew-label": "ߜߋ߬ߟߎ߲߬ߠߌ߲߬ ߛߙߍߘߍ߫ ߞߎߘߊ߫ ߓߘߊ߫ ߡߊߦߟߍ߬ߡߊ߲߫",
+       "rcfilters-filter-watchlist-notwatched-label": "ߊ߬ ߕߍ߫ ߜߋ߬ߟߎ߲߬ߠߌ߲߬ ߛߙߍߘߍ ߘߐ߫",
        "rcfilters-filtergroup-changetype": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߛߎ߯ߦߊ",
        "rcfilters-filter-pageedits-label": "ߞߐߜߐ ߡߊߦߟߍ߬ߡߊ߲߫",
        "rcfilters-filter-pageedits-description": "ߞߐߜߍ ߛߌ߲ߘߟߌ",
        "rcfilters-filter-newpages-label": "ߞߐߜߍ ߛߌ߲ߘߟߌ",
        "rcfilters-filter-newpages-description": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߡߍ߲ ߠߎ߬ ߦߋ߫ ߞߐߜߍ߫ ߞߎߘߊ߫ ߟߊߘߊ߲߫ ߠߊ߫.",
        "rcfilters-filter-categorization-label": "ߦߌߟߡߊ߫ ߡߊߦߟߍߡߊ߲",
+       "rcfilters-filtergroup-lastrevision": "ߡߊ߬ߛߊ߬ߦߌ߲߬ߠߌ߲ ߕߊ߬ߡߌ߲߬ߣߍ߲",
+       "rcfilters-filter-lastrevision-label": "ߡߊ߬ߛߊ߬ߦߌ߲߬ߠߌ߲ ߕߊ߬ߡߌ߲߬ߣߍ߲",
+       "rcfilters-filter-lastrevision-description": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߎ߲ߓߊ ߟߎ߬ ߘߐߙߐ߲߫ ߦߋ߫ ߞߍ߫ ߞߐߜߍ ߘߐ߫.",
+       "rcfilters-filter-previousrevision-label": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߐ߯ߟߕߊ ߝߋ߲߫ ߕߍ߫",
+       "rcfilters-filter-previousrevision-description": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߠߎ߬ ߓߍ߯ ߡߍ߲ ߠߎ߬ ߕߍ߫ \"ߟߢߊ߬ߟߌ߬ ߞߐ߯ߟߕߊ߫\" ߘߌ߫.",
+       "rcfilters-filter-excluded": "ߊ߬ ߓߘߊ߫ ߟߊߘߏ߲߬ ߊ߬ ߘߐ߫",
+       "rcfilters-tag-prefix-namespace-inverted": "<strong>:ߍ߲߬ߍ߲߫</strong> $1",
        "rcfilters-target-page-placeholder": "ߞߐߜߍ ߕߐ߮ ߟߊߘߏ߲߬ (ߥߟߊ߫ ߦߌߟߡߊ)",
        "rcnotefrom": "ߘߎ߰ߟߊ ߘߐ߫ {{PLURAL:$5|is the change|are the changes}} ߞߊ߬ߦߌ߯ <strong>$3, $4</strong> (up to <strong>$1</strong> shown).",
        "rclistfromreset": "ߞߐߜߍ ߓߊߕߐߡߐ߲ߠߌ߲ ߡߊߦߟߍ߬ߡߊ߲߫",
        "verification-error": "ߞߐߕߐ߮ ߣߌ߲߬ ߡߊ߫ ߕߊ߬ߡߌ߲߬ ߞߐߕߐ߮ ߝߛߍ߬ߝߛߍ߬ ߦߌߟߊ.",
        "hookaborted": "ߌ ߕߘߍ߬ ߦߋ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߡߍ߲ ߞߍ߫ ߞߏ ߘߐ߫߸ ߊ߬ ߘߐߛߊ߬ߣߍ߲߬ ߦߋ߫ ߘߐ߬ߥߙߊ߬ߟߌ ߟߋ߬ ߓߟߏ߫.",
        "illegal-filename": "ߞߐߕߐ߮ ߕߐ߮ ߟߊߘߌ߬ߢߍ߬ߣߍ߲߬ ߕߍ߫.",
+       "unknown-error": "ߝߎ߬ߕߎ߲߬ߕߌ߬ ߡߊߟߐ߲ߓߊߟߌ ߘߏ߫ ߓߘߊ߫ ߓߌ߬ߟߵߊ߬ ߘߐ߫.",
+       "tmp-create-error": "ߊ߬ ߕߍ߫ ߣߊ߬ ߥߊ߯ߕߌ߫ ߟߊߕߊߡߌ߲߫ ߞߐߕߐ߮ ߛߌ߲ߘߌ߫ ߟߊ߫.",
        "uploadwarning": "ߟߊ߬ߦߟߍ߬ߟߌ ߖߊ߬ߛߙߋ߬ߡߊ߬ߟߊ",
        "uploadwarning-text": "ߞߐߕߐ߮ ߘߎ߰ߟߊ߬ߘߐ߫ ߞߊ߲ߛߓߍߟߌ ߡߊ߬ߦߟߍ߬ߡߊ߲߫ ߖߊ߰ߣߌ߲߬߸ ߞߵߊ߬ ߡߊߝߍߣߍ߲߫ ߕߎ߲߯.",
        "savefile": "ߞߐߕߐ߮ ߟߊߞߎ߲߬ߘߎ߬",
        "upload-description": "ߞߐߕߐ߮ ߞߊ߲߬ߛߓߍߟߌ",
        "upload-options": "ߟߊ߬ߦߟߍ߬ߟߌ ߢߣߊߕߊߟߌ",
        "watchthisupload": "ߞߐߕߐ߮ ߣߌ߲߬ ߘߐߜߍ߫",
+       "upload-file-error": "ߞߣߐߟߊߘߐ߫ ߝߎߕߎ߲ߕߌ",
+       "upload-misc-error": "ߟߊ߬ߦߟߍ߬ߟߌ ߝߎ߬ߕߎ߲߬ߕߌ߬ ߡߊߟߐ߲ߓߊߟߌ",
+       "upload-misc-error-text": "ߝߎ߬ߕߎ߲߬ߕߌ߬ ߡߊߟߐ߲ߓߊߟߌ ߘߏ߫ ߓߘߊ߫ ߓߌ߬ߟߵߊ߬ ߘߐ߫ ߟߊ߬ߦߟߍ߬ߟߌ ߞߎ߲߬ߕߊ߮ ߞߘߐ߫. ߊ߬ ߝߛߍ߬ߝߛߍ߬ߟߌ ߞߍ߫ ߞߵߊ߬ ߟߐ߲߫ ߣߌ߫ URL ߓߍ߲߬ߣߍ߲߬ ߊ߬ ߣߴߊ߬ ߡߊߛߐ߬ߘߐ߲߬ߕߊ ߦߋ߫ ߞߣߊ߬ ߕߴߊ߬ ߡߊߝߍߣߍ߲߫ ߣߴߏ߬ ߞߐ߫.\nߣߌ߫ ߝߙߋߞߋ ߘߏ߲߬ ߠߊߝߛߊ߬ ߘߊ߫߸ ߓߌ߬ߟߊ߬ߢߐ߲߰ߡߊ ߢߌߣߌ߲߫ [[Special:ListUsers/sysop|administrator]] ߝߍ߬.",
+       "upload-http-error": "HTTP ߝߎ߬ߕߎ߲߬ߕߌ ߘߏ߫ ߓߘߊ߫ ߓߌ߬ߟߵߊ߬ ߘߐ߫: $1",
        "upload-dialog-title": "ߞߐߕߐ߮ ߟߊߦߟߍ߬",
        "upload-dialog-button-cancel": "ߊ߬ ߘߐߛߊ߬",
        "upload-dialog-button-back": "ߌ ߞߐߛߊ߬ߦߌ߬",
        "upload-form-label-own-work-message-generic-local": "ߒ ߧߴߊ߬ ߟߊߛߙߋߦߊ߫ ߟߊ߫ ߞߏ߫ ߒ ߧߋ߫ ߞߐߕߐ߮ ߣߌ߲߬ ߠߊߦߟߍ߬ ߞߊ߲߬ ߞߊ߬ ߓߍ߲߬ ߗߋߘߊ ߛߙߊߕߌ ߣߌ߫ ߕߌ߰ߦߊ ߤߊߞߍ ߡߊ߬ {{SITENAME}} ߞߊ߲߬",
        "backend-fail-delete": "ߞߐߕߐ߮ ߕߴߛߋ߫ ߖߏ߰ߛߌ߬ ߟߊ߫  \"$1\".",
        "backend-fail-describe": "ߡߋߕߊߘߕߊ ߞߐߕߐ߮ ߕߴߛߋ߫ ߡߊߦߟߍ߬ߡߊ߲߫ ߠߊ߫  \"$1\".",
+       "backend-fail-alreadyexists": "ߞߐߕߐ߮  \"$1\" ߦߋ߫ ߦߋ߲߬ ߞߘߐ߬ߡߊ߲߬.",
        "backend-fail-store": "ߞߐߕߐ߮  \"$1\" ߕߍ߫ ߛߐ߲߬ ߟߊߡߙߊ߬ ߟߊ߫ ߦߊ߲߬  \"$2\"",
        "backend-fail-copy": "ߊ߬ ߕߍ߫ ߣߊ߬ ߛߐ߲߬ ߠߊ߫ ߞߐߕߐ߮  \"$1\" ߓߊߦߟߍ߬ߡߊ߲߬ ߠߊ߫ ߦߊ߲߬  \"$2\".",
+       "backend-fail-move": "ߊ߬ ߕߍ߫ ߣߊ߬ ߛߐ߲߬ ߠߊ߫ ߞߐߕߐ߮  \"$1\" ߓߊߦߟߍ߬ߡߊ߲߬ ߠߊ߫ ߦߊ߲߬  \"$2\".",
+       "backend-fail-opentemp": "ߊ߬ ߕߍ߫ ߣߊ߬ ߥߊ߯ߕߌ߫ ߟߊߕߊߡߌ߲߫ ߞߐߕߐ߮ ߛߌ߲ߘߌ߫ ߟߊ߫.",
+       "backend-fail-writetemp": "ߊ߬ ߕߍ߫ ߣߊ߬ ߥߊ߯ߕߌ߫ ߟߊߕߊߡߌ߲߫ ߞߐߕߐ߮ ߛߓߍ߫ ߟߊ߫.",
+       "backend-fail-closetemp": "ߊ߬ ߕߍ߫ ߣߊ߬ ߥߊ߯ߕߌ߫ ߟߊߕߊߡߌ߲߫ ߞߐߕߐ߮ ߘߊߕߎ߲߯ ߠߊ߫.",
+       "backend-fail-read": "ߞߐߕߐ߮ ߕߴߛߋ߫ ߘߐߞߊ߬ߙߊ߲߬ ߠߊ߫   \"$1\".",
+       "backend-fail-create": "ߊ߬ ߕߍ߫ ߣߊ߬ ߛߐ߲߬ ߠߊ߫ ߞߐߕߐ߮  \"$1\" ߛߓߍ߫ ߟߊ߫.",
+       "backend-fail-maxsize": "ߊ߫ ߕߍ߫ ߣߊ߬ ߞߐߕߐ߮  \"$1\" ߛߓߍ߫ ߟߊ߫߸ ߓߊߏ߬ ߊ߬ ߓߏ߲߬ߓߊ߫ ߞߊ߬ ߕߊ߬ߡߌ߲߬ {{PLURAL:$2|ߝߙߐ߬ߢߐ߬ ߞߋߟߋ߲߫|ߝߙߐ߬ߢߐ ߟߎ߬ $2}}.",
        "img-auth-nofile": "ߞߐߕߐ߮  \"$1\" ߕߍ߫ ߦߋ߲߬.",
        "http-request-error": "HTTP ߡߊ߬ߢߌ߬ߣߌ߲߬ߠߌ߲ ߓߘߊ߫ ߗߌߙߏ߲߫ ߝߎ߬ߕߎ߲߬ߕߌ߬ ߡߊߟߐ߲ߓߊߟߌ ߘߏ߫ ߞߏߛߐ߲߬.",
        "http-read-error": "HTTP ߘߐ߬ߞߊ߬ߙߊ߲߬ߠߌ߲ ߝߎ߬ߕߎ߲߬ߕߌ.",
        "http-bad-status": "ߝߙߋߞߋ ߕߘߍ߬ ߦߋ߫ ߦߋ߲߬ HTTP ߡߊߢߌߣߌ߲ߠߌ߲: $1 $2 ߘߐ߫",
        "http-internal-error": "HTTP ߞߣߐߟߊ ߘߐ߫ ߝߎߕߎ߲ߕߌ.",
        "upload-curl-error6": "ߌ ߕߍ߫ ߣߊ߬ URL ߡߊߛߐ߬ߘߐ߲߬ ߠߊ߫",
+       "upload-curl-error28": "ߟߊ߬ߦߟߍ߬ߟߌ ߕߎ߬ߡߊ ߓߘߊ߫ ߕߊ߬ߡߌ߲߬",
        "license": "ߟߊ߬ߘߌ߬ߢߍ߬ߟߌ ߦߴߌ ߘߐ߫:",
        "license-header": "ߟߊ߬ߘߌ߬ߢߍ߬ߟߌ ߦߴߌ ߘߐ߫",
+       "nolicense": "ߊ߬ ߡߊ߫ ߓߊߕߐ߬ߡߐ߲߬",
+       "listfiles-delete": "ߊ߬ ߖߏ߬ߛߌ߬",
        "imgfile": "ߞߐߕߐ߮",
        "listfiles": "ߞߐߕߐ߮ ߛߙߍߘߍ",
+       "listfiles_thumb": "ߞߝߊ߬ߟߋ߲ߛߋ߲",
+       "listfiles_date": "ߕߎ߬ߡߊ߬ߘߊ",
+       "listfiles_name": "ߕߐ߮",
+       "listfiles_user": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ",
+       "listfiles_size": "ߢߊ߲ߞߊ߲",
+       "listfiles_description": "ߞߊ߲߬ߛߓߍߟߌ",
+       "listfiles_count": "ߦߌߟߡߊ",
+       "listfiles-latestversion-yes": "ߐ߲߬ߐ߲߬ߐ߲߫",
+       "listfiles-latestversion-no": "ߊ߬ߦߌ߫",
        "file-anchor-link": "ߞߐߕߐ߮",
        "filehist": "ߞߐߕߐ߮ ߟߊ߫ ߘߐ߬ߝߐ",
        "filehist-help": "ߕߎ߬ߡߊ߬ߘߊ/ߕߎ߬ߡߊ ߛߐ߲߬ߞߌ߲߬ ߓߊ߫߸ ߞߊ߬ ߕߎ߬ߡߊ߬ߘߊ ߞߐߕߐ߮ ߟߎ߬ ߦߋ߫.",
+       "filehist-deleteall": "ߊ߬ ߓߍ߯ ߖߏ߰ߛߌ߬",
+       "filehist-deleteone": "ߊ߬ ߖߏ߬ߛߌ߬",
        "filehist-revert": "ߊ߬ ߟߊߢߊ߬",
        "filehist-current": "ߞߍߛߊ߲ߞߏ",
        "filehist-datetime": "ߕߎ߬ߡߊ߬ߘߊ/ߕߎ߬ߡߊ߬ߟߊ߲",
        "filehist-nothumb": "ߖߌ߬ߦߊ߬ ߘߐ߯ߡߊ߲߫ ߕߴߦߋ߲߬",
        "filehist-user": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ",
        "filehist-dimensions": "ߛߎߡߊ߲ߘߐ",
+       "filehist-filesize": "ߞߐߕߐ߮ ߢߊ߲ߞߊ߲",
        "filehist-comment": "ߞߊ߲߬ߝߐߟߌ",
        "imagelinks": "ߞߐߕߐ߮ ߟߊߓߊ߯ߙߊߟߌ",
        "linkstoimage": "ߞߐߕߐ߮ ߣߌ߲߬ {{PLURAL:$1|ߞߐߜߍ ߟߎ߬|$1 ߞߐߜߍ ߟߎ߬}}:",
        "linkstoimage-redirect": "$1 (ߞߐߕߐ߯ ߟߊߞߎ߲߬ߛߌ߲߬ߣߍ߲߬) $2",
        "sharedupload-desc-here": "ߘߐ߬ߛߙߋ ߣߌ߲߬ ߦߋ߫ ߦߊ߲߬ ߠߋ߫ $1 ߖߊ߬ߕߋ߬ߘߐ߬ߛߌ߮ ߕߐ߭ ߟߎ߬ ߞߏ߬ߣߌ߲ ߘߌ߫ ߛߴߊ߬ ߟߊߓߊ߯ߙߊ߫ ߟߊ߫. ߊ߬ ߕߐ߯ ߛߓߍߟߌ ߦߙߐ [$2 ߞߐߕߐ߮ ߞߊ߲߬ߛߓߍߟߌ ߞߐߜߍ] ߟߋ߬ ߦߋ߫ ߘߎ߰ߟߊ ߘߐ߫ ߣߌ߲߬.",
        "filepage-nofile": "ߕߐ߮ ߣߌ߲߬ ߞߐߕߐ߯ ߛߎ߯ ߕߍ߫ ߦߋ߲߬",
+       "shared-repo-from": "ߞߊ߬ ߝߘߊ߫: $1",
        "upload-disallowed-here": "ߌ ߕߍߣߊ߬ ߞߐߜߍ ߣߌ߲߬ ߞߊ߲߬ߛߓߍ߫ ߟߊ߫.",
+       "filedelete": "ߖߏ߰ߛߌ߬ߟߌ $1",
+       "filedelete-legend": "ߞߐߕߐ߮ ߖߏ߰ߛߌ߬",
+       "unusedtemplateswlh": "ߛߘߌ߬ߜߋ߲ ߜߘߍ ߟߎ߬",
        "randompage": "ߞߎ߲߬ߝߍ߬ ߞߐߜߍ",
+       "randomincategory": "ߓߍ߲߬ߛߋ߲߬ߡߊ߬ ߞߐߜߍ ߦߌߟߡߊ ߘߐ߫",
+       "randomincategory-nopages": "ߞߐߜߍ߫ ߛߌ߫ ߕߍ߫  [[:Category:$1|$1]] ߘߌ߫ ߦߌߟߡߊ",
+       "randomincategory-category": "ߦߌߟߡߊ",
+       "randomincategory-legend": "ߓߍ߲߬ߛߋ߲߬ߡߊ߬ ߞߐߜߍ ߦߌߟߡߊ ߘߐ߫",
+       "randomincategory-submit": "ߕߊ߯",
+       "randomredirect": "ߓߍ߲߬ߛߋ߲߬ߡߊ߬ ߟߊߞߎ߲ߛߌ߲ߠߌ߲",
        "statistics": "ߖߊ߬ߕߋ߬ߛߎ߬ߓߐ ߟߎ߬",
+       "statistics-articles": "ߞߣߐߘߐ߫ ߞߐߜߍ",
+       "statistics-pages": "ߞߐߜߍ ߟߎ߬",
+       "statistics-pages-desc": "ߞߐߜߍ ߡߍ߲ ߓߍ߯ ߦߋ߫ ߥߞߌ ߞߊ߲߬߸ ߦߏ߫ ߞߎߡߊߢߐ߲߯ߦߊ߫ ߞߐߜߍ߸ ߟߊ߬ߞߎ߲߬ߛߌ߲߬ߠߌ߲߸ ߊ߬ ߣߌ߫.",
+       "statistics-files": "ߞߐߕߐ߮ ߟߊߦߟߍ߬ߣߍ߲ ߠߎ߬",
        "double-redirect-fixer": "ߟߊ߬ߞߎ߲߬ߛߌ߲߬ߠߌ߲ ߘߐߓߍ߲߬ߟߊ߲",
        "nbytes": "$1 {{PLURAL:$1|ߝߌ߬ߘߊ|ߝߌ߬ߘߊ߲ ߠߎ߬}}",
        "nmembers": "$1 {{PLURAL:$1|ߛߌ߲߬ߝߏ߲ |ߛߌ߲߬ߝߏ߲ ߠߎ߬}}",
index 639063b..e1635f4 100644 (file)
                        "Didifelisberto",
                        "Tks4Fish",
                        "Luig",
-                       "Piotrex43"
+                       "Piotrex43",
+                       "Waldyrious"
                ]
        },
        "tog-underline": "Ligação sublinhada:",
index f765ef4..0069197 100644 (file)
@@ -79,7 +79,8 @@
                        "Athena in Wonderland",
                        "Fitoschido",
                        "Ldacosta",
-                       "CaiusSPQR"
+                       "CaiusSPQR",
+                       "Waldyrious"
                ]
        },
        "tog-underline": "Sublinhar hiperligações:",
index 475365e..2d22536 100644 (file)
                        "Zoranzoki21",
                        "Woytecr",
                        "PiefPafPier",
-                       "Bagas Chrisara"
+                       "Bagas Chrisara",
+                       "Waldyrious"
                ]
        },
        "sidebar": "{{notranslate}}",
        "contributions": "Display name for the 'User contributions', shown in the sidebar menu of all user pages and user talk pages.\n\nAlso the page name of the target page.\n\nThe target page shows an overview of the most recent contributions by a user.\n\nParameters:\n* $1 - username\n\nSee also:\n* {{msg-mw|Contributions}}\n* {{msg-mw|Accesskey-t-contributions}}\n* {{msg-mw|Tooltip-t-contributions}}",
        "contributions-summary": "{{doc-specialpagesummary|contributions}}",
        "contributions-title": "{{Gender}}\nThe page title in your browser bar, but not the page title.\n\nParameters:\n* $1 - the username\nSee also:\n* {{msg-mw|Contributions}}",
-       "mycontris": "In the personal urls page section - right upper corner.\n\nSee also:\n* {{msg-mw|Mycontris}}\n* {{msg-mw|Accesskey-pt-mycontris}}\n* {{msg-mw|Tooltip-pt-mycontris}}\n{{Identical|Contribution}}",
+       "mycontris": "Link to the current user's own contributions, in the personal account links area, at the upper right corner of the page.\n\nSee also:\n* {{msg-mw|Mycontris}}\n* {{msg-mw|Accesskey-pt-mycontris}}\n* {{msg-mw|Tooltip-pt-mycontris}}\n{{Identical|Contribution}}",
        "anoncontribs": "Same as {{msg-mw|mycontris}} but used for non-logged-in users.\n\nSee also:\n* {{msg-mw|Accesskey-pt-anoncontribs}}\n* {{msg-mw|Tooltip-pt-anoncontribs}}\n{{Identical|Contribution}}",
        "contribsub2": "Contributions for \"user\" (links). Parameters:\n* $1 is an IP address or a username, with a link which points to the user page (if registered user).\n* $2 is list of tool links. The list contains a link which has text {{msg-mw|Sp-contributions-talk}}.\n* $3 is a plain text username used for GENDER.\n{{Identical|For $1}}",
        "contributions-subtitle": "Successor to {{msg-mw|contribsub2}}. Contributions for \"user\". Parameters:\n* $1 is an IP address or a username, with a link which points to the user page (if registered user).",
index 8cd4eac..fc1efcf 100644 (file)
        "specialmute-label-mute-email": "Отключить эл. почту от этого участника",
        "specialmute-header": "Пожалуйста, выберите настройки уведомлений от {{BIDI:[[User:$1]]}}.",
        "specialmute-error-invalid-user": "Указанное вами имя участника не может быть найдено.",
+       "specialmute-error-email-blacklist-disabled": "Не активирован функционал запрета участникам слать вам письма.",
        "specialmute-error-email-preferences": "Вы должны подтвердить вашу электронную почту, прежде чем отключить уведомление от других. Это можно сделать на странице [[Special:Preferences]].",
        "specialmute-email-footer": "Для управления настройками эл. почты для {{BIDI:$2}}, пожалуйста, посмотрите <$1>.",
        "specialmute-login-required": "Пожалуйста, войдите, чтобы совершить изменения.",
index ab3e9f5..9624db6 100644 (file)
        "recentchanges-label-minor": "Chistha è una mudìfigga minori",
        "recentchanges-label-bot": "Chistha è una mudìfigga pa unu bot",
        "recentchanges-label-unpatrolled": "Mudìfigga nò ancora contrulladda",
-       "recentchanges-label-plusminus": "A misura di la pàgina è isthadda ciambiadda di kisthu  innùmaru di byte",
+       "recentchanges-label-plusminus": "La misura di la pàgina è isthadda ciambiadda di chisthu  innùmaru di byte",
        "recentchanges-legend-heading": "<strong>Legenda:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (vedi puru [[Special:NewPages|lu listhinu di li pàgini nobi]])",
        "rcnotefrom": "Inogghi sottu {{PLURAL:$5|z'è la mudìfigga|zi sò li mudìfigghi}} a partì da <strong>$3, $4</strong> (màssimu <strong>$1</strong> ).",
        "whatlinkshere-hideredirs": "$1 rinvii",
        "whatlinkshere-hidetrans": "$1 incrusioni",
        "whatlinkshere-hidelinks": "$1 liadduri",
-       "whatlinkshere-hideimages": "$1 liadduri a file",
+       "whatlinkshere-hideimages": "$1 liadduri a ischedàriu",
        "whatlinkshere-filters": "Filthri",
        "blockip": "Brocca utenti",
        "ipaddressorusername": "Indirizzu IP o innòmu utenti:",
index c5791cb..4ea707f 100644 (file)
        "confirmable-no": "否",
        "thisisdeleted": "查看或还原$1?",
        "viewdeleted": "查看$1?",
-       "restorelink": "$1个已删除的编辑",
+       "restorelink": "$1个已删除的编辑",
        "feedlinks": "源:",
        "feed-invalid": "无效的订阅feed类型。",
        "feed-unavailable": "不提供联合feed",
        "systemblockedtext": "您的用户名或IP地址已被MediaWiki自动封禁。封禁原因:\n\n:<em>$2</em>\n\n* 开始时间:$8\n* 到期时间:$6\n* 目标用户:$7\n\n您当前的IP地址是$3。请在您做出的任何查询中包含所有上述详情。",
        "blockednoreason": "未给出原因",
        "blockedtext-composite": "您的用户名或IP地址已被封禁。封禁原因:\n\n:<em>$2</em>\n\n* 开始时间:$8\n* 到期时间:$6\n\n您当前的IP地址是$3。请在您做出的任何查询中包含所有上述详情。",
+       "blockedtext-composite-reason": "有多个封禁目标为您的账户和/或IP地址",
        "whitelistedittext": "请$1以编辑页面。",
        "confirmedittext": "您必须确认您的电子邮件地址才能编辑页面。请通过[[Special:Preferences|系统设置]]设置并确认您的电子邮件地址。",
        "nosuchsectiontitle": "没有这个段落",
        "prefs-help-watchlist-token2": "这是您的监视列表的网络feed密钥。任何拥有者均可以浏览您的监视列表,因此不要公开该密钥。如果有需要,[[Special:ResetTokens|您可以重置密钥]]。",
        "prefs-help-tokenmanagement": "您可以查看并重置您账户的密钥,它用来访问您监视列表的Web订阅源。任何知道密钥的人都将可以阅读您的监视列表,所以不要分享它。",
        "savedprefs": "您的系统设置已保存。",
-       "savedrights": "{{GENDER:$1|$1}}的用户组已保存。",
+       "savedrights": "{{GENDER:$1|$1}}的用户组已保存。",
        "timezonelegend": "时区:",
        "localtime": "当地时间:",
        "timezoneuseserverdefault": "使用wiki默认值($1)",
        "img-auth-nofile": "文件“$1”不存在。",
        "img-auth-isdir": "您正试图访问目录“$1”。您只能访问文件。",
        "img-auth-streaming": "流式化“$1”中。",
-       "img-auth-public": "img_auth.phpç\9a\84å\8a\9fè\83½æ\98¯ä»\8eé\9d\9eå\85¬å¼\80wikiè¾\93å\87ºæ\96\87件ã\80\82æ\9c¬wiki已被设置为å\85¬å¼\80ã\80\82为äº\86æ\9c\80ä½³å®\89å\85¨ç\8a¶å\86µï¼\8cimg_auth.phpå·²å\81\9cç\94¨ã\80\82",
+       "img-auth-public": "img_auth.php的功能是从非公开wiki输出文件。本wiki已设置为公开。为了最佳安全状况,img_auth.php已停用。",
        "img-auth-noread": "用户无权读取“$1”。",
        "http-invalid-url": "无效URL:$1",
        "http-invalid-scheme": "带“$1”方案的URL不受支持。",
        "undeleteinvert": "反向选择",
        "undeletecomment": "原因:",
        "cannotundelete": "部分或全部还原删除失败:$1",
-       "undeletedpage": "<strong>$1å·²ç»\8f被è¿\98å\8e\9f</strong>\n\næ\9c\80è¿\91ç\9a\84å\88 é\99¤å\92\8cè¿\98å\8e\9fè®°å½\95请è§\81[[Special:Log/delete|å\88 é\99¤æ\97¥å¿\97]]ã\80\82",
+       "undeletedpage": "<strong>$1已经还原</strong>\n\n最近的删除和还原记录请见[[Special:Log/delete|删除日志]]。",
        "undelete-header": "如要查询最近的记录请参阅[[Special:Log/delete|删除日志]]。",
        "undelete-search-title": "搜索已删除页面",
        "undelete-search-box": "搜索已删除页面",
        "unblockiptext": "使用下列表单来恢复之前被封禁的IP地址或用户名的写权限。",
        "ipusubmit": "解除此封禁",
        "unblocked": "[[User:$1|$1]]已经被解封",
-       "unblocked-range": "$1已被解å°\81",
+       "unblocked-range": "$1已解å°\81ã\80\82",
        "unblocked-id": "封禁$1已被解除",
        "unblocked-ip": "[[Special:Contributions/$1|$1]]已解封。",
        "blocklist": "被封禁用户",
        "anonymous": "{{SITENAME}}匿名{{PLURAL:$1|用户}}",
        "siteuser": "{{SITENAME}}用户$1",
        "anonuser": "{{SITENAME}}匿名用户$1",
-       "lastmodifiedatby": "本页面$3最后编辑于$1 $2。",
+       "lastmodifiedatby": "本页面$3最后编辑于$1 $2。",
        "othercontribs": "基于$1的劳动成果。",
        "others": "其他",
        "siteusers": "{{SITENAME}}{{PLURAL:$2|{{GENDER:$1|用户}}}}$1",
index 39d9be7..966c9d3 100644 (file)
        "history": "頁面歷史",
        "history_short": "歷史",
        "history_small": "歷史",
-       "updatedmarker": "è\87ªæ\88\91上次瀏覽之後的更新",
+       "updatedmarker": "è\87ªæ\82¨上次瀏覽之後的更新",
        "printableversion": "可列印版",
        "permalink": "靜態連結",
        "print": "列印",
        "restrictionsfield-help": "一個 IP 位址或 CIDR 範圍一行,要開啟所有範圍可使用:<pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "錯誤:$1",
        "edit-error-long": "錯誤:\n\n$1",
+       "specialmute-submit": "確認",
+       "specialmute-error-invalid-user": "無法找到請求的使用者名稱。",
        "revid": "修訂 $1",
        "pageid": "頁面 ID $1",
        "interfaceadmin-info": "$1\n\n編輯全站 CSS/JS/JSON 檔案的權限,近期已從 <code>editinterface</code> 權限裡拆分。若您不清楚為何會收到此錯誤,請查看 [[mw:MediaWiki_1.32/interface-admin]]。",
index 92b4fd4..f510329 100644 (file)
@@ -1365,6 +1365,7 @@ return [
        ],
        'mediawiki.action.edit.preview' => [
                'scripts' => 'resources/src/mediawiki.action/mediawiki.action.edit.preview.js',
+               'styles' => 'resources/src/mediawiki.action/mediawiki.action.edit.preview.css',
                'dependencies' => [
                        'jquery.spinner',
                        'jquery.textSelection',
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.preview.css b/resources/src/mediawiki.action/mediawiki.action.edit.preview.css
new file mode 100644 (file)
index 0000000..87030df
--- /dev/null
@@ -0,0 +1,7 @@
+.mw-preview-copyelements {
+       transition: opacity 200ms;
+}
+
+.mw-preview-copyelements-loading {
+       opacity: 0.4;
+}
index 3af8222..7f2dbdd 100644 (file)
                        $spinner.show();
                }
 
-               // Can't use fadeTo because it calls show(), and we might want to keep some elements hidden
-               // (e.g. empty #catlinks)
-               // FIXME: Use CSS transition
-               // eslint-disable-next-line no-jquery/no-animate
-               $copyElements.animate( { opacity: 0.4 }, 'fast' );
+               $copyElements.addClass( [ 'mw-preview-copyelements', 'mw-preview-copyelements-loading' ] );
 
                api = new mw.Api();
                postData = {
                        mw.hook( 'wikipage.editform' ).fire( $editform );
                } ).always( function () {
                        $spinner.hide();
-                       // FIXME: Use CSS transition
-                       // eslint-disable-next-line no-jquery/no-animate
-                       $copyElements.animate( {
-                               opacity: 1
-                       }, 'fast' );
+                       $copyElements.removeClass( 'mw-preview-copyelements-loading' );
                } ).fail( function ( code, result ) {
                        // This just shows the error for whatever request failed first
                        var errorMsg = 'API error: ' + code;
index 536de24..bba9d5a 100644 (file)
@@ -180,7 +180,13 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
        }
 
        public static function setUpBeforeClass() {
+               global $IP;
                parent::setUpBeforeClass();
+               if ( !file_exists( "$IP/LocalSettings.php" ) ) {
+                       echo 'A working MediaWiki installation with a configured LocalSettings.php file is'
+                       . ' required for tests that extend ' . self::class;
+                       die();
+               }
                self::initializeForStandardPhpunitEntrypointIfNeeded();
 
                // Get the original service locator
index 3ac69ae..acbb04a 100644 (file)
@@ -46,11 +46,9 @@ class ReleaseNotesTest extends MediaWikiTestCase {
                        "SECURITY",
                ];
 
-               $testCases = [];
                foreach ( $rootFiles as $rootFile ) {
-                       $testCases["$rootFile file"] = [ "$IP/$rootFile" ];
+                       yield "$rootFile file" => [ "$IP/$rootFile" ];
                }
-               return $testCases;
        }
 
        /**
@@ -82,9 +80,10 @@ class ReleaseNotesTest extends MediaWikiTestCase {
                        }
                        $errors[] = "line $num: length $length > $max_length:\n$line";
                }
-               # Using assertSame() to show the full line
+               # Use assertSame() instead of assertEqual(), to show the full line in the diff
                $this->assertSame(
-                       [], $errors,
+                       [],
+                       $errors,
                        "$type file '$fileName' lines " .
                        "have at most $max_length characters"
                );
index 9b021c4..4ffef02 100644 (file)
@@ -800,6 +800,65 @@ class TitleTest extends MediaWikiTestCase {
                        'Virtual namespace cannot have talk page' => [
                                Title::makeTitle( NS_MEDIA, 'Kitten.jpg' ), false
                        ],
+                       'Relative link has no talk page' => [
+                               Title::makeTitle( NS_MAIN, '', 'Kittens' ), false
+                       ],
+                       'Interwiki link has no talk page' => [
+                               Title::makeTitle( NS_MAIN, 'Kittens', '', 'acme' ), false
+                       ],
+               ];
+       }
+
+       public function provideIsWatchable() {
+               return [
+                       'User page is watchable' => [
+                               Title::makeTitle( NS_USER, 'Jane' ), true
+                       ],
+                       'Talke page is watchable' => [
+                               Title::makeTitle( NS_TALK, 'Foo' ), true
+                       ],
+                       'Special page is not watchable' => [
+                               Title::makeTitle( NS_SPECIAL, 'Thing' ), false
+                       ],
+                       'Virtual namespace is not watchable' => [
+                               Title::makeTitle( NS_MEDIA, 'Kitten.jpg' ), false
+                       ],
+                       'Relative link is not watchable' => [
+                               Title::makeTitle( NS_MAIN, '', 'Kittens' ), false
+                       ],
+                       'Interwiki link is not watchable' => [
+                               Title::makeTitle( NS_MAIN, 'Kittens', '', 'acme' ), false
+                       ],
+               ];
+       }
+
+       public static function provideGetTalkPage_good() {
+               return [
+                       [ Title::makeTitle( NS_MAIN, 'Test' ), Title::makeTitle( NS_TALK, 'Test' ) ],
+                       [ Title::makeTitle( NS_TALK, 'Test' ), Title::makeTitle( NS_TALK, 'Test' ) ],
+               ];
+       }
+
+       public static function provideGetTalkPage_bad() {
+               return [
+                       [ Title::makeTitle( NS_SPECIAL, 'Test' ) ],
+                       [ Title::makeTitle( NS_MEDIA, 'Test' ) ],
+                       [ Title::makeTitle( NS_MAIN, '', 'Kittens' ) ],
+                       [ Title::makeTitle( NS_MAIN, 'Kittens', '', 'acme' ) ],
+               ];
+       }
+
+       public static function provideGetSubjectPage_good() {
+               return [
+                       [ Title::makeTitle( NS_TALK, 'Test' ), Title::makeTitle( NS_MAIN, 'Test' ) ],
+                       [ Title::makeTitle( NS_MAIN, 'Test' ), Title::makeTitle( NS_MAIN, 'Test' ) ],
+               ];
+       }
+
+       public static function provideGetOtherPage_good() {
+               return [
+                       [ Title::makeTitle( NS_MAIN, 'Test' ), Title::makeTitle( NS_TALK, 'Test' ) ],
+                       [ Title::makeTitle( NS_TALK, 'Test' ), Title::makeTitle( NS_MAIN, 'Test' ) ],
                ];
        }
 
@@ -815,31 +874,44 @@ class TitleTest extends MediaWikiTestCase {
                $this->assertSame( $expected, $actual, $title->getPrefixedDBkey() );
        }
 
-       public static function provideGetTalkPage_good() {
-               return [
-                       [ Title::makeTitle( NS_MAIN, 'Test' ), Title::makeTitle( NS_TALK, 'Test' ) ],
-                       [ Title::makeTitle( NS_TALK, 'Test' ), Title::makeTitle( NS_TALK, 'Test' ) ],
-               ];
+       /**
+        * @dataProvider provideIsWatchable
+        * @covers Title::isWatchable
+        *
+        * @param Title $title
+        * @param bool $expected
+        */
+       public function testIsWatchable( Title $title, $expected ) {
+               $actual = $title->canHaveTalkPage();
+               $this->assertSame( $expected, $actual, $title->getPrefixedDBkey() );
        }
 
        /**
         * @dataProvider provideGetTalkPage_good
         * @covers Title::getTalkPageIfDefined
         */
-       public function testGetTalkPageIfDefined_good( Title $title ) {
-               $talk = $title->getTalkPageIfDefined();
-               $this->assertInstanceOf(
-                       Title::class,
-                       $talk,
-                       $title->getPrefixedDBKey()
-               );
+       public function testGetTalkPage_good( Title $title, Title $expected ) {
+               $actual = $title->getTalkPage();
+               $this->assertTrue( $expected->equals( $actual ), $title->getPrefixedDBkey() );
        }
 
-       public static function provideGetTalkPage_bad() {
-               return [
-                       [ Title::makeTitle( NS_SPECIAL, 'Test' ) ],
-                       [ Title::makeTitle( NS_MEDIA, 'Test' ) ],
-               ];
+       /**
+        * @dataProvider provideGetTalkPage_bad
+        * @covers Title::getTalkPageIfDefined
+        */
+       public function testGetTalkPage_bad( Title $title ) {
+               $this->setExpectedException( MWException::class );
+               $title->getTalkPage();
+       }
+
+       /**
+        * @dataProvider provideGetTalkPage_good
+        * @covers Title::getTalkPageIfDefined
+        */
+       public function testGetTalkPageIfDefined_good( Title $title, Title $expected ) {
+               $actual = $title->getTalkPageIfDefined();
+               $this->assertNotNull( $actual, $title->getPrefixedDBkey() );
+               $this->assertTrue( $expected->equals( $actual ), $title->getPrefixedDBkey() );
        }
 
        /**
@@ -850,10 +922,37 @@ class TitleTest extends MediaWikiTestCase {
                $talk = $title->getTalkPageIfDefined();
                $this->assertNull(
                        $talk,
-                       $title->getPrefixedDBKey()
+                       $title->getPrefixedDBkey()
                );
        }
 
+       /**
+        * @dataProvider provideGetSubjectPage_good
+        * @covers Title::getSubjectPage
+        */
+       public function testGetSubjectPage_good( Title $title, Title $expected ) {
+               $actual = $title->getSubjectPage();
+               $this->assertTrue( $expected->equals( $actual ), $title->getPrefixedDBkey() );
+       }
+
+       /**
+        * @dataProvider provideGetOtherPage_good
+        * @covers Title::getOtherPage
+        */
+       public function testGetOtherPage_good( Title $title, Title $expected ) {
+               $actual = $title->getOtherPage();
+               $this->assertTrue( $expected->equals( $actual ), $title->getPrefixedDBkey() );
+       }
+
+       /**
+        * @dataProvider provideGetTalkPage_bad
+        * @covers Title::getOtherPage
+        */
+       public function testGetOtherPage_bad( Title $title ) {
+               $this->setExpectedException( MWException::class );
+               $title->getOtherPage();
+       }
+
        public function provideCreateFragmentTitle() {
                return [
                        [ Title::makeTitle( NS_MAIN, 'Test' ), 'foo' ],
index f444d40..4bb9d5a 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use MediaWiki\User\UserIdentityValue;
+
 /**
  * @group Database
  */
@@ -214,6 +216,23 @@ class LogFormatterTest extends MediaWikiLangTestCase {
                $this->assertEquals( $expected, $logParam );
        }
 
+       /**
+        * @covers LogFormatter::newFromEntry
+        * @covers LogFormatter::getActionText
+        */
+       public function testLogParamsTypeUserLink_empty() {
+               $params = [ '4:user-link:userLink' => ':' ];
+
+               $entry = $this->newLogEntry( 'param', $params );
+               $formatter = LogFormatter::newFromEntry( $entry );
+
+               $this->context->setLanguage( Language::factory( 'qqx' ) );
+               $formatter->setContext( $this->context );
+
+               $logParam = $formatter->getActionText();
+               $this->assertContains( '(empty-username)', $logParam );
+       }
+
        /**
         * @covers LogFormatter::newFromEntry
         * @covers LogFormatter::getActionText
@@ -248,6 +267,20 @@ class LogFormatterTest extends MediaWikiLangTestCase {
                $this->assertEquals( $expected, $logParam );
        }
 
+       /**
+        * @covers LogFormatter::getPerformerElement
+        */
+       public function testGetPerformerElement() {
+               $entry = $this->newLogEntry( 'param', [] );
+               $entry->setPerformer( new UserIdentityValue( 1328435, 'Test', 0 ) );
+
+               $formatter = LogFormatter::newFromEntry( $entry );
+               $formatter->setContext( $this->context );
+
+               $element = $formatter->getPerformerElement();
+               $this->assertContains( 'User:Test', $element );
+       }
+
        /**
         * @covers LogFormatter::newFromEntry
         * @covers LogFormatter::getComment
index c630447..ef2f219 100644 (file)
@@ -1,9 +1,11 @@
 <?php
+use MediaWiki\MediaWikiServices;
+
 /**
  * @group Database
  * @covers CoreParserFunctions
  */
-class CoreParserFunctionsTest extends MediaWikiTestCase {
+class CoreParserFunctionsTest extends MediaWikiLangTestCase {
 
        public function testGender() {
                $user = User::createNew( '*Female' );
@@ -18,4 +20,56 @@ class CoreParserFunctionsTest extends MediaWikiTestCase {
                $this->assertEquals( $msg, 'f', 'Works escaped' );
        }
 
+       public function provideTalkpagename() {
+               yield [ 'Talk:Foo bar', 'foo_bar' ];
+               yield [ 'Talk:Foo', ' foo ' ];
+               yield [ 'Talk:Foo', 'Talk:Foo' ];
+               yield [ 'User talk:Foo', 'User:foo' ];
+               yield [ '', 'Special:Foo' ];
+               yield [ '', '' ];
+               yield [ '', ' ' ];
+               yield [ '', '__' ];
+               yield [ '', '#xyzzy' ];
+               yield [ '', '#' ];
+               yield [ '', ':' ];
+               yield [ '', ':#' ];
+               yield [ '', 'User:' ];
+               yield [ '', 'User:#' ];
+       }
+
+       /**
+        * @dataProvider provideTalkpagename
+        */
+       public function testTalkpagename( $expected, $title ) {
+               $parser = MediaWikiServices::getInstance()->getParser();
+
+               $this->assertSame( $expected, CoreParserFunctions::talkpagename( $parser, $title ) );
+       }
+
+       public function provideSubjectpagename() {
+               yield [ 'Foo bar', 'Talk:foo_bar' ];
+               yield [ 'Foo', ' Talk:foo ' ];
+               yield [ 'User:Foo', 'User talk:foo' ];
+               yield [ 'Special:Foo', 'Special:Foo' ];
+               yield [ '', '' ];
+               yield [ '', ' ' ];
+               yield [ '', '__' ];
+               yield [ '', '#xyzzy' ];
+               yield [ '', '#' ];
+               yield [ '', ':' ];
+               yield [ '', ':#' ];
+               yield [ '', 'Talk:' ];
+               yield [ '', 'User talk:#' ];
+               yield [ '', 'User:#' ];
+       }
+
+       /**
+        * @dataProvider provideTalkpagename
+        */
+       public function testSubjectpagename( $expected, $title ) {
+               $parser = MediaWikiServices::getInstance()->getParser();
+
+               $this->assertSame( $expected, CoreParserFunctions::talkpagename( $parser, $title ) );
+       }
+
 }
index 7eb8fd5..c1e258d 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 use MediaWiki\Config\ServiceOptions;
+use MediaWiki\Linker\LinkTarget;
 
 class NamespaceInfoTest extends MediaWikiTestCase {
        /**********************************************************************************************
@@ -688,73 +689,88 @@ class NamespaceInfoTest extends MediaWikiTestCase {
 
        /**
         * @dataProvider provideSpecialNamespaces
-        * @covers NamespaceInfo::getTalk
-        * @covers NamespaceInfo::getTalkPage
+        * @covers NamespaceInfo::getAssociated
         * @covers NamespaceInfo::isMethodValidFor
         *
         * @param int $ns
         */
-       public function testGetTalkPage_special( $ns ) {
-               $this->setExpectedException( MWException::class,
-                       "NamespaceInfo::getTalk does not make any sense for given namespace $ns" );
-               $this->newObj()->getTalkPage( new TitleValue( $ns, 'A' ) );
+       public function testGetAssociated_special( $ns ) {
+               $this->setExpectedException(
+                       MWException::class,
+                       "NamespaceInfo::getAssociated does not make any sense for given namespace $ns"
+               );
+               $this->newObj()->getAssociated( $ns );
+       }
+
+       public static function provideCanHaveTalkPage() {
+               return [
+                       [ new TitleValue( NS_MAIN, 'Test' ), true ],
+                       [ new TitleValue( NS_TALK, 'Test' ), true ],
+                       [ new TitleValue( NS_USER, 'Test' ), true ],
+                       [ new TitleValue( NS_SPECIAL, 'Test' ), false ],
+                       [ new TitleValue( NS_MEDIA, 'Test' ), false ],
+                       [ new TitleValue( NS_MAIN, '', 'Kittens' ), false ],
+                       [ new TitleValue( NS_MAIN, 'Kittens', '', 'acme' ), false ],
+               ];
        }
 
        /**
-        * @dataProvider provideSpecialNamespaces
-        * @covers NamespaceInfo::getTalk
-        * @covers NamespaceInfo::getTalkPage
-        * @covers NamespaceInfo::isMethodValidFor
-        * @covers Title::getTalkPage
-        *
-        * @param int $ns
+        * @dataProvider provideCanHaveTalkPage
+        * @covers NamespaceInfo::canHaveTalkPage
         */
-       public function testTitleGetTalkPage_special( $ns ) {
-               $this->setExpectedException( MWException::class,
-                       "NamespaceInfo::getTalk does not make any sense for given namespace $ns" );
-               Title::makeTitle( $ns, 'A' )->getTalkPage();
+       public function testCanHaveTalkPage( LinkTarget $t, $expected ) {
+               $actual = $this->newObj()->canHaveTalkPage( $t );
+               $this->assertEquals( $expected, $actual, $t->getDBkey() );
+       }
+
+       public static function provideGetTalkPage_good() {
+               return [
+                       [ new TitleValue( NS_MAIN, 'Test' ), new TitleValue( NS_TALK, 'Test' ) ],
+                       [ new TitleValue( NS_TALK, 'Test' ), new TitleValue( NS_TALK, 'Test' ) ],
+                       [ new TitleValue( NS_USER, 'Test' ), new TitleValue( NS_USER_TALK, 'Test' ) ],
+               ];
        }
 
        /**
-        * @dataProvider provideSpecialNamespaces
-        * @covers NamespaceInfo::getAssociated
+        * @dataProvider provideGetTalkPage_good
+        * @covers NamespaceInfo::getTalk
+        * @covers NamespaceInfo::getTalkPage
         * @covers NamespaceInfo::isMethodValidFor
-        *
-        * @param int $ns
         */
-       public function testGetAssociated_special( $ns ) {
-               $this->setExpectedException( MWException::class,
-                       "NamespaceInfo::getAssociated does not make any sense for given namespace $ns" );
-               $this->newObj()->getAssociated( $ns );
+       public function testGetTalkPage_good( LinkTarget $t, LinkTarget $expected ) {
+               $actual = $this->newObj()->getTalkPage( $t );
+               $this->assertEquals( $expected, $actual, $t->getDBkey() );
+       }
+
+       public static function provideGetTalkPage_bad() {
+               return [
+                       [ new TitleValue( NS_SPECIAL, 'Test' ) ],
+                       [ new TitleValue( NS_MEDIA, 'Test' ) ],
+                       [ new TitleValue( NS_MAIN, '', 'Kittens' ) ],
+                       [ new TitleValue( NS_MAIN, 'Kittens', '', 'acme' ) ],
+               ];
        }
 
        /**
-        * @dataProvider provideSpecialNamespaces
-        * @covers NamespaceInfo::getAssociated
-        * @covers NamespaceInfo::getAssociatedPage
+        * @dataProvider provideGetTalkPage_bad
+        * @covers NamespaceInfo::getTalk
+        * @covers NamespaceInfo::getTalkPage
         * @covers NamespaceInfo::isMethodValidFor
-        *
-        * @param int $ns
         */
-       public function testGetAssociatedPage_special( $ns ) {
-               $this->setExpectedException( MWException::class,
-                       "NamespaceInfo::getAssociated does not make any sense for given namespace $ns" );
-               $this->newObj()->getAssociatedPage( new TitleValue( $ns, 'A' ) );
+       public function testGetTalkPage_bad( LinkTarget $t ) {
+               $this->setExpectedException( MWException::class );
+               $this->newObj()->getTalkPage( $t );
        }
 
        /**
-        * @dataProvider provideSpecialNamespaces
+        * @dataProvider provideGetTalkPage_bad
         * @covers NamespaceInfo::getAssociated
         * @covers NamespaceInfo::getAssociatedPage
         * @covers NamespaceInfo::isMethodValidFor
-        * @covers Title::getOtherPage
-        *
-        * @param int $ns
         */
-       public function testTitleGetOtherPage_special( $ns ) {
-               $this->setExpectedException( MWException::class,
-                       "NamespaceInfo::getAssociated does not make any sense for given namespace $ns" );
-               Title::makeTitle( $ns, 'A' )->getOtherPage();
+       public function testGetAssociatedPage_bad( LinkTarget $t ) {
+               $this->setExpectedException( MWException::class );
+               $this->newObj()->getAssociatedPage( $t );
        }
 
        /**