Merge "Unset weird ancient WMF-specific shared upload settings"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Mon, 22 Aug 2016 17:46:17 +0000 (17:46 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 22 Aug 2016 17:46:17 +0000 (17:46 +0000)
31 files changed:
autoload.php
docs/database.txt
includes/MWTimestamp.php
includes/api/i18n/ja.json
includes/db/Database.php
includes/db/loadbalancer/LBFactory.php
includes/db/loadbalancer/LoadBalancer.php
includes/debug/MWDebug.php
includes/filebackend/lockmanager/DBLockManager.php
includes/filebackend/lockmanager/MySqlLockManager.php [new file with mode: 0644]
includes/filebackend/lockmanager/PostgreSqlLockManager.php [new file with mode: 0644]
includes/htmlform/HTMLFormElement.php [new file with mode: 0644]
includes/htmlform/HTMLFormField.php
includes/specials/SpecialExport.php
languages/i18n/azb.json
languages/i18n/fr.json
languages/i18n/hr.json
languages/i18n/ilo.json
languages/i18n/jv.json
languages/i18n/lb.json
languages/i18n/nb.json
languages/i18n/nn.json
languages/i18n/sah.json
languages/i18n/ur.json
languages/i18n/zh-hant.json
resources/Resources.php
resources/src/jquery/jquery.makeCollapsible.js
resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.less
resources/src/mediawiki/htmlform/autoinfuse.js
resources/src/mediawiki/htmlform/hide-if.js
resources/src/mediawiki/htmlform/htmlform.Element.js [new file with mode: 0644]

index e37a011..330ebc4 100644 (file)
@@ -527,8 +527,11 @@ $wgAutoloadLocalClasses = [
        'HTMLFileCache' => __DIR__ . '/includes/cache/HTMLFileCache.php',
        'HTMLFloatField' => __DIR__ . '/includes/htmlform/fields/HTMLFloatField.php',
        'HTMLForm' => __DIR__ . '/includes/htmlform/HTMLForm.php',
+       'HTMLFormActionFieldLayout' => __DIR__ . '/includes/htmlform/HTMLFormElement.php',
+       'HTMLFormElement' => __DIR__ . '/includes/htmlform/HTMLFormElement.php',
        'HTMLFormField' => __DIR__ . '/includes/htmlform/HTMLFormField.php',
        'HTMLFormFieldCloner' => __DIR__ . '/includes/htmlform/fields/HTMLFormFieldCloner.php',
+       'HTMLFormFieldLayout' => __DIR__ . '/includes/htmlform/HTMLFormElement.php',
        'HTMLFormFieldRequiredOptionsException' => __DIR__ . '/includes/htmlform/HTMLFormFieldRequiredOptionsException.php',
        'HTMLFormFieldWithButton' => __DIR__ . '/includes/htmlform/fields/HTMLFormFieldWithButton.php',
        'HTMLHiddenField' => __DIR__ . '/includes/htmlform/fields/HTMLHiddenField.php',
@@ -950,7 +953,7 @@ $wgAutoloadLocalClasses = [
        'MwSql' => __DIR__ . '/maintenance/sql.php',
        'MySQLField' => __DIR__ . '/includes/db/DatabaseMysqlBase.php',
        'MySQLMasterPos' => __DIR__ . '/includes/db/DatabaseMysqlBase.php',
-       'MySqlLockManager' => __DIR__ . '/includes/filebackend/lockmanager/DBLockManager.php',
+       'MySqlLockManager' => __DIR__ . '/includes/filebackend/lockmanager/MySqlLockManager.php',
        'MysqlInstaller' => __DIR__ . '/includes/installer/MysqlInstaller.php',
        'MysqlUpdater' => __DIR__ . '/includes/installer/MysqlUpdater.php',
        'NaiveForeignTitleFactory' => __DIR__ . '/includes/title/NaiveForeignTitleFactory.php',
@@ -1058,7 +1061,7 @@ $wgAutoloadLocalClasses = [
        'PopulateRecentChangesSource' => __DIR__ . '/maintenance/populateRecentChangesSource.php',
        'PopulateRevisionLength' => __DIR__ . '/maintenance/populateRevisionLength.php',
        'PopulateRevisionSha1' => __DIR__ . '/maintenance/populateRevisionSha1.php',
-       'PostgreSqlLockManager' => __DIR__ . '/includes/filebackend/lockmanager/DBLockManager.php',
+       'PostgreSqlLockManager' => __DIR__ . '/includes/filebackend/lockmanager/PostgreSqlLockManager.php',
        'PostgresBlob' => __DIR__ . '/includes/db/DatabasePostgres.php',
        'PostgresField' => __DIR__ . '/includes/db/DatabasePostgres.php',
        'PostgresInstaller' => __DIR__ . '/includes/installer/PostgresInstaller.php',
index ba3045e..44ec764 100644 (file)
@@ -8,7 +8,7 @@ By Tim Starling, January 2006.
 For information about the MediaWiki database layout, such as a 
 description of the tables and their contents, please see:
   https://www.mediawiki.org/wiki/Manual:Database_layout
-  https://gerrit.wikimedia.org/r/gitweb?p=mediawiki/core.git;a=blob_plain;f=maintenance/tables.sql;hb=HEAD
+  https://phabricator.wikimedia.org/diffusion/MW/browse/master/maintenance/tables.sql
 
 
 ------------------------------------------------------------------------
index 4964fe6..defdc96 100644 (file)
@@ -56,10 +56,14 @@ class MWTimestamp {
         *
         * @since 1.20
         *
-        * @param bool|string|int|float $timestamp Timestamp to set, or false for current time
+        * @param bool|string|int|float|DateTime $timestamp Timestamp to set, or false for current time
         */
        public function __construct( $timestamp = false ) {
-               $this->setTimestamp( $timestamp );
+               if ( $timestamp instanceof DateTime ) {
+                       $this->timestamp = $timestamp;
+               } else {
+                       $this->setTimestamp( $timestamp );
+               }
        }
 
        /**
index 2712c13..d3ef0e4 100644 (file)
@@ -8,7 +8,8 @@
                        "Mfuji",
                        "Otokoume",
                        "Sujiniku",
-                       "Macofe"
+                       "Macofe",
+                       "Suchichi02"
                ]
        },
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|説明文書]]\n* [[mw:API:FAQ|よくある質問]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api メーリングリスト]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API 告知]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R バグの報告とリクエスト]\n</div>\n<strong>状態:</strong> このページに表示されている機能は全て動作するはずですが、この API は未だ活発に開発されており、変更される可能性があります。アップデートの通知を受け取るには、[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce メーリングリスト]に参加してください。\n\n<strong>誤ったリクエスト:</strong> 誤ったリクエストが API に送られた場合、\"MediaWiki-API-Error\" HTTP ヘッダーが送信され、そのヘッダーの値と送り返されるエラーコードは同じ値にセットされます。より詳しい情報は [[mw:API:Errors_and_warnings|API: Errors and warnings]] を参照してください。\n\n<strong>テスト:</strong> API のリクエストのテストは、[[Special:ApiSandbox]]で簡単に行えます。",
        "apihelp-query+watchlist-param-prop": "追加で取得するプロパティ:",
        "apihelp-query+watchlist-paramvalue-prop-ids": "版IDとページIDを追加します。",
        "apihelp-query+watchlist-paramvalue-prop-title": "ページ名を追加します。",
+       "apihelp-query+watchlist-paramvalue-prop-flags": "編集のフラグを追加します。",
        "apihelp-query+watchlist-paramvalue-prop-comment": "編集のコメントを追加します。",
        "apihelp-query+watchlist-paramvalue-prop-parsedcomment": "編集の構文解析されたコメントを追加します。",
        "apihelp-query+watchlist-paramvalue-prop-timestamp": "編集のタイムスタンプを追加します。",
index 528a298..186a87b 100644 (file)
@@ -849,8 +849,6 @@ abstract class DatabaseBase implements IDatabase {
                        wfDebugLog( 'queries', sprintf( "%s: %s", $this->mDBname, $commentedSql ) );
                }
 
-               $queryId = MWDebug::query( $sql, $fname, $isMaster );
-
                # Avoid fatals if close() was called
                $this->assertOpen();
 
@@ -862,7 +860,7 @@ abstract class DatabaseBase implements IDatabase {
                $this->getTransactionProfiler()->recordQueryCompletion(
                        $queryProf, $startTime, $isWriteQuery, $this->affectedRows() );
 
-               MWDebug::queryTime( $queryId );
+               MWDebug::query( $sql, $fname, $isMaster, $queryRuntime );
 
                # Try reconnecting if the connection was lost
                if ( false === $ret && $this->wasErrorReissuable() ) {
@@ -2559,7 +2557,7 @@ abstract class DatabaseBase implements IDatabase {
 
                $autoTrx = $this->getFlag( DBO_TRX ); // automatic begin() enabled?
                /** @var Exception $e */
-               $e = $ePrior = null; // last exception
+               $e = null; // first exception
                do { // callbacks may add callbacks :)
                        $callbacks = array_merge(
                                $this->mTrxIdleCallbacks,
@@ -2577,11 +2575,9 @@ abstract class DatabaseBase implements IDatabase {
                                        } else {
                                                $this->clearFlag( DBO_TRX ); // restore auto-commit
                                        }
-                               } catch ( Exception $e ) {
-                                       if ( $ePrior ) {
-                                               MWExceptionHandler::logException( $ePrior );
-                                       }
-                                       $ePrior = $e;
+                               } catch ( Exception $ex ) {
+                                       MWExceptionHandler::logException( $ex );
+                                       $e = $e ?: $ex;
                                        // Some callbacks may use startAtomic/endAtomic, so make sure
                                        // their transactions are ended so other callbacks don't fail
                                        if ( $this->trxLevel() ) {
@@ -2592,7 +2588,7 @@ abstract class DatabaseBase implements IDatabase {
                } while ( count( $this->mTrxIdleCallbacks ) );
 
                if ( $e instanceof Exception ) {
-                       throw $e; // re-throw any last exception
+                       throw $e; // re-throw any first exception
                }
        }
 
@@ -2602,9 +2598,10 @@ abstract class DatabaseBase implements IDatabase {
         * This method should not be used outside of Database/LoadBalancer
         *
         * @since 1.22
+        * @throws Exception
         */
        public function runOnTransactionPreCommitCallbacks() {
-               $e = $ePrior = null; // last exception
+               $e = null; // first exception
                do { // callbacks may add callbacks :)
                        $callbacks = $this->mTrxPreCommitCallbacks;
                        $this->mTrxPreCommitCallbacks = []; // consumed (and recursion guard)
@@ -2612,17 +2609,15 @@ abstract class DatabaseBase implements IDatabase {
                                try {
                                        list( $phpCallback ) = $callback;
                                        call_user_func( $phpCallback );
-                               } catch ( Exception $e ) {
-                                       if ( $ePrior ) {
-                                               MWExceptionHandler::logException( $ePrior );
-                                       }
-                                       $ePrior = $e;
+                               } catch ( Exception $ex ) {
+                                       MWExceptionHandler::logException( $ex );
+                                       $e = $e ?: $ex;
                                }
                        }
                } while ( count( $this->mTrxPreCommitCallbacks ) );
 
                if ( $e instanceof Exception ) {
-                       throw $e; // re-throw any last exception
+                       throw $e; // re-throw any first exception
                }
        }
 
index efc6148..b320544 100644 (file)
@@ -234,6 +234,7 @@ abstract class LBFactory implements DestructibleService {
         * @param string $fname Caller name
         * @param array $options Options map:
         *   - maxWriteDuration: abort if more than this much time was spent in write queries
+        * @throws Exception
         */
        public function commitMasterChanges( $fname = __METHOD__, array $options = [] ) {
                // Perform all pre-commit callbacks, aborting on failure
@@ -245,9 +246,18 @@ abstract class LBFactory implements DestructibleService {
                // Actually perform the commit on all master DB connections
                $this->forEachLBCallMethod( 'commitMasterChanges', [ $fname ] );
                // Run all post-commit callbacks
-               $this->forEachLBCallMethod( 'runMasterPostCommitCallbacks' );
+               /** @var Exception $e */
+               $e = null; // first callback exception
+               $this->forEachLB( function ( LoadBalancer $lb ) use ( &$e ) {
+                       $ex = $lb->runMasterPostCommitCallbacks();
+                       $e = $e ?: $ex;
+               } );
                // Commit any dangling DBO_TRX transactions from callbacks on one DB to another DB
                $this->forEachLBCallMethod( 'commitMasterChanges', [ $fname ] );
+               // Throw any last post-commit callback error
+               if ( $e instanceof Exception ) {
+                       throw $e;
+               }
        }
 
        /**
index 93ec037..f045acf 100644 (file)
@@ -1125,13 +1125,21 @@ class LoadBalancer {
 
        /**
         * Issue all pending post-commit callbacks
+        * @return Exception|null The first exception or null if there were none
         * @since 1.28
         */
        public function runMasterPostCommitCallbacks() {
-               $this->forEachOpenMasterConnection( function ( DatabaseBase $db ) {
+               $e = null; // first exception
+               $this->forEachOpenMasterConnection( function ( DatabaseBase $db ) use ( &$e ) {
                        $db->setPostCommitCallbackSupression( false );
-                       $db->runOnTransactionIdleCallbacks( IDatabase::TRIGGER_COMMIT );
+                       try {
+                               $db->runOnTransactionIdleCallbacks( IDatabase::TRIGGER_COMMIT );
+                       } catch ( Exception $ex ) {
+                               $e = $e ?: $ex;
+                       }
                } );
+
+               return $e;
        }
 
        /**
index d90ef8a..6ce5829 100644 (file)
@@ -347,10 +347,11 @@ class MWDebug {
         * @param string $sql
         * @param string $function
         * @param bool $isMaster
+        * @param float $runTime Query run time
         * @return int ID number of the query to pass to queryTime or -1 if the
         *  debugger is disabled
         */
-       public static function query( $sql, $function, $isMaster ) {
+       public static function query( $sql, $function, $isMaster, $runTime ) {
                if ( !self::$enabled ) {
                        return -1;
                }
@@ -384,28 +385,12 @@ class MWDebug {
                        'sql' => $sql,
                        'function' => $function,
                        'master' => (bool)$isMaster,
-                       'time' => 0.0,
-                       '_start' => microtime( true ),
+                       'time' => $runTime,
                ];
 
                return count( self::$query ) - 1;
        }
 
-       /**
-        * Calculates how long a query took.
-        *
-        * @since 1.19
-        * @param int $id
-        */
-       public static function queryTime( $id ) {
-               if ( $id === -1 || !self::$enabled ) {
-                       return;
-               }
-
-               self::$query[$id]['time'] = microtime( true ) - self::$query[$id]['_start'];
-               unset( self::$query[$id]['_start'] );
-       }
-
        /**
         * Returns a list of files included, along with their size
         *
index c9aad43..0aefbfa 100644 (file)
@@ -239,205 +239,3 @@ abstract class DBLockManager extends QuorumLockManager {
                }
        }
 }
-
-/**
- * MySQL version of DBLockManager that supports shared locks.
- *
- * All lock servers must have the innodb table defined in locking/filelocks.sql.
- * All locks are non-blocking, which avoids deadlocks.
- *
- * @ingroup LockManager
- */
-class MySqlLockManager extends DBLockManager {
-       /** @var array Mapping of lock types to the type actually used */
-       protected $lockTypeMap = [
-               self::LOCK_SH => self::LOCK_SH,
-               self::LOCK_UW => self::LOCK_SH,
-               self::LOCK_EX => self::LOCK_EX
-       ];
-
-       protected function getLocalLB() {
-               // Use a separate connection so releaseAllLocks() doesn't rollback the main trx
-               return wfGetLBFactory()->newMainLB( $this->domain );
-       }
-
-       protected function initConnection( $lockDb, IDatabase $db ) {
-               # Let this transaction see lock rows from other transactions
-               $db->query( "SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;" );
-       }
-
-       /**
-        * Get a connection to a lock DB and acquire locks on $paths.
-        * This does not use GET_LOCK() per http://bugs.mysql.com/bug.php?id=1118.
-        *
-        * @see DBLockManager::getLocksOnServer()
-        * @param string $lockSrv
-        * @param array $paths
-        * @param string $type
-        * @return Status
-        */
-       protected function doGetLocksOnServer( $lockSrv, array $paths, $type ) {
-               $status = Status::newGood();
-
-               $db = $this->getConnection( $lockSrv ); // checked in isServerUp()
-
-               $keys = []; // list of hash keys for the paths
-               $data = []; // list of rows to insert
-               $checkEXKeys = []; // list of hash keys that this has no EX lock on
-               # Build up values for INSERT clause
-               foreach ( $paths as $path ) {
-                       $key = $this->sha1Base36Absolute( $path );
-                       $keys[] = $key;
-                       $data[] = [ 'fls_key' => $key, 'fls_session' => $this->session ];
-                       if ( !isset( $this->locksHeld[$path][self::LOCK_EX] ) ) {
-                               $checkEXKeys[] = $key;
-                       }
-               }
-
-               # Block new writers (both EX and SH locks leave entries here)...
-               $db->insert( 'filelocks_shared', $data, __METHOD__, [ 'IGNORE' ] );
-               # Actually do the locking queries...
-               if ( $type == self::LOCK_SH ) { // reader locks
-                       $blocked = false;
-                       # Bail if there are any existing writers...
-                       if ( count( $checkEXKeys ) ) {
-                               $blocked = $db->selectField( 'filelocks_exclusive', '1',
-                                       [ 'fle_key' => $checkEXKeys ],
-                                       __METHOD__
-                               );
-                       }
-                       # Other prospective writers that haven't yet updated filelocks_exclusive
-                       # will recheck filelocks_shared after doing so and bail due to this entry.
-               } else { // writer locks
-                       $encSession = $db->addQuotes( $this->session );
-                       # Bail if there are any existing writers...
-                       # This may detect readers, but the safe check for them is below.
-                       # Note: if two writers come at the same time, both bail :)
-                       $blocked = $db->selectField( 'filelocks_shared', '1',
-                               [ 'fls_key' => $keys, "fls_session != $encSession" ],
-                               __METHOD__
-                       );
-                       if ( !$blocked ) {
-                               # Build up values for INSERT clause
-                               $data = [];
-                               foreach ( $keys as $key ) {
-                                       $data[] = [ 'fle_key' => $key ];
-                               }
-                               # Block new readers/writers...
-                               $db->insert( 'filelocks_exclusive', $data, __METHOD__ );
-                               # Bail if there are any existing readers...
-                               $blocked = $db->selectField( 'filelocks_shared', '1',
-                                       [ 'fls_key' => $keys, "fls_session != $encSession" ],
-                                       __METHOD__
-                               );
-                       }
-               }
-
-               if ( $blocked ) {
-                       foreach ( $paths as $path ) {
-                               $status->fatal( 'lockmanager-fail-acquirelock', $path );
-                       }
-               }
-
-               return $status;
-       }
-
-       /**
-        * @see QuorumLockManager::releaseAllLocks()
-        * @return Status
-        */
-       protected function releaseAllLocks() {
-               $status = Status::newGood();
-
-               foreach ( $this->conns as $lockDb => $db ) {
-                       if ( $db->trxLevel() ) { // in transaction
-                               try {
-                                       $db->rollback( __METHOD__ ); // finish transaction and kill any rows
-                               } catch ( DBError $e ) {
-                                       $status->fatal( 'lockmanager-fail-db-release', $lockDb );
-                               }
-                       }
-               }
-
-               return $status;
-       }
-}
-
-/**
- * PostgreSQL version of DBLockManager that supports shared locks.
- * All locks are non-blocking, which avoids deadlocks.
- *
- * @ingroup LockManager
- */
-class PostgreSqlLockManager extends DBLockManager {
-       /** @var array Mapping of lock types to the type actually used */
-       protected $lockTypeMap = [
-               self::LOCK_SH => self::LOCK_SH,
-               self::LOCK_UW => self::LOCK_SH,
-               self::LOCK_EX => self::LOCK_EX
-       ];
-
-       protected function doGetLocksOnServer( $lockSrv, array $paths, $type ) {
-               $status = Status::newGood();
-               if ( !count( $paths ) ) {
-                       return $status; // nothing to lock
-               }
-
-               $db = $this->getConnection( $lockSrv ); // checked in isServerUp()
-               $bigints = array_unique( array_map(
-                       function ( $key ) {
-                               return Wikimedia\base_convert( substr( $key, 0, 15 ), 16, 10 );
-                       },
-                       array_map( [ $this, 'sha1Base16Absolute' ], $paths )
-               ) );
-
-               // Try to acquire all the locks...
-               $fields = [];
-               foreach ( $bigints as $bigint ) {
-                       $fields[] = ( $type == self::LOCK_SH )
-                               ? "pg_try_advisory_lock_shared({$db->addQuotes( $bigint )}) AS K$bigint"
-                               : "pg_try_advisory_lock({$db->addQuotes( $bigint )}) AS K$bigint";
-               }
-               $res = $db->query( 'SELECT ' . implode( ', ', $fields ), __METHOD__ );
-               $row = $res->fetchRow();
-
-               if ( in_array( 'f', $row ) ) {
-                       // Release any acquired locks if some could not be acquired...
-                       $fields = [];
-                       foreach ( $row as $kbigint => $ok ) {
-                               if ( $ok === 't' ) { // locked
-                                       $bigint = substr( $kbigint, 1 ); // strip off the "K"
-                                       $fields[] = ( $type == self::LOCK_SH )
-                                               ? "pg_advisory_unlock_shared({$db->addQuotes( $bigint )})"
-                                               : "pg_advisory_unlock({$db->addQuotes( $bigint )})";
-                               }
-                       }
-                       if ( count( $fields ) ) {
-                               $db->query( 'SELECT ' . implode( ', ', $fields ), __METHOD__ );
-                       }
-                       foreach ( $paths as $path ) {
-                               $status->fatal( 'lockmanager-fail-acquirelock', $path );
-                       }
-               }
-
-               return $status;
-       }
-
-       /**
-        * @see QuorumLockManager::releaseAllLocks()
-        * @return Status
-        */
-       protected function releaseAllLocks() {
-               $status = Status::newGood();
-
-               foreach ( $this->conns as $lockDb => $db ) {
-                       try {
-                               $db->query( "SELECT pg_advisory_unlock_all()", __METHOD__ );
-                       } catch ( DBError $e ) {
-                               $status->fatal( 'lockmanager-fail-db-release', $lockDb );
-                       }
-               }
-
-               return $status;
-       }
-}
diff --git a/includes/filebackend/lockmanager/MySqlLockManager.php b/includes/filebackend/lockmanager/MySqlLockManager.php
new file mode 100644 (file)
index 0000000..c51df16
--- /dev/null
@@ -0,0 +1,123 @@
+<?php
+/**
+ * MySQL version of DBLockManager that supports shared locks.
+ *
+ * All lock servers must have the innodb table defined in locking/filelocks.sql.
+ * All locks are non-blocking, which avoids deadlocks.
+ *
+ * @ingroup LockManager
+ */
+class MySqlLockManager extends DBLockManager {
+       /** @var array Mapping of lock types to the type actually used */
+       protected $lockTypeMap = [
+               self::LOCK_SH => self::LOCK_SH,
+               self::LOCK_UW => self::LOCK_SH,
+               self::LOCK_EX => self::LOCK_EX
+       ];
+
+       protected function getLocalLB() {
+               // Use a separate connection so releaseAllLocks() doesn't rollback the main trx
+               return wfGetLBFactory()->newMainLB( $this->domain );
+       }
+
+       protected function initConnection( $lockDb, IDatabase $db ) {
+               # Let this transaction see lock rows from other transactions
+               $db->query( "SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;" );
+       }
+
+       /**
+        * Get a connection to a lock DB and acquire locks on $paths.
+        * This does not use GET_LOCK() per http://bugs.mysql.com/bug.php?id=1118.
+        *
+        * @see DBLockManager::getLocksOnServer()
+        * @param string $lockSrv
+        * @param array $paths
+        * @param string $type
+        * @return Status
+        */
+       protected function doGetLocksOnServer( $lockSrv, array $paths, $type ) {
+               $status = Status::newGood();
+
+               $db = $this->getConnection( $lockSrv ); // checked in isServerUp()
+
+               $keys = []; // list of hash keys for the paths
+               $data = []; // list of rows to insert
+               $checkEXKeys = []; // list of hash keys that this has no EX lock on
+               # Build up values for INSERT clause
+               foreach ( $paths as $path ) {
+                       $key = $this->sha1Base36Absolute( $path );
+                       $keys[] = $key;
+                       $data[] = [ 'fls_key' => $key, 'fls_session' => $this->session ];
+                       if ( !isset( $this->locksHeld[$path][self::LOCK_EX] ) ) {
+                               $checkEXKeys[] = $key;
+                       }
+               }
+
+               # Block new writers (both EX and SH locks leave entries here)...
+               $db->insert( 'filelocks_shared', $data, __METHOD__, [ 'IGNORE' ] );
+               # Actually do the locking queries...
+               if ( $type == self::LOCK_SH ) { // reader locks
+                       $blocked = false;
+                       # Bail if there are any existing writers...
+                       if ( count( $checkEXKeys ) ) {
+                               $blocked = $db->selectField( 'filelocks_exclusive', '1',
+                                       [ 'fle_key' => $checkEXKeys ],
+                                       __METHOD__
+                               );
+                       }
+                       # Other prospective writers that haven't yet updated filelocks_exclusive
+                       # will recheck filelocks_shared after doing so and bail due to this entry.
+               } else { // writer locks
+                       $encSession = $db->addQuotes( $this->session );
+                       # Bail if there are any existing writers...
+                       # This may detect readers, but the safe check for them is below.
+                       # Note: if two writers come at the same time, both bail :)
+                       $blocked = $db->selectField( 'filelocks_shared', '1',
+                               [ 'fls_key' => $keys, "fls_session != $encSession" ],
+                               __METHOD__
+                       );
+                       if ( !$blocked ) {
+                               # Build up values for INSERT clause
+                               $data = [];
+                               foreach ( $keys as $key ) {
+                                       $data[] = [ 'fle_key' => $key ];
+                               }
+                               # Block new readers/writers...
+                               $db->insert( 'filelocks_exclusive', $data, __METHOD__ );
+                               # Bail if there are any existing readers...
+                               $blocked = $db->selectField( 'filelocks_shared', '1',
+                                       [ 'fls_key' => $keys, "fls_session != $encSession" ],
+                                       __METHOD__
+                               );
+                       }
+               }
+
+               if ( $blocked ) {
+                       foreach ( $paths as $path ) {
+                               $status->fatal( 'lockmanager-fail-acquirelock', $path );
+                       }
+               }
+
+               return $status;
+       }
+
+       /**
+        * @see QuorumLockManager::releaseAllLocks()
+        * @return Status
+        */
+       protected function releaseAllLocks() {
+               $status = Status::newGood();
+
+               foreach ( $this->conns as $lockDb => $db ) {
+                       if ( $db->trxLevel() ) { // in transaction
+                               try {
+                                       $db->rollback( __METHOD__ ); // finish transaction and kill any rows
+                               } catch ( DBError $e ) {
+                                       $status->fatal( 'lockmanager-fail-db-release', $lockDb );
+                               }
+                       }
+               }
+
+               return $status;
+       }
+}
diff --git a/includes/filebackend/lockmanager/PostgreSqlLockManager.php b/includes/filebackend/lockmanager/PostgreSqlLockManager.php
new file mode 100644 (file)
index 0000000..d55b5ae
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+/**
+ * PostgreSQL version of DBLockManager that supports shared locks.
+ * All locks are non-blocking, which avoids deadlocks.
+ *
+ * @ingroup LockManager
+ */
+class PostgreSqlLockManager extends DBLockManager {
+       /** @var array Mapping of lock types to the type actually used */
+       protected $lockTypeMap = [
+               self::LOCK_SH => self::LOCK_SH,
+               self::LOCK_UW => self::LOCK_SH,
+               self::LOCK_EX => self::LOCK_EX
+       ];
+
+       protected function doGetLocksOnServer( $lockSrv, array $paths, $type ) {
+               $status = Status::newGood();
+               if ( !count( $paths ) ) {
+                       return $status; // nothing to lock
+               }
+
+               $db = $this->getConnection( $lockSrv ); // checked in isServerUp()
+               $bigints = array_unique( array_map(
+                       function ( $key ) {
+                               return Wikimedia\base_convert( substr( $key, 0, 15 ), 16, 10 );
+                       },
+                       array_map( [ $this, 'sha1Base16Absolute' ], $paths )
+               ) );
+
+               // Try to acquire all the locks...
+               $fields = [];
+               foreach ( $bigints as $bigint ) {
+                       $fields[] = ( $type == self::LOCK_SH )
+                               ? "pg_try_advisory_lock_shared({$db->addQuotes( $bigint )}) AS K$bigint"
+                               : "pg_try_advisory_lock({$db->addQuotes( $bigint )}) AS K$bigint";
+               }
+               $res = $db->query( 'SELECT ' . implode( ', ', $fields ), __METHOD__ );
+               $row = $res->fetchRow();
+
+               if ( in_array( 'f', $row ) ) {
+                       // Release any acquired locks if some could not be acquired...
+                       $fields = [];
+                       foreach ( $row as $kbigint => $ok ) {
+                               if ( $ok === 't' ) { // locked
+                                       $bigint = substr( $kbigint, 1 ); // strip off the "K"
+                                       $fields[] = ( $type == self::LOCK_SH )
+                                               ? "pg_advisory_unlock_shared({$db->addQuotes( $bigint )})"
+                                               : "pg_advisory_unlock({$db->addQuotes( $bigint )})";
+                               }
+                       }
+                       if ( count( $fields ) ) {
+                               $db->query( 'SELECT ' . implode( ', ', $fields ), __METHOD__ );
+                       }
+                       foreach ( $paths as $path ) {
+                               $status->fatal( 'lockmanager-fail-acquirelock', $path );
+                       }
+               }
+
+               return $status;
+       }
+
+       /**
+        * @see QuorumLockManager::releaseAllLocks()
+        * @return Status
+        */
+       protected function releaseAllLocks() {
+               $status = Status::newGood();
+
+               foreach ( $this->conns as $lockDb => $db ) {
+                       try {
+                               $db->query( "SELECT pg_advisory_unlock_all()", __METHOD__ );
+                       } catch ( DBError $e ) {
+                               $status->fatal( 'lockmanager-fail-db-release', $lockDb );
+                       }
+               }
+
+               return $status;
+       }
+}
diff --git a/includes/htmlform/HTMLFormElement.php b/includes/htmlform/HTMLFormElement.php
new file mode 100644 (file)
index 0000000..e553218
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * Allows custom data specific to HTMLFormField to be set for OOjs UI forms. A matching JS widget
+ * (defined in htmlform.Element.js) picks up the extra config when constructed using OO.ui.infuse().
+ *
+ * Currently only supports passing 'hide-if' data.
+ */
+trait HTMLFormElement {
+
+       protected $hideIf = null;
+
+       public function initializeHTMLFormElement( array $config = [] ) {
+               // Properties
+               $this->hideIf = isset( $config['hideIf'] ) ? $config['hideIf'] : null;
+
+               // Initialization
+               if ( $this->hideIf ) {
+                       $this->addClasses( [ 'mw-htmlform-hide-if' ] );
+               }
+               $this->registerConfigCallback( function( &$config ) {
+                       if ( $this->hideIf !== null ) {
+                               $config['hideIf'] = $this->hideIf;
+                       }
+               } );
+       }
+}
+
+class HTMLFormFieldLayout extends OOUI\FieldLayout {
+       use HTMLFormElement;
+
+       public function __construct( $fieldWidget, array $config = [] ) {
+               // Parent constructor
+               parent::__construct( $fieldWidget, $config );
+               // Traits
+               $this->initializeHTMLFormElement( $config );
+       }
+
+       protected function getJavaScriptClassName() {
+               return 'mw.htmlform.FieldLayout';
+       }
+}
+
+class HTMLFormActionFieldLayout extends OOUI\ActionFieldLayout {
+       use HTMLFormElement;
+
+       public function __construct( $fieldWidget, $buttonWidget = false, array $config = [] ) {
+               // Parent constructor
+               parent::__construct( $fieldWidget, $buttonWidget, $config );
+               // Traits
+               $this->initializeHTMLFormElement( $config );
+       }
+
+       protected function getJavaScriptClassName() {
+               return 'mw.htmlform.ActionFieldLayout';
+       }
+}
index b47bfa0..3319d3b 100644 (file)
@@ -627,7 +627,7 @@ abstract class HTMLFormField {
                ];
 
                if ( $infusable && $this->shouldInfuseOOUI() ) {
-                       $this->mParent->getOutput()->addModules( 'oojs-ui-core' );
+                       $this->mParent->getOutput()->addModules( 'mediawiki.htmlform.ooui' );
                        $config['classes'][] = 'mw-htmlform-field-autoinfuse';
                }
 
@@ -637,6 +637,11 @@ abstract class HTMLFormField {
                        $config['label'] = new OOUI\HtmlSnippet( $label );
                }
 
+               if ( $this->mHideIf ) {
+                       $this->mParent->getOutput()->addModules( 'mediawiki.htmlform.ooui' );
+                       $config['hideIf'] = $this->mHideIf;
+               }
+
                return $this->getFieldLayoutOOUI( $inputField, $config );
        }
 
@@ -655,9 +660,9 @@ abstract class HTMLFormField {
        protected function getFieldLayoutOOUI( $inputField, $config ) {
                if ( isset( $this->mClassWithButton ) ) {
                        $buttonWidget = $this->mClassWithButton->getInputOOUI( '' );
-                       return new OOUI\ActionFieldLayout( $inputField, $buttonWidget, $config );
+                       return new HTMLFormActionFieldLayout( $inputField, $buttonWidget, $config );
                }
-               return new OOUI\FieldLayout( $inputField, $config );
+               return new HTMLFormFieldLayout( $inputField, $config );
        }
 
        /**
index 3e66ab0..fe97739 100644 (file)
@@ -201,6 +201,7 @@ class SpecialExport extends SpecialPage {
                                'buttontype' => 'submit',
                                'buttonname' => 'addcat',
                                'buttondefault' => $this->msg( 'export-addcat' )->text(),
+                               'hide-if' => [ '===', 'exportall', '1' ],
                        ],
                ];
                if ( $config->get( 'ExportFromNamespaces' ) ) {
@@ -216,6 +217,7 @@ class SpecialExport extends SpecialPage {
                                        'buttontype' => 'submit',
                                        'buttonname' => 'addns',
                                        'buttondefault' => $this->msg( 'export-addns' )->text(),
+                                       'hide-if' => [ '===', 'exportall', '1' ],
                                ],
                        ];
                }
@@ -240,6 +242,7 @@ class SpecialExport extends SpecialPage {
                                'nodata' => true,
                                'rows' => 10,
                                'default' => $page,
+                               'hide-if' => [ '===', 'exportall', '1' ],
                        ],
                ];
 
index c2a09db..1a537ce 100644 (file)
        "tooltip-undo": "ائدیلمیش ديَیشیکلیگی گئری قايتار و گئری قايتارما سببینی قئيد ائتمک اۆچون سێناق گؤستریشینی آچ",
        "tooltip-preferences-save": "ترجیحلری ساخلا",
        "tooltip-summary": "قیسا بیر خولاصه‌‌ یازین",
-       "anonymous": "{{SITENAME}} Ø³Ø§Û\8cتÛ\8cÙ\86Û\8cÙ\86 Ø¢Ù\86Ù\88Ù\86Û\8cÙ\85 {{PLURAL:$1|Û\8cستÛ\8cÙ\81ادÚ\86Û\8cسÛ\8c\8cستÛ\8cÙ\81ادÙ\87â\80\8cÚ\86Û\8câ\80\8cلری}}",
+       "anonymous": "{{SITENAME}} Ø³Ø§Û\8cتÛ\8cÙ\86Û\8cÙ\86 ØªØ§Ù\86Û\8cÙ\86Ù\85اÙ\85Û\8cØ´ {{PLURAL:$1|Û\8cØ´Ù\84دÙ\86\8cØ´Ù\84دÙ\86لری}}",
        "siteuser": "{{SITENAME}} ایستیفاده‌چی‌سی $1",
-       "anonuser": "{{SITENAME}} Ø¢Ù\86Ù\88Ù\86Û\8cÙ\85 Ø§Û\8cستÛ\8cÙ\81ادÙ\87â\80\8cÚ\86Û\8câ\80\8cسÛ\8c $1",
+       "anonuser": "{{SITENAME}} Ø¢Ù\86Ù\88Ù\86Û\8cÙ\85 Ø§Û\8cØ´Ù\84دÙ\86 $1",
        "lastmodifiedatby": "بۇ صحیفه‌‌ سوْنونجو دفعه‌‌ $1، $2 تاریخینده دَییشیلیب.",
        "othercontribs": "$1-این ایشینه اساسلانیب.",
        "others": "آیریلار",
index 5aef77a..55d067f 100644 (file)
        "listgrouprights-key": "Légende :\n*<span class=\"listgrouprights-granted\">Droit octroyé</span>\n*<span class=\"listgrouprights-revoked\">Droit révoqué</span>",
        "listgrouprights-group": "Groupe",
        "listgrouprights-rights": "Droits associés",
-       "listgrouprights-helppage": "Help:Droits des groupes",
+       "listgrouprights-helppage": "Help:Droits de groupes",
        "listgrouprights-members": "(liste des membres)",
        "listgrouprights-addgroup": "Ajouter des membres {{PLURAL:$2|au groupe|aux groupes}} : $1",
        "listgrouprights-removegroup": "Retirer des membres {{PLURAL:$2|du groupe|des groupes}} : $1",
        "trackingcategories-desc": "Critère d’inclusion de la catégorie",
        "restricted-displaytitle-ignored": "Pages avec des titres d'affichage ignorés",
        "restricted-displaytitle-ignored-desc": "La page a un <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> ignoré parce qu'il n'est pas équivalent au titre actuel de la page.",
-       "noindex-category-desc": "La page contient <code><nowiki>__NOINDEX__</nowiki></code> et est dans un espace de noms où ce marquage est autorisé ; elle ne sera donc pas indexée par les robots.",
-       "index-category-desc": "La page contient <code><nowiki>__INDEX__</nowiki></code> et est dans un espace de noms où ce marquage est autorisé ; elle sera donc indexée par les robots alors qu’elle ne l’aurait pas été normalement.",
+       "noindex-category-desc": "La page n'est pas indexée par les robots car elle contient le mot magique <code><nowiki>__NOINDEX__</nowiki></code> et se trouve dans un espace de noms où ce marquage est autorisé.",
+       "index-category-desc": "La page contient <code><nowiki>__INDEX__</nowiki></code> (et est dans un espace de noms où ce marquage est autorisé), et  sera donc indexée par les robots alors qu’elle ne l’aurait pas été normalement.",
        "post-expand-template-inclusion-category-desc": "La taille de la page dépasse <code>$wgMaxArticleSize</code> après le développement de tous ses modèles ; certains n’ont donc pas été développés.",
        "post-expand-template-argument-category-desc": "La page dépasse <code>$wgMaxArticleSize</code> après avoir développé l’argument d’un modèle (quelque chose entre accolades triples, comme <code>{{{Foo}}}</code>).",
        "expensive-parserfunction-category-desc": "La page utilise trop de fonctions coûteuses de l’analyseur (comme <code>#ifexist</code>). Voyez [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Manual:$wgExpensiveParserFunctionLimit].",
        "broken-file-category-desc": "La page contient un lien de fichier incorrect (un lien pour inclure un fichier alors que celui-ci n’existe pas).",
-       "hidden-category-category-desc": "La catégorie contient <code><nowiki>__HIDDENCAT__</nowiki></code> dans son contenu, ce qui empêche son affichage dans la zone des liens de catégorie sur les pages, par défaut.",
+       "hidden-category-category-desc": "La catégorie contient <code><nowiki>__HIDDENCAT__</nowiki></code> dans son contenu, ce qui empêche son affichage dans la zone des liens de catégorie sur les pages par défaut.",
        "trackingcategories-nodesc": "Aucune description disponible.",
        "trackingcategories-disabled": "La catégorie est désactivée",
        "mailnologin": "Pas d'adresse d'expéditeur",
-       "mailnologintext": "Vous devez être [[Special:UserLogin|identifié]] et avoir indiqué une adresse électronique valide dans vos [[Special:Preferences|préférences]] pour pouvoir envoyer des courriels à d'autres utilisateurs.",
+       "mailnologintext": "Vous devez être [[Special:UserLogin|connecté]] et avoir indiqué une adresse électronique valide dans vos [[Special:Preferences|préférences]] pour pouvoir envoyer des courriels à d'autres utilisateurs.",
        "emailuser": "Lui envoyer un courriel",
        "emailuser-title-target": "Envoyer un courriel à {{GENDER:$1|cet utilisateur|cette utilisatrice}}",
        "emailuser-title-notarget": "Envoyer un courriel à l'utilisateur",
index e4b81bf..ef1b90a 100644 (file)
        "blockedtext": "'''Vaše suradničko ime ili IP adresa je blokirana'''\n\nBlokirao Vas je $1.\nRazlog blokiranja je sljedeći: ''$2''.\n\n* Početak blokade: $8\n* Istek blokade: $6\n* Ime blokiranog suradnika: $7\n\nMožete kontaktirati $1 ili jednog od [[{{MediaWiki:Grouppage-sysop}}|administratora]] kako bi Vam pojasnili razlog blokiranja.\n\nPrimijetite da ne možete koristiti opciju \"Pošalji mu e-poruku\" ako niste upisali valjanu adresu e-pošte u Vašim [[Special:Preferences|suradničkim postavkama]] i ako niste u tome onemogućeni prilikom blokiranja.\n\nVaša trenutačna IP adresa je $3, a oznaka bloka #$5. Molimo navedite ovaj broj kod svakog upita vezano za razlog blokiranja.",
        "autoblockedtext": "Vaša IP adresa automatski je blokirana zbog toga što ju je koristio drugi suradnik, kojeg je blokirao $1.\nRazlog blokiranja je sljedeći:\n\n:''$2''\n\n* Početak blokade: $8\n* Blokada istječe: $6\n* Ime blokiranog suradnika: $7\n\nMožete kontaktirati $1 ili jednog od [[{{MediaWiki:Grouppage-sysop}}|administratora]] kako bi Vam pojasnili razlog blokiranja.\n\nPrimijetite da ne možete rabiti opciju \"Pošalji mu e-poruku\" ako niste upisali valjanu adresu e-pošte u Vašim [[Special:Preferences|suradničkim postavkama]] i ako niste u tome onemogućeni prilikom blokiranja.\n\nVaša trenutačna IP adresa je $3, a oznaka bloka #$5. Molimo navedite ovaj broj kod svakog upita vezano za razlog blokiranja.",
        "blockednoreason": "bez obrazloženja",
-       "whitelistedittext": "Za uređivanje stranice morate se $1.",
+       "whitelistedittext": "Za uređivanje stranice molimo $1.",
        "confirmedittext": "Morate potvrditi Vašu adresu e-pošte prije nego što Vam bude omogućeno uređivanje. Molim unesite i ovjerite Vašu adresu e-pošte u [[Special:Preferences|suradničkim postavkama]].",
        "nosuchsectiontitle": "Ne mogu pronaći odlomak",
        "nosuchsectiontext": "Pokušali ste uređivati odlomak koji ne postoji.\nMožda je premješten ili izbrisan dok ste pregledavali stranicu.",
        "loginreqtitle": "Nužna prijava",
        "loginreqlink": "prijavite se",
-       "loginreqpagetext": "Morate se $1 da biste vidjeli ostale stranice.",
+       "loginreqpagetext": "Da biste vidjeli ostale stranice, molimo $1.",
        "accmailtitle": "Lozinka poslana.",
        "accmailtext": "Nova lozinka za [[User talk:$1|$1]] je poslana na $2.\n\nNakon prijave, lozinka za ovaj novi račun može biti promijenjena na stranici ''[[Special:ChangePassword|promijeni lozinku]]'' nakon prijave.",
        "newarticle": "(Novo)",
        "reuploaddesc": "Vratite se u obrazac za postavljanje.",
        "upload-tryagain": "Pošalji izmijenjeni opis datoteke",
        "uploadnologin": "Niste prijavljeni",
-       "uploadnologintext": "Za postavljanje datoteka morate biti $1.",
+       "uploadnologintext": "Da biste postavljali datoteke, molimo $1.",
        "upload_directory_missing": "Mapa za datoteke ($1) nedostaje i webserver ju ne može napraviti.",
        "upload_directory_read_only": "Server ne može pisati u direktorij za postavljanje ($1).",
        "uploaderror": "Pogreška kod postavljanja",
index 9a6228a..0cca8aa 100644 (file)
@@ -27,6 +27,7 @@
        "tog-watchdefault": "Agnayon kadagiti panid ken papeles nga inurnosko iti listaan ti bambantayak",
        "tog-watchmoves": "Agnayon kadagiti panid ken papeles nga inyalisko iti listaan ti bambantayak",
        "tog-watchdeletion": "Agnayon kadagiti panid ken papeles nga inikkatko iti listaan ti bambantayak",
+       "tog-watchuploads": "Inayon dagiti baro a papeles iti bambantayak",
        "tog-watchrollback": "Agnayon kadagiti panid nga adda inramidko nga insubli iti bambantayak",
        "tog-minordefault": "Markaan amin dagiti inurnos a kas bassit babaen ti kasisigud",
        "tog-previewontop": "Ipakita ti panagipadas sakbay ti pagurnosan a kahon",
@@ -51,7 +52,7 @@
        "tog-ccmeonemails": "Patulodandak kadagiti kopia ti esurat nga ipatulodko kadagiti sabali nga agar-aramat",
        "tog-diffonly": "Saan nga iparang ti linaon ti panid dita baba dagiti pagiddiatan",
        "tog-showhiddencats": "Ipakita dagiti nailemmeng a kategoria",
-       "tog-norollbackdiff": "Laksiden ti paggiddiatan kalpasan ti panagaramid ti panagisubli",
+       "tog-norollbackdiff": "Saan nga ipakita ti paggiddiatan kalpasan ti panagaramid ti panagisubli",
        "tog-useeditwarning": "Pakaunaannak no pumanawak iti maysa pagurnosan a panid nga addaan iti saan a naidulin a sinuksukatan",
        "tog-prefershttps": "Kankanayon nga agusar ti natalged a koneksion no nakastrek",
        "underline-always": "Kanayon",
        "logentry-protect-protect-cascade": "{{GENDER:$2|Sinalakniban}} ni $1 ti $3 $4 [sariap]",
        "logentry-protect-modify": "{{GENDER:$2|Binaliwan}} ni $1 ti agpang ti salaknib para iti $3 $4",
        "logentry-protect-modify-cascade": "{{GENDER:$2|Binaliwan}} ni $1 ti agpang ti salaknib para iti $3 $4 [sariap]",
-       "logentry-rights-rights": "Ni $1 ket {{GENDER:$2|binaliwanna}} ti grupo a pannakaikameng para kenni $3 manipud ti $4 iti $5",
+       "logentry-rights-rights": "Ni $1 ket {{GENDER:$2|binaliwanna}} ti grupo a pannakaikameng para kenni {{GENDER:$6|$3}} manipud iti $4 iti $5",
        "logentry-rights-rights-legacy": "Ni $1 ket {{GENDER:$2|binaliwanna}} ti grupo a pannakaikameng para kenni $3",
        "logentry-rights-autopromote": "Ni $1 ket automatiko idi a {{GENDER:$2|naipangato}} manipud ti $4 iti $5",
        "logentry-upload-upload": "Ni $1 ket {{GENDER:$2|inkargana}} ti $3",
        "searchsuggest-containing": "naglaon ti...",
        "api-error-badaccess-groups": "Saanka mapalubosan nga agikarga kadagiti papeles iti daytoy a wiki.",
        "api-error-badtoken": "Akin-uneg a biddut: Dakes a tandaan.",
+       "api-error-blocked": "Naserraankan manipud iti panagurnos.",
        "api-error-copyuploaddisabled": "Ti panagikarga babaen ti URL ket nabaldado iti daytoy server.",
        "api-error-duplicate": "Adda {{PLURAL:$1|sabali a papeles|dagiti sabali a papeles}} nga addan iti daytoy a sitio nga agraman iti agpada a linaon.",
        "api-error-duplicate-archive": "Adda {{PLURAL:$1|idi sabali a papeles|dagidi sabali a papeles}} nga addaan ditoy a sitio nga agpada ti linaonda, ngem {{PLURAL:$1|daytoy|dagitoy}} ket naikkat.",
        "json-error-unsupported-type": "Naited ti pateg iti kita a saan a maikodigo",
        "headline-anchor-title": "Isilpo iti daytoy a paset",
        "special-characters-group-latin": "Latin",
-       "special-characters-group-latinextended": "Latin napaatiddog",
+       "special-characters-group-latinextended": "Naipaatiddog a Latin",
        "special-characters-group-ipa": "IPA",
        "special-characters-group-symbols": "Dagiti simbolo",
        "special-characters-group-greek": "Griego",
        "special-characters-group-greekextended": "Naipaatiddog a Griego",
        "special-characters-group-cyrillic": "Siriliko",
        "special-characters-group-arabic": "Arabiko",
-       "special-characters-group-arabicextended": "Arabiko a napaatiddog",
+       "special-characters-group-arabicextended": "Naipaatiddog nga Arabiko",
        "special-characters-group-persian": "Persiano",
        "special-characters-group-hebrew": "Hebreo",
        "special-characters-group-bangla": "Bangla",
index 2402224..28f11c0 100644 (file)
        "grant-createaccount": "Gawé akun",
        "grant-createeditmovepage": "Gawé, besut, lan lih kaca",
        "grant-delete": "Busak kaca, owahan, lan isian cathetan",
-       "newuserlogpage": "Cathetan panganggo anyar",
+       "newuserlogpage": "Log naraguna anyar",
        "newuserlogpagetext": "Ing ngisor iki kapacak log pandaftaran panganggo anyar.",
        "rightslog": "Log pangowahan hak aksès",
        "rightslogtext": "Ing ngisor iki kapacak log pangowahan marang hak-hak panganggo.",
        "booksources-invalid-isbn": "ISBN sing diwènèhaké katonané ora valid; priksa kasalahan penyalinan saka sumber asli.",
        "specialloguserlabel": "Panampil:",
        "speciallogtitlelabel": "Patujon (judhul utawa panganggo) :",
-       "log": "Cathetan",
+       "log": "Log",
        "all-logs-page": "Kabèh log publik",
        "alllogstext": "Gabungan tampilam kabèh log sing ana ing {{SITENAME}}.\nPanjenengan bisa mbatesi tampilan kanthi milih jinis log, jeneng panganggo (sènsitif aksara gedhé/cilik), utawa kaca sing magepokan (uga sènsitif aksara gedhé/cilik).",
        "logempty": "Ora ditemokaké èntri log sing pas.",
        "actioncomplete": "Proses tuntas",
        "actionfailed": "Tindakan gagal",
        "deletedtext": "\"$1\" sampun kabusak. Coba pirsani $2 kanggé log paling énggal kaca ingkang kabusak.",
-       "dellogpage": "Cathetan busakan",
+       "dellogpage": "Log busak",
        "dellogpagetext": "Ing ngisor iki kapacak log pambusakan kaca sing anyar dhéwé.",
        "deletionlog": "Cathetan sing dibusak",
        "reverted": "Dibalèkaké ing revisi sadurungé",
        "rollback-success": "Suntingan dibalèkaké déning $1;\ndiowahi bali menyang vèrsi pungkasan déning $2.",
        "sessionfailure-title": "Sèsi gagal",
        "sessionfailure": "Katoné ana masalah karo sèsi log panjenengan; log panjenengan wis dibatalaké kanggo nyegah pambajakan. Mangga mencèt tombol \"back\" lan unggahaké manèh kaca sadurungé mlebu log, lan coba manèh.",
-       "protectlogpage": "Cathetan pangreksan",
+       "protectlogpage": "Log reksa",
        "protectlogtext": "Ngisor iki daptar owahan saka panjagan kaca.\nDelok [[Special:ProtectedPages|daptar kaca sing dijaga]] kanggo daptar panjagan kaca paling anyar.",
        "protectedarticle": "ngreksa \"[[$1]]\"",
        "modifiedarticleprotection": "ngowahi tingkat pangreksan \"[[$1]]\"",
        "protect-otherreason-op": "Alesan liya",
        "protect-dropdown": "*Alesan umum pangreksan\n** Vandalisme makaping-kaping\n** Spam makaping-kaping\n** Perang suntingan\n** Kaca kerep disunting",
        "protect-edit-reasonlist": "Mbesut jalaraning pangreksa",
-       "protect-expiry-options": "1 jam:1 hour,1 dina:1 day,1 minggu:1 week,2 minggu:2 weeks,1 sasi:1 month,3 sasi:3 months,6 sasi:6 months,1 taun:1 year,tanpa wates:infinite",
+       "protect-expiry-options": "1 jam:1 hour,1 dina:1 day,1 minggu:1 week,2 minggu:2 weeks,1 wulan:1 month,3 wulan:3 months,6 wulan:6 months,1 taun:1 year,tanpa wates:infinite",
        "restriction-type": "Pangreksan:",
        "restriction-level": "Tingkatan pambatesan:",
        "minimum-size": "Ukuran minimum",
        "ipbenableautoblock": "Blokir alamat IP pungkasan sing dienggo déning pengguna iki sacara otomatis, lan kabèh alamat sabanjuré sing dicoba arep dienggo nyunting.",
        "ipbsubmit": "Kirimna",
        "ipbother": "Wektu liya",
-       "ipboptions": "2 jam:2 hours,1 dina:1 day,3 dina:3 days,1 minggu:1 week,2 minggu:2 weeks,1 sasi:1 month,3 sasi:3 months,6 sasi:6 months,1 taun:1 year,tanpa wates:infinite",
+       "ipboptions": "2 jam:2 hours,1 dina:1 day,3 dina:3 days,1 minggu:1 week,2 minggu:2 weeks,1 wulan:1 month,3 wulan:3 months,6 wulan:6 months,1 taun:1 year,tanpa wates:infinite",
        "ipbhidename": "Delikna jeneng panganggo saka suntingan lan pratélan",
        "ipbwatchuser": "Wasi kaca panganggoning lan kaca gegunemaning panganggo iki",
        "ipb-disableusertalk": "Alangi panganggo iki nyunting kaca gunemané nalika diblokir",
        "movepage-page-moved": "Kaca $1 wis dipindhah menyang $2.",
        "movepage-page-unmoved": "Kaca $1 ora bisa dialihaké menyang $2.",
        "movepage-max-pages": "Paling akèh $1 {{PLURAL:$1|kaca|kaca}} wis dialihaké lan ora ana manèh sing bakal dialihaké sacara otomatis.",
-       "movelogpage": "Cathetan lih-lihan",
+       "movelogpage": "Log alih",
        "movelogpagetext": "Ing ngisor iki kapacak log pangalihan kaca.",
        "movesubpage": "{{PLURAL:$1|Anak-kaca|Anak-kaca}}",
        "movesubpagetext": "Kaca iki nduwèni $1 {{PLURAL:$1|anak-kaca|anak-kaca}} kaya kapacak ing ngisor.",
        "hours": "{{PLURAL:$1|$1 jam|$1 jam}}",
        "days": "{{PLURAL:$1|$1 dina|$1 dina}}",
        "weeks": "{{PLURAL:$1|minggu|minggu}}",
-       "months": "{{PLURAL:$1|$1 sasi|$1 sasi}}",
+       "months": "{{PLURAL:$1|$1 wulan}}",
        "years": "{{PLURAL:$1|$1 taun|$1 taun}}",
        "ago": "$1 kapungkur",
        "just-now": "baru saja",
index 594636e..f56536b 100644 (file)
        "apihelp": "API-Hëllef",
        "apihelp-no-such-module": "Modul \"$1\" net fonnt.",
        "apisandbox": "API-Sandkëscht",
+       "apisandbox-jsonly": "Fir d'API-Sandkëscht ze benotze braucht Dir JavaScript.",
        "apisandbox-api-disabled": "API ass op dësem Site ausgeschalt.",
        "apisandbox-unfullscreen": "Säit weisen",
        "apisandbox-submit": "Ufro maachen",
        "apisandbox-reset": "Eidel maachen",
        "apisandbox-retry": "Nach eng Kéier probéieren",
+       "apisandbox-no-parameters": "Dësen API-Modul huet keng Parameteren.",
        "apisandbox-helpurls": "Hëllef-Linken",
        "apisandbox-examples": "Beispiller",
        "apisandbox-dynamic-parameters": "Zousätzlech Parameteren",
        "lockdbsuccesstext": "D'{{SITENAME}}-Datebank gouf gespaart. <br />\nDenkt drun [[Special:UnlockDB|d'Spär erëm ewechzehuele]] soubaal d'Maintenance-Aarbechte fäerdeg sinn.",
        "unlockdbsuccesstext": "D'Spär vun der Datebank ass opgehuewen.",
        "lockfilenotwritable": "De Fichier mat de Späre vun der Datebank kann net geännert ginn.\nFir d'Datebank ze spären oder fir d'Spär opzehiewe muss dëse Fichier vum Webserver geännert kënne ginn.",
+       "databaselocked": "D'Datebank ass scho gespaart.",
        "databasenotlocked": "D'Datebank ass net gespaart.",
        "lockedbyandtime": "(vum $1 de(n) $2 ëm $3 Auer)",
        "move-page": "Réckel $1",
        "api-error-unknownerror": "Onbekannte Feeler: \"$1\".",
        "api-error-uploaddisabled": "D'Eroplueden ass op dëser Wiki ausgeschalt.",
        "api-error-verification-error": "Dëse Fichier kéint korrupt sinn, oder en huet eng falsch Erweiderung.",
+       "api-error-was-deleted": "E Fichier mat dësem Numm gouf virdrun eropgelueden an duerno geläscht.",
        "duration-seconds": "$1 {{PLURAL:$1|Sekonn|Sekonnen}}",
        "duration-minutes": "$1 {{PLURAL:$1|Minutt|Minutten}}",
        "duration-hours": "$1 {{PLURAL:$1|Stonn|Stonnen}}",
index 150527f..581cc97 100644 (file)
@@ -67,6 +67,7 @@
        "tog-watchdefault": "Legg til sider og filer jeg endrer på i min overvåkingsliste",
        "tog-watchmoves": "Legg til sider og filer jeg flytter til min overvåkingsliste",
        "tog-watchdeletion": "Legg til sider og filer jeg sletter i min overvåkingsliste",
+       "tog-watchuploads": "Legg til nye filer jeg laster opp i overvåkningslisten min",
        "tog-watchrollback": "Legg til sider hvor jeg har utført tilbakestilling i min overvåkningsliste",
        "tog-minordefault": "Merk i utgangspunktet alle redigeringer som mindre",
        "tog-previewontop": "Vis forhåndsvisningen over redigeringsboksen",
        "tagline": "Fra {{SITENAME}}",
        "help": "Hjelp",
        "search": "Søk",
+       "search-ignored-headings": " #<!-- la denne linjen stå akkurat som den er --> <pre>\n# Overskrifter som vil bli ignorert ved søking.\n# Endringer på denne siden trer i kraft ved neste indeksering.\n# Du kan fremtvinge en reindeksering av en gitt side ved å gjøre en nullredigering.\n# Syntaksen er som følger:\n#   * Alt fra et \"#\"-tegn til slutten av en linje er en kommentar.\n#   * Enhver ikke-tom linje regnes som en ordrett tittel (inkludert skille mellom store og små bokstaver) som skal ignoreres.\nReferanser\nKilder\nEksterne lenker\nSe også\n #</pre> <!-- la denne linjen stå akkurat som den er -->",
        "searchbutton": "Søk",
        "go": "Gå",
        "searcharticle": "Gå",
        "botpasswords-insert-failed": "Kunne ikke legge til robotnavnet \"$1\". Har det allerede blitt lagt til?",
        "botpasswords-update-failed": "Kunne ikke oppdatere robotnavnet \"$1\". Er det slettet?",
        "botpasswords-created-title": "Robotpassord opprettet",
-       "botpasswords-created-body": "Robotpassordet \"$1\" ble opprettet.",
+       "botpasswords-created-body": "Robotpassordet for boten «$1» til brukeren «$2» ble opprettet.",
        "botpasswords-updated-title": "Robotpassord oppdatert",
-       "botpasswords-updated-body": "Robotpassordet \"$1\" ble oppdatert.",
+       "botpasswords-updated-body": "Robotpassordet for boten «$1» til brukeren «$2» ble oppdatert.",
        "botpasswords-deleted-title": "Robotpassord slettet",
-       "botpasswords-deleted-body": "Robotpassordet \"$1\" ble slettet.",
+       "botpasswords-deleted-body": "Robotpassordet for boten «$1» til brukeren «$2» ble slettet.",
        "botpasswords-newpassword": "Det nye passordet for å logge inn med <strong>$1</strong> er <strong>$2</strong>. <em>Vennligst lagre dette for fremtidig referanse.</em>",
        "botpasswords-no-provider": "BotPasswordsSessionProvider er ikke tilgjengelig.",
        "botpasswords-restriction-failed": "Begrensninger for robotpassord tillater ikke denne innloggingen.",
        "resetpass-no-info": "Du må være logget inn for å gå til denne siden direkte",
        "resetpass-submit-loggedin": "Endre passord",
        "resetpass-submit-cancel": "Avbryt",
-       "resetpass-wrong-oldpass": "Ugyldig midlertidig eller nåværende passord.\nDu kan ha allerede byttet passordet, eller bedt om et nytt midlertidig passord.",
+       "resetpass-wrong-oldpass": "Ugyldig midlertidig eller aktivt passord.\nDet kan tenkes at allerede har gjennomført et vellykket bytte av passord, eller bedt om et nytt midlertidig passord.",
        "resetpass-recycled": "Vær vennlig å endre passordet til noe annen enn gjeldende passord.",
        "resetpass-temp-emailed": "Du logget inn med en midlertidig kode sendt på e-post.\nFor å avslutte innloggingen må du angi et nytt passord her:",
        "resetpass-temp-password": "Midlertidig passord:",
        "passwordreset-emailelement": "Brukernavn: \n$1\n\nMidlertidig passord: \n$2",
        "passwordreset-emailsentemail": "Hvis denne epostadressen er koblet til din konto, så vil det bli sendt en epost om tilbakestilling av passord.",
        "passwordreset-emailsentusername": "Hvis det finnes en epostadresse knyttet til dette brukernavnet, vil en epost med informasjon om tilbakestilling av passord bli sendt.",
+       "passwordreset-emailsent-capture2": "{{PLURAL:$1|E-post}} om passordtilbakestilling har blitt sendt. {{PLURAL:$1|Brukernavnet og passordet|Listen over brukernavn og passord}} vises under.",
+       "passwordreset-emailerror-capture2": "Kunne ikke sende e-post til {{GENDER:$2|brukeren}}: $1 {{PLURAL:$3|Brukernavnet og passordet|Listen over brukernavn og passord}} vises under.",
+       "passwordreset-invalideamil": "Ugyldig e-postadresse",
+       "passwordreset-nodata": "Verken et brukernavn eller en e-postadresse ble oppgitt",
        "changeemail": "Endre eller fjerne epostadresse",
        "changeemail-header": "Fyll ut dette skjemaet for å bytte din epost-adresse. Hvis du vil fjerne epostadressen fra din konto, kan du la ny epostadresse-feltet være tomt når.",
        "changeemail-no-info": "Du må være innlogget for å få direkte tilgang til denne siden.",
        "minoredit": "Dette er en mindre endring",
        "watchthis": "Overvåk denne siden",
        "savearticle": "Lagre siden",
+       "savechanges": "Lagre endringer",
        "publishpage": "Publiser siden",
        "publishchanges": "Publiser endringene",
        "preview": "Forhåndsvisning",
        "accmailtext": "Et tilfeldig passord for [[User talk:$1|$1]] har blitt sendt til $2. Det kan endres på [[Special:ChangePassword|passordendringssiden]] under innlogging.",
        "newarticle": "(Ny)",
        "newarticletext": "Du har fulgt en lenke til en side som ikke finnes ennå.\nFor å opprette siden, begynn å skrive i boksen under (se [$1 hjelpesiden] for mer informasjon).\nOm du havnet her ved en feil, trykk '''tilbake''' i nettleseren.",
-       "anontalkpagetext": "----\n''Dette er en diskusjonsside for en uregistrert bruker som ikke har opprettet konto eller ikke er logget inn.\nVi er derfor nødt til å bruke den numeriske IP-adressen til å identifisere ham eller henne.\nEn IP-adresse kan være delt mellom flere brukere.\nHvis du er en uregistrert bruker og synes at du har fått irrelevante kommentarer på en slik side, [[Special:CreateAccount|opprett en konto]] eller [[Special:UserLogin|logg inn]] så vi unngår fremtidige forvekslinger med andre uregistrerte brukere.''",
+       "anontalkpagetext": "----\n<em>Dette er en diskusjonsside for en anonym bruker som ikke har opprettet konto enda, eller som ikke bruker den.</em>\nVi er derfor nødt til å bruke den numeriske IP-adressen til å identifisere ham eller henne.\nEn IP-adresse kan være delt mellom flere brukere.\nHvis du er en anonym bruker og opplever å få irrelevante kommentarer rettet mot deg, [[Special:CreateAccount|opprett en konto]] eller [[Special:UserLogin|logg inn]] for å unngå fremtidige forvekslinger med andre anonyme brukere.",
        "noarticletext": "Det er for tiden ingen tekst på denne siden.\nDu kan [[Special:Search/{{PAGENAME}}|søke etter denne sidetittelen]] på andre sider,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} søke i relaterte logger],\neller [{{fullurl:{{FULLPAGENAME}}|action=edit}} opprette siden]</span>.",
        "noarticletext-nopermission": "Det er for tiden ingen tekst på denne siden.\nDu kan [[Special:Search/{{PAGENAME}}|søke etter sidens tittel]] blant andre sider, eller <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} søke i relevante logger]</span>, men du har ikke tillatelse til å opprette denne siden.",
        "missing-revision": "Revisjonen #$1 av siden med navnet \"{{FULLPAGENAME}}\" eksisterer ikke.\n\nDette skyldes som regel at en gammel historikklenke er fulgt til en side som er slettet.\nDetaljer kan finnes i [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} sletteloggen].",
        "userpage-userdoesnotexist": "Brukerkontoen «$1» er ikke registrert.\nSjekk om du ønsker å opprette/redigere denne siden.",
        "userpage-userdoesnotexist-view": "Kontoen «$1» er ikke registrert.",
        "blocked-notice-logextract": "Denne brukeren er for tiden blokkert.\nSiste blokkeringsloggelement kan sees nedenfor.",
-       "clearyourcache": "'''Merk:''' Etter lagring vil det kanskje være nødvendig at nettleseren sletter hurtiglageret sitt for at endringene skal tre i kraft.\n* '''Firefox / Safari:''' Hold ''Shift'' mens du klikker på ''Oppdater'' eller trykk ''Ctrl-F5'' eller ''Ctrl-R'' (''⌘-R'' på en Mac)\n* '''Google Chrome:''' Trykk ''Ctrl-Shift-R'' (''⌘-Shift-R'' på en Mac)\n* '''Internet Explorer:''' Hold ''Ctrl'' mens du klikker på ''Oppdater'' eller trykk ''Ctrl-F5''\n* '''Opera:''' Tøm hurtiglageret i ''Verktøy → Innstillinger''",
+       "clearyourcache": "<strong>Merk:</strong> Etter lagring vil det kanskje være nødvendig at nettleseren sletter hurtiglageret sitt for at endringene skal tre i kraft.\n* <strong>Firefox / Safari:</strong> Hold <em>Shift</em> mens du klikker på <em>Oppdater</em> eller trykk <em>Ctrl-F5</em> eller <em>Ctrl-R</em> (<em>⌘-R</em> på en Mac)\n* <strong>Google Chrome:</strong> Trykk <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> på en Mac)\n* <strong>Internet Explorer:</strong> Hold <em>Ctrl</em> mens du klikker på <em>Oppdater</em> eller trykk <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Tøm hurtiglageret i <em>Meny → Innstillinger</em> og deretter <em>Personvern & sikkerhet → Slett surfedata → Mellomlagrede bilder og filer</em>.",
        "usercssyoucanpreview": "'''Tips:''' Bruk «{{int:showpreview}}»-knappen for å teste din nye CSS før du lagrer.",
        "userjsyoucanpreview": "'''Tips:''' Bruk «{{int:showpreview}}»-knappen for å teste ditt nye JS før du lagrer.",
        "usercsspreview": "'''Husk at dette bare er en forhåndsvisning av din bruker-CSS og at den ikke er lagret!'''",
        "continue-editing": "Gå til redigeringsfeltet",
        "previewconflict": "Slik vil teksten i redigeringsvinduet se ut dersom du lagrer den.",
        "session_fail_preview": "'''Beklager! Klarte ikke å lagre redigeringen din på grunn av tap av øktdata.'''\n\nDu kan ha blitt logget ut. <strong>Sjekk at du fortsatt er innlogget og prøv igjen.</strong>\nOm det fortsetter å gå galt, prøv å [[Special:UserLogout|logge ut]] og så inn igjen, og sjekk at nettleseren din godtar informasjonskapsler fra denne siden.",
-       "session_fail_preview_html": "'''Beklager! Klarte ikke å lagre redigeringen din på grunn av tap av øktdata.'''\n\n''Fordi {{SITENAME}} har rå HTML slått på, er forhåndsvisningen skjult for å forhindre JavaScript-angrep.''\n\n'''Om dette er et legitimt redigeringsforsøk, prøv igjen. Om det da ikke fungerer, prøv å [[Special:UserLogout|logge ut]] og logge inn igjen.'''",
+       "session_fail_preview_html": "Beklager! Klarte ikke å lagre redigeringen din på grunn av tap av øktdata.\n\n<em>Fordi {{SITENAME}} har rå HTML slått på, er forhåndsvisningen skjult for å forhindre JavaScript-angrep.</em>\n\n<strong>Om dette er et legitimt redigeringsforsøk, prøv igjen.</strong> Om det fortsatt ikke fungerer, prøv å [[Special:UserLogout|logge ut]] og logge inn igjen og sjekk at nettleseren din godtar informasjonskapsler fra dette nettstedet.",
        "token_suffix_mismatch": "'''Redigeringen din har blitt avvist fordi klienten din ikke hadde punktasjonstegn i redigeringsteksten. Redigeringen har blitt avvist for å hindre ødeleggelse av artikkelteksten. Dette forekommer av og til når man bruker vevbaserte anonyme proxytjenester.'''",
        "edit_form_incomplete": "'''Deler av redigeringsskjemaet nådde ikke tjeneren; dobbelsjekk at redigeringen er korrekt og prøv igjen.'''",
        "editing": "Redigerer $1",
        "revdelete-unsuppress": "Fjern betingelser på gjenopprettede revisjoner",
        "revdelete-log": "Årsak:",
        "revdelete-submit": "Utfør på {{PLURAL:$1|valgt revisjon|valgte revisjoner}}",
-       "revdelete-success": "'''Revisjonssynlighet vellykket oppdatert.'''",
+       "revdelete-success": "Revisjonssynlighet ble oppdatert.",
        "revdelete-failure": "'''Kunne ikke endre versjonssynligheten:'''\n$1",
-       "logdelete-success": "'''Hendelsessynlighet satt.'''",
+       "logdelete-success": "Hendelsessynlighet ble satt.",
        "logdelete-failure": "'''Loggens synlighet kunne ikke bli stilt inn:'''\n$1",
        "revdel-restore": "endre synlighet",
        "pagehist": "Sidehistorikk",
        "userrights-unchangeable-col": "Grupper du ikke kan endre",
        "userrights-irreversible-marker": "$1 *",
        "userrights-conflict": "En konflikt med endringen av brukerrettigheter! Vær vennlig å sjekke og på nytt bekrefte endringene dine.",
-       "userrights-removed-self": "Du har fjernet dine egne rettigheter. Du har derfor ikke lengere adgang til denne siden.",
+       "userrights-removed-self": "Du har fjernet dine egne rettigheter. Du har derfor ikke lengre adgang til denne siden.",
        "group": "Gruppe:",
        "group-user": "Brukere",
        "group-autoconfirmed": "Autobekreftede brukere",
        "right-override-export-depth": "Eksporter sider inkludert lenkede sider til en dypde på 5",
        "right-sendemail": "Send e-post til andre brukere",
        "right-passwordreset": "Vis e-poster over tilbakestilte passord",
-       "right-managechangetags": "Opprette og slette [[Special:Tags|tagger]] fra databasen",
+       "right-managechangetags": "Opprette og (de)aktivere [[Special:Tags|tagger]]",
        "right-applychangetags": "Legg til [[Special:Tags|merker]] sammen med ens endringer",
        "right-changetags": "Legg til og fjern vilkårlige [[Special:Tags|merker]] på individuelle revisjoner og loggposter",
+       "right-deletechangetags": "Slette [[Special:Tags|tagger]] fra databasen",
        "grant-generic": "Rettighetspakken «$1»",
        "grant-group-page-interaction": "Interagere med sider",
        "grant-group-file-interaction": "Interagere med media",
        "rightslogtext": "Dette er en logg over endringer av brukerrettigheter.",
        "action-read": "se denne siden",
        "action-edit": "redigere denne siden",
-       "action-createpage": "opprette sider",
-       "action-createtalk": "opprette diskusjonssider",
+       "action-createpage": "opprette denne siden",
+       "action-createtalk": "opprette denne diskusjonssiden",
        "action-createaccount": "opprette denne kontoen",
        "action-history": "se historikken til denne siden",
        "action-minoredit": "merke denne redigeringen som mindre",
        "action-viewmyprivateinfo": "vise din private informasjon",
        "action-editmyprivateinfo": "rediger din private informasjon",
        "action-editcontentmodel": "rediger innholdsmodellen til en side",
-       "action-managechangetags": "opprette og slette tagger fra databasen",
+       "action-managechangetags": "opprette og (de)aktivere tagger",
        "action-applychangetags": "bruk merker sammen med dine endringer",
        "action-changetags": "legg til og fjern vilkårlige merker på individuelle revisjoner og loggposter",
+       "action-deletechangetags": "slette tagger fra databasen",
        "nchanges": "$1 {{PLURAL:$1|endring|endringer}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|siden forrige besøk}}",
        "enhancedrc-history": "historikk",
        "recentchangeslinked-page": "Sidenavn:",
        "recentchangeslinked-to": "Vis endringer på sider som lenker til den gitte siden istedet",
        "recentchanges-page-added-to-category": "[[:$1]] lagt til kategori",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] og [[Special:WhatLinksHere/$1|{{PLURAL:$2|én side|$2 sider}}]] lagt til kategori",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] lagt til i kategori, [[Special:WhatLinksHere/$1|denne siden er inkludert i andre sider]]",
        "recentchanges-page-removed-from-category": "[[:$1]] fjernet fra kategori",
-       "recentchanges-page-removed-from-category-bundled": "[[:$1]] og {{PLURAL:$2|én side|$2 sider}} fjernet fra kategori",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] fjernet fra kategori, [[Special:WhatLinksHere/$1|denne siden er inkludert i andre sider]]",
        "autochange-username": "Automatisk MediaWiki-endring",
        "upload": "Last opp fil",
        "uploadbtn": "Last opp fil",
        "backend-fail-read": "Klarte ikke lese filen $1.",
        "backend-fail-create": "Kunne ikke opprette filen $1.",
        "backend-fail-maxsize": "Kunne ikke skrive filen $1 fordi den er større enn {{PLURAL:$2|én byte|$2 bytes}}.",
-       "backend-fail-readonly": "Underliggende \"$1\" er satt skrivebeskyttet fordi: \"$2\"",
+       "backend-fail-readonly": "Lagringssystemet «$1» er midlertidig skrivebeskyttet fordi: <em>$2</em>",
        "backend-fail-synced": "Fila «$1» er i en inkonsistent status innen de interne bakstykkene",
        "backend-fail-connect": "Kunne ikke koble til filbackend «$1».",
        "backend-fail-internal": "En ukjent feil oppsto i filbackend «$1».",
        "uploadstash-summary": "Denne siden gir tilgang til filer som har blitt lastet opp (eller er i ferd med å bli lastet opp) men som ennå ikke er publisert til wikien. Disse filene er ikke synlige for andre enn brukeren som lastet dem opp.",
        "uploadstash-clear": "Fjern stashede filer",
        "uploadstash-nofiles": "Du har ingen stashede filer.",
-       "uploadstash-badtoken": "Utføringen av den handlingen var mislykket, kanskje fordi redigeringsrettighetene dine har utløpt. Prøv igjen.",
-       "uploadstash-errclear": "Fjerning av filene var mislykket.",
+       "uploadstash-badtoken": "Utføringen av handlingen feilet, kanskje fordi redigeringsrettighetene dine har utløpt. Prøv igjen.",
+       "uploadstash-errclear": "Filene lot seg ikke fjerne.",
        "uploadstash-refresh": "Oppdater listen over filer",
        "invalid-chunk-offset": "Ugyldig delforskyvning",
        "img-auth-accessdenied": "Ingen tilgang",
        "apihelp-no-such-module": "Modulen «$1» ikke funnet.",
        "apisandbox": "API-sandkasse",
        "apisandbox-api-disabled": "API er deaktivert på dette nettstedet.",
-       "apisandbox-intro": "Bruk denne siden for å eksperimentere med '''MediaWiki web service APIet'''.\nSjekk [https://www.mediawiki.org/wiki/API:Main_page API-dokumentasjonen] for mer informasjon om bruk av APIet. Eksempel: [https://www.mediawiki.org/wiki/API#A_simple_example hente innholdet til en hovedside]. Velg en handling for å se flere eksempler.\n\nMerk at du kan utføre handlinger her som fører til endringer på wikien.",
+       "apisandbox-intro": "Bruk denne siden for å eksperimentere med <strong>MediaWiki webtjeneste-APIet</strong>.\nSjekk [[mw:API:Main page|API-dokumentasjonen]] for mer informasjon om bruk av APIet. Eksempel: [https://www.mediawiki.org/wiki/API#A_simple_example hente innholdet til en hovedside]. Velg en handling for å se flere eksempler.\n\nMerk at du kan utføre handlinger her som fører til endringer på wikien.",
        "apisandbox-submit": "Foreta en forespørsel",
        "apisandbox-reset": "Tilbakestill",
-       "apisandbox-examples": "Eksempel",
-       "apisandbox-results": "Resultat",
+       "apisandbox-examples": "Eksempler",
+       "apisandbox-results": "Resultater",
        "apisandbox-request-url-label": "Forespurt URL:",
-       "apisandbox-request-time": "Forespørselstid: $1",
+       "apisandbox-request-time": "Forespørselstid: {{PLURAL:$1|$1 ms}}",
        "booksources": "Bokkilder",
        "booksources-search-legend": "Søk etter bokkilder",
        "booksources-search": "Søk",
        "listgrouprights-namespaceprotection-header": "Navneromsbegrensinger",
        "listgrouprights-namespaceprotection-namespace": "Navnerom",
        "listgrouprights-namespaceprotection-restrictedto": "Rettighet(er) som tillater at brukeren redigerer",
-       "listgrants-summary": "Følgende er en liste over OAuth-tildelinger og hvilke brukerrettigheter de gir tilgang til. Brukere kan autorisere applikasjoner til å bruke kontoen deres, med rettigheter begrenset til de gitt av tildelingene brukeren har godkjent. En applikasjon som handler på vegne av en bruker kan imidlertid aldri benytte seg av rettigheter brukeren ikke selv har.\nDet kan finnes [[{{MediaWiki:Listgrouprights-helppage}}|ytterligere informasjon]] om de ulike rettighetene.",
+       "listgrants-summary": "Følgende er en liste over tildelinger samt hvilke brukerrettigheter de gir tilgang til. Brukere kan autorisere applikasjoner til å bruke kontoen deres, med rettigheter begrenset til de gitt av tildelingene brukeren har godkjent. En applikasjon som handler på vegne av en bruker kan imidlertid aldri benytte seg av rettigheter brukeren ikke selv har.\nDet kan finnes [[{{MediaWiki:Listgrouprights-helppage}}|ytterligere informasjon]] om de ulike rettighetene.",
        "listgrants-rights": "Rettigheter",
        "trackingcategories": "Sporingskategori",
        "trackingcategories-summary": "Denne siden lister sporingskategorier som er automatisk befolket av Mediawiki-programvaren. Navnene deres kan endres ved å redigere de tilhørende systembeskjedene i {{ns:8}}-navnerommet.",
        "delete-toobig": "Denne siden har en stor redigeringshistorikk, med over {{PLURAL:$1|$1&nbsp;revisjon|$1&nbsp;revisjoner}}. Muligheten til å slette slike sider er begrenset for å unngå utilsiktet forstyrring av {{SITENAME}}.",
        "delete-warning-toobig": "Denne siden har en stor redigeringshistorikk, med over {{PLURAL:$1|$1&nbsp;revisjon|$1&nbsp;revisjoner}}. Sletting av denne siden kan forstyrre databasen til {{SITENAME}}; vær varsom.",
        "deleteprotected": "Du kan ikke slette denne siden fordi den er beskyttet.",
-       "deleting-backlinks-warning": "'''Advarsel:''' [[Special:WhatLinksHere/{{FULLPAGENAME}}|Andre sider]] lenker til eller inkluderer siden du er i ferd med å slette.",
+       "deleting-backlinks-warning": "<strong>Advarsel:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Andre sider]] lenker til eller inkluderer siden du er i ferd med å slette.",
        "rollback": "Fjern redigeringer",
        "rollbacklink": "tilbakestill",
        "rollbacklinkcount": "tilbakestill {{PLURAL:$1|én endring|$1 endringer}}",
        "undeletedrevisions": "{{PLURAL:$1|Én revisjon|$1 revisjoner}} gjenopprettet",
        "undeletedrevisions-files": "{{PLURAL:$1|Én revisjon|$1 revisjoner}} og {{PLURAL:$2|én fil|$2 filer}} gjenopprettet",
        "undeletedfiles": "{{PLURAL:$1|Én fil|$1 filer}} gjenopprettet",
-       "cannotundelete": "Gjennoppretting feilet:\n$1",
+       "cannotundelete": "Deler av eller hele gjennopprettingen feilet:\n$1",
        "undeletedpage": "'''$1 ble gjenopprettet'''\n\nSjekk [[Special:Log/delete|slettingsloggen]] for en liste over nylige slettinger og gjenopprettelser.",
        "undelete-header": "Se [[Special:Log/delete|slettingsloggen]] for nylig slettede sider.",
        "undelete-search-title": "Søk i slettede sider",
        "lastmodifiedatby": "Denne siden ble sist redigert $1 kl. $2 av $3.",
        "othercontribs": "Basert på arbeid av $1.",
        "others": "andre",
-       "siteusers": "{{SITENAME}}-{{PLURAL:$2|bruker|brukere}} $1",
+       "siteusers": "{{SITENAME}}-{{PLURAL:$2|{{GENDER:$1|bruker}}|brukere}} $1",
        "anonusers": "{{SITENAME}}s {{PLURAL:$2|anonyme bruker|anonyme brukere}} $1",
        "creditspage": "Sidekrediteringer",
        "nocredits": "Ingen krediteringer er tilgjengelig for denne siden.",
        "scarytranscludefailed-httpstatus": "[Henting av mal for $1 feilet: HTTP $2]",
        "scarytranscludetoolong": "[URL-en er for lang]",
        "deletedwhileediting": "'''Advarsel:''' Denne siden har blitt slettet etter at du begynte å redigere den!",
-       "confirmrecreate": "«[[User:$1|$1]]» ([[User talk:$1|diskusjon]]) slettet siden etter at du begynte å redigere den, med begrunnelsen «$2». Vennligst bekreft at du vil gjenopprette siden.",
-       "confirmrecreate-noreason": "Brukeren [[User:$1|$1]] ([[User talk:$1|diskusjon]]) slettet denne siden etter at du begynte å redigere. Bekreft at du virkelig ønsker å gjenopprette denne siden.",
+       "confirmrecreate": "Brukeren [[User:$1|$1]] ([[User talk:$1|diskusjon]]) {{GENDER:$1|slettet}} siden etter at du begynte å redigere den, med begrunnelsen:\n: <em>$2</em>\nVennligst bekreft at du vil gjenopprette siden.",
+       "confirmrecreate-noreason": "Brukeren [[User:$1|$1]] ([[User talk:$1|diskusjon]]) {{GENDER:$1|slettet}} denne siden etter at du begynte å redigere. Bekreft at du virkelig ønsker å gjenopprette denne siden.",
        "recreate": "Gjenopprett",
        "confirm_purge_button": "OK",
        "confirm-purge-top": "Vil du slette tjenerens mellomlagrede versjon (''cache'') av denne siden?",
        "watchlistedit-raw-done": "Overvåkningslisten din er oppdatert.",
        "watchlistedit-raw-added": "{{PLURAL:$1|Én tittel|$1 titler}} ble lagt til:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|Én tittel|$1 titler}} ble fjernet:",
-       "watchlistedit-clear-title": "Rensket overvåkningslisten",
+       "watchlistedit-clear-title": "Tøm overvåkningslisten",
        "watchlistedit-clear-legend": "Rensk overvåkninslisten",
        "watchlistedit-clear-explain": "Alle titlene blir fjernet fra overvåkningslisten din",
        "watchlistedit-clear-titles": "Titler:",
        "tags-edit-revision-legend": "Legg til eller fjern fra {{PLURAL:$1|denne revisjonen|alle revisjoner}}",
        "tags-edit-logentry-legend": "Legg til eller fjern fra {{PLURAL:$1|denne loggposten|alle loggposter}}",
        "tags-edit-existing-tags": "Eksisterende merker:",
-       "tags-edit-existing-tags-none": "«Ingen»",
+       "tags-edit-existing-tags-none": "<em>Ingen</em>",
        "tags-edit-new-tags": "Nye merker:",
        "tags-edit-add": "Legg til disse merkene:",
        "tags-edit-remove": "Fjern disse merkene:",
        "tags-edit-reason": "Årsak:",
        "tags-edit-revision-submit": "Utfør endringene på {{PLURAL:$1|denne revisjonen|$1 revisjoner}}",
        "tags-edit-logentry-submit": "Utfør endringene på {{PLURAL:$1|denne loggposten|$1 loggposter}}",
-       "tags-edit-success": "Endringene ble suksessfullt utført.",
+       "tags-edit-success": "Endringene ble utført.",
        "tags-edit-failure": "Denne endringen kunne ikke bli utført:\n$1",
        "tags-edit-nooldid-title": "Ugyldig målrevisjon",
        "tags-edit-nooldid-text": "Du har enten ikke angitt noen målversjon for denne funksjonen, eller så har du angitt en revisjon som ikke finnes.",
        "logentry-protect-protect-cascade": "$1 {{GENDER:$2|beskyttet}} $3 $4 [cascading]",
        "logentry-protect-modify": "$1 {{GENDER:$2|endret}} beskyttelsesnivå for $3 $4",
        "logentry-protect-modify-cascade": "$1 {{GENDER:$2|endret}} beskyttelsesnivå for $3 $4 [cascading]",
-       "logentry-rights-rights": "$1 {{GENDER:$2|endret}} gruppemedlemskap for $3 fra $4 til $5",
+       "logentry-rights-rights": "$1 {{GENDER:$2|endret}} gruppemedlemskap for {{GENDER:$6|$3}} fra $4 til $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|endret}} gruppemedlemskap for $3",
        "logentry-rights-autopromote": "$1 ble automatisk {{GENDER:$2|forfremmet}} fra $4 til $5",
        "logentry-upload-upload": "$1 {{GENDER:$2|lastet opp}} $3",
        "expand_templates_preview": "Forhåndsvisning",
        "expand_templates_preview_fail_html": "<em>Fordi {{SITENAME}} har slått på rå HTML og sesjonsdata ble tapt er forhåndsvisningen skjult for å beskytte mot JavaScript-angrep.</em>\n\n<strong>Om dette er et legitimt forsøk på å forhåndsvise, prøv igjen.</strong> Om det fortsatt ikke fungerer, prøv å [[Special:UserLogout|logge ut]] og logge inn igjen.",
        "expand_templates_preview_fail_html_anon": "<em>Fordi {{SITENAME}} har slått på rå HTML og du ikke er logget inn er forhåndsvisningen skjult for å beskytte mot JavaScript-angrep.</em>\n\n<strong>Om dette er et legitimt forsøk på å forhåndsvise, [[Special:UserLogin|logg inn]] og prøv igjen.</strong>",
-       "pagelanguage": "Valg av sidespråk",
+       "pagelanguage": "Endre sidespråk",
        "pagelang-name": "Side",
        "pagelang-language": "Språk",
        "pagelang-use-default": "Bruk standardspråk",
        "pagelang-submit": "Lagre",
        "right-pagelang": "Endre sidespråk",
        "action-pagelang": "endre sidespråket",
-       "log-name-pagelang": "Endre språklogg",
+       "log-name-pagelang": "Logg for språkendringer",
        "log-description-pagelang": "Dette er en logg som viser endringer i sidespråk",
-       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|endret}} sidespråk for $3 fra $4 til $5.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|endret}} språk for $3 fra $4 til $5.",
        "default-skin-not-found": "Ops! Standarddrakten for wikien din, definert i <code dir=\"ltr\">$wgDefaultSkin</code> som <code>$1</code>, er ikke tilgjengelig.\n\nInstallasjonen din ser ut til å inneholde følgende {{PLURAL:$4|drakt|drakter}}. Se [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] for informasjon om hvordan du kan slå {{PLURAL:$4|denne på|disse på og velge en standarddrakt}}.\n\n$2\n\n; Om du nettopp har installert MediaWiki:\n: Du har trolig installert fra git, eller direkte fra kildekoden med en annen metode. Dette er forventet. Prøv å installere noen drakter fra [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org sin draktbase] ved å\n:* laste ned [https://www.mediawiki.org/wiki/Download tarball-installereren], som kommer med flere drakter og utvidelser. Du kan kopiere og lime inn <code>skins/</code>-mappen fra denne.\n:* laste ned individuelle drakter fra [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* klone en av <code>mediawiki/skins/*</code>-lagrene via git inn i <code>skins/</code> -mappen av din MediaWiki-installasjon.\n: Å gjøre dette skal ikke forstyrre git-mappen din om du er en MediaWiki-utvikler.\n\n; Om du nettopp har oppgradert MediaWiki:\n: MediaWiki 1.24 og nyere slår ikke lenger på automatisk installerte drakter (se [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]). Du kan lime inn følgende {{PLURAL:$5|linje|linjer}} i <code>LocalSettings.php</code> for å slå på {{PLURAL:$5|den|alle}} nåværende installerte {{PLURAL:$5|drakten|drakter}}:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Om du nettopp har endret <code>LocalSettings.php</code>:\n: Dobbelsjekk draktnavnene for skrivefeil.",
        "default-skin-not-found-no-skins": "Ops! Standarddrakten for wikien din, definert i <code>$wgDefaultSkin</code> som <code>$1</code>, er ikke tilgjengelig.\n\nDu har ingen installerte drakter.\n\n;Om du nettopp har installert eller oppgradert MediaWiki:\n: Du installerte trolig fra git, eller direkte fra kildekoden med en annen metode. Dette er forventet. MediaWiki 1.24 og nyere inkluderer ingen drakter i hovedarkivet. Prøv å installere noen drakter fra [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.orgs draktmappe], ved å:\n:* laste ned [https://www.mediawiki.org/wiki/Download tarball-installereren], som kommer med mange drakter og tillegg. Du kan kopiere og lime inn <code>skins/</code>-mappen fra denne.\n:* laste ned individuelle drakt-tarballer fra [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* klone en av <code>mediawiki/skins/*</code>-arkivene via git til <code dir=\"ltr\">skins/</code>-mappa i din MediaWiki-installasjon.\n: Å gjøre dette vil ikke forstyrre ditt git-arkiv om du er en MediaWiki-utvikler. Se [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual:Skin configuration] for informasjon om hvordan du slår på drakter og velger en standarddrakt.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (slått på)",
index bffd6e9..2a1628f 100644 (file)
        "emailuser-title-target": "Send epost åt {{GENDER:$1|brukaren}}",
        "emailuser-title-notarget": "Send e-post åt brukar",
        "emailpagetext": "Du kan nytte skjemaet nedanfor til å sende ein e-post til denne {{GENDER:$1|brukaren}}.\nE-postadressa du har sett i [[Special:Preferences|innstillingane dine]] vil dukke opp i «frå»-feltet på denne e-posten, så mottakaren er i stand til å svare.",
-       "defemailsubject": "{{SITENAME}} epost frå brukar \"$1\"",
+       "defemailsubject": "{{SITENAME}}-e-post frå brukar «$1»",
        "usermaildisabled": "Brukare-post slegen av",
        "usermaildisabledtext": "Du kan ikkje senda e-postar til andre brukarar på wikien",
        "noemailtitle": "Inga e-postadresse",
index 643d165..4dca72d 100644 (file)
        "category-subcat-count-limited": "Бу категория {{PLURAL:$1|субкатегориялаах|$1 субкатегориялардаах}}.",
        "category-article-count": "{{PLURAL:$2|Бу категория манна эрэ көстүбүт субкатегориялаах.|$2 категорияттан {{PLURAL:$1|субкатегорията|$1 субкатегориялара}} көрдөрүлүннүлэр.}}",
        "category-article-count-limited": "Бу категорияҕа {{PLURAL:$1|1 эрэ сирэй|$1 сирэй}} баар.",
-       "category-file-count": "{{PLURAL:$2|Бу категория манна эрэ көстүбүт билэлээх.|$2 категорияттан {{PLURAL:$1|билэтэ|$1 билэлэрэ}} көрдөрүлүннүлэр.}}",
+       "category-file-count": "{{PLURAL:$2|Бу категория манна эрэ көстүбүт билэлээх.|Бу категорияҕа баар $2 билэттэн {{PLURAL:$1|билэтэ|$1 билэтэ}} көрдөрүлүннэ.}}",
        "category-file-count-limited": "Бу категорияҕа  {{PLURAL:$1|соҕотох билэ|$1 билэ}} баар.",
        "listingcontinuesabbrev": "(салгыыта)",
        "index-category": "Индекстэммит сирэйдэр",
        "userlogin-yourname-ph": "Бэлиэ-ааккын киллэр",
        "createacct-another-username-ph": "Ааккын суруй",
        "yourpassword": "Киирии тыла:",
-       "userlogin-yourpassword": "Ð\9aииÑ\80ии Ñ\82Ñ\8bл",
+       "userlogin-yourpassword": "Ð\90һаÑ\80Ñ\8bк",
        "userlogin-yourpassword-ph": "Киирии тылгын суруй",
        "createacct-yourpassword-ph": "Киирии тылгын суруй",
        "yourpasswordagain": "Киирии тылгын хатылаа:",
        "passwordtooshort": "Киирии тылыҥ наһаа кылгас.\nКырата {{PLURAL:$1|1 бэлиэлээх|$1 бэлиэлээх}} буолуохтаах.",
        "passwordtoolong": "Аһарык {{PLURAL:$1|1 бэлиэттэн|$1 бэлиэттэн}} уһун буолуо суохтаах.",
        "passwordtoopopular": "Элбэхтэ туттуллар аһарыктары туттар сатаммат. Бука диэн атын аһарыкта тал.",
-       "password-name-match": "Ð\9aииÑ\80ии Ñ\82Ñ\8bл ааккыттан атын буолуохтаах.",
+       "password-name-match": "Ð\90һаÑ\80Ñ\8bгÑ\8bÒ¥ ааккыттан атын буолуохтаах.",
        "password-login-forbidden": "Маннык ааты уонна киирии тылы туһаныы бобуллар.",
        "mailmypassword": "Киирии тылы саҥардыы",
        "passwordremindertitle": "{{SITENAME}} киирии тылын санатыы",
-       "passwordremindertext": "Ð\9aим Ñ\8dÑ\80Ñ\8d (бадаÒ\95а Ñ\8dн Ð±Ñ\83 IP-аадÑ\8bÑ\80Ñ\8bÑ\81Ñ\82ан: $1), {{SITENAME}} ($4) ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bлÑ\8bн Ñ\81аҥаÑ\82Ñ\82ан Ñ\8bÑ\8bÑ\82Ñ\8bÒ¥ Ð´Ð¸Ñ\8dбиÑ\82.\n\"$2\" ÐºÑ\8bÑ\82Ñ\82ааÑ\87Ñ\87Ñ\8b Ð±Ñ\8bÑ\81Ñ\82аÑ\85 ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bла Ð±Ð¸Ð»Ð¸Ð³Ð¸Ð½ Ð¼Ð°Ð½Ð½Ñ\8bк: \"$3\".\nÓ¨Ñ\81кө Ð¼Ð°Ð½Ñ\8b Ñ\8dн Ñ\87аÑ\85Ñ\87Ñ\8b ÐºÓ©Ñ\80дөөбүÑ\82 Ð±Ñ\83оллаÑ\85Ñ\85Ñ\8bна, Ñ\81иÑ\81Ñ\82иÑ\8dмÑ\8dÒ\95Ñ\8d Ñ\81аҥаÑ\82Ñ\82ан ÐºÐ¸Ð¸Ñ\80Ñ\8dҥҥин ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bлгÑ\8bн Ñ\83лаÑ\80Ñ\8bÑ\82Ñ\8bаÑ\85Ñ\85Ñ\8bн Ñ\81өп.\nÐ\91Ñ\8bÑ\81Ñ\82аÑ\85 ÐºÐ¸Ð¸Ñ\80и Ñ\82Ñ\8bл {{PLURAL:$5|бииÑ\80 Ñ\85онÑ\83к|$5 Ñ\85онÑ\83к Ñ\83Ñ\81Ñ\82аÑ\82а}} Ò¯Ð»Ñ\8dлииÑ\80.\n\nÓ¨Ñ\81көÑ\82үн ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bлÑ\8b Ñ\81аҥаÑ\82Ñ\82ан ÐºÓ©Ñ\80дөөбөÑ\82Ó©Ñ\85 Ð±Ñ\83оллаÑ\85Ñ\85Ñ\8bна,\nÑ\8dбÑ\8dÑ\82Ñ\8dÑ\80 Ñ\83Ñ\80Ñ\83ккÑ\83 ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bлгÑ\8bн Ó©Ð¹Ð´Ó©Ó©Ð½ ÐºÑ\8dлбиÑ\82 Ð±Ñ\83оллаÑ\85Ñ\85Ñ\8bна,\nбÑ\83 Ñ\81Ñ\83Ñ\80Ñ\83кка Ð°Ð°Ñ\85Ñ\85айÑ\8bма Ñ\83онна Ñ\83Ñ\80Ñ\83ккÑ\83 ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bлгын салгыы туһан.",
+       "passwordremindertext": "Ð\9aим Ñ\8dÑ\80Ñ\8d (бадаÒ\95а Ñ\8dн Ð±Ñ\83 IP-аадÑ\8bÑ\80Ñ\8bÑ\81Ñ\82ан: $1), {{SITENAME}} ($4) Ð°Ò»Ð°Ñ\80Ñ\8bгÑ\8bн Ñ\81аҥаÑ\82Ñ\82ан Ñ\8bÑ\8bÑ\82Ñ\8bÒ¥ Ð´Ð¸Ñ\8dбиÑ\82.\n\"$2\" ÐºÑ\8bÑ\82Ñ\82ааÑ\87Ñ\87Ñ\8b Ð±Ñ\8bÑ\81Ñ\82аÑ\85 Ð°Ò»Ð°Ñ\80Ñ\8bга Ð±Ð¸Ð»Ð¸Ð³Ð¸Ð½ Ð¼Ð°Ð½Ð½Ñ\8bк: \"$3\".\nÓ¨Ñ\81кө Ð¼Ð°Ð½Ñ\8b Ñ\8dн Ñ\87аÑ\85Ñ\87Ñ\8b ÐºÓ©Ñ\80дөөбүÑ\82 Ð±Ñ\83оллаÑ\85Ñ\85Ñ\8bна, Ñ\81иÑ\81Ñ\82иÑ\8dмÑ\8dÒ\95Ñ\8d Ñ\81аҥаÑ\82Ñ\82ан ÐºÐ¸Ð¸Ñ\80Ñ\8dҥҥин Ð°Ò»Ð°Ñ\80Ñ\8bккÑ\8bн Ñ\83лаÑ\80Ñ\8bÑ\82Ñ\8bаÑ\85Ñ\85Ñ\8bн Ñ\81өп.\nÐ\91Ñ\8bÑ\81Ñ\82аÑ\85 Ð°Ò»Ð°Ñ\80Ñ\8bк {{PLURAL:$5|бииÑ\80 Ñ\85онÑ\83к|$5 Ñ\85онÑ\83к Ñ\83Ñ\81Ñ\82аÑ\82а}} Ò¯Ð»Ñ\8dлииÑ\80.\n\nÓ¨Ñ\81көÑ\82үн Ð°Ò»Ð°Ñ\80Ñ\8bгÑ\8b Ñ\81аҥаÑ\82Ñ\82ан ÐºÓ©Ñ\80дөөбөÑ\82Ó©Ñ\85 Ð±Ñ\83оллаÑ\85Ñ\85Ñ\8bна,\nÑ\8dбÑ\8dÑ\82Ñ\8dÑ\80 Ñ\83Ñ\80Ñ\83ккÑ\83 Ð°Ò»Ð°Ñ\80Ñ\8bккн Ó©Ð¹Ð´Ó©Ó©Ð½ ÐºÑ\8dлбиÑ\82 Ð±Ñ\83оллаÑ\85Ñ\85Ñ\8bна,\nбÑ\83 Ñ\81Ñ\83Ñ\80Ñ\83гÑ\83 Ð°Ð°Ñ\85Ñ\85айÑ\8bма Ñ\83онна Ñ\83Ñ\80Ñ\83ккÑ\83 Ð°Ò»Ð°Ñ\80Ñ\8bккын салгыы туһан.",
        "noemail": "\"$1\" ааттаах киһиэхэ эл. почтата ыйыллыбатах.",
        "noemailcreate": "Электроннай почтаҥ сөптөөх аадырыһын суруйуохтааххын",
-       "passwordsent": "Саҥа ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bл \"$1\" Ñ\8dл. Ð¿Ð¾Ñ\87Ñ\82аÑ\82Ñ\8bгаÑ\80 Ñ\8bÑ\8bÑ\82Ñ\8bлÑ\8bнна.\nСиÑ\81Ñ\82емаÒ\95а Ñ\81аҥа ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bлÑ\8b Ñ\82Ñ\83һанан ÐºÐ¸Ð¸Ñ\80.",
+       "passwordsent": "Саҥа Ð°Ò»Ð°Ñ\80Ñ\8bк Ñ\82Ñ\8bл \"$1\" Ñ\8dл. Ð¿Ð¾Ñ\87Ñ\82аÑ\82Ñ\8bгаÑ\80 Ñ\8bÑ\8bÑ\82Ñ\8bлÑ\8bнна.\nТиһиккÑ\8d ÐºÐ¸Ð¸Ñ\80Ñ\8dÑ\80гÑ\8d Ñ\81аҥа Ð°Ò»Ð°Ñ\80Ñ\8bгÑ\8b Ñ\82Ñ\83һан.",
        "blocked-mailpassword": "Эн IP аадырыскыттан манна тугу эмэ уларытар бобуллубут,\nонон киирии тылы өйдөтөр кыах эмиэ суох.",
        "eauthentsent": "Эл. почтаҕар сурук ыытылынна.\nБу аадырыс эйиэнэ буоларын бигэргэтэргэ өссө тугу гыныахтааҕыҥ туһунан сурукка кэпсэниллэр.",
        "throttled-mailpassword": "Киирии тылы өйдөтөр тэрил бүтэһик {{PLURAL:$1|чаас|$1 чаас}} иһигэр туттулла сылдьыбыт.\nКөмүскэнэр соруктан сылтаан киирии тылы {{PLURAL:$1|чааска|$1 чааска}} биирдэ эрэ ыйытыахха сөп.",
        "resetpass_announce": "Түмүктүүргэ саҥа киирии тылла суруй.",
        "resetpass_text": "<!-- Тиэкиһи манна эбэн суруйуҥ -->",
        "resetpass_header": "Аат киирии тылын уларытыы",
-       "oldpassword": "ЭÑ\80гÑ\8d ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bл:",
-       "newpassword": "Саҥа ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bл:",
+       "oldpassword": "ЭÑ\80гÑ\8d Ð°Ò»Ð°Ñ\80Ñ\8bк:",
+       "newpassword": "Саҥа Ð°Ò»Ð°Ñ\80Ñ\8bк:",
        "retypenew": "Саҥа киирии тылы хатылаа:",
        "resetpass_submit": "Киирии тылы уларыт уонна киир",
        "changepassword-success": "Киирии тылыҥ этэҥҥэ уларыйда!",
        "resetpass-no-info": "Ааккын билиһиннэрдэххинэ эрэ бу сирэйгэ быһа тиийиэххин сөп.",
        "resetpass-submit-loggedin": "Киирии тылы уларытыы",
        "resetpass-submit-cancel": "Салҕаама",
-       "resetpass-wrong-oldpass": "Ð\9aииÑ\80ии Ñ\82Ñ\8bл Ñ\81өп Ñ\82үбÑ\8dÑ\81пÑ\8dÑ\82Ñ\8d.\nÐ\91аÒ\95аÑ\80 Ñ\83лаÑ\80Ñ\8bппÑ\8bÑ\82Ñ\8bÒ¥ Ð±Ñ\83олÑ\83о Ñ\8dбÑ\8dÑ\82Ñ\8dÑ\80 Ð±Ñ\8bÑ\81Ñ\82аÑ\85 ÐºÑ\8dмҥÑ\8d Ñ\82Ñ\83Ñ\82Ñ\82Ñ\83ллаÑ\80 ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bлы оҥотторбутуҥ буолуо.",
+       "resetpass-wrong-oldpass": "Ð\90һаÑ\80Ñ\8bк Ñ\81өп Ñ\82үбÑ\8dÑ\81пÑ\8dÑ\82Ñ\8d.\nÐ\91аÒ\95аÑ\80 Ñ\83лаÑ\80Ñ\8bппÑ\8bÑ\82Ñ\8bÒ¥ Ñ\8dбÑ\8dÑ\82Ñ\8dÑ\80 Ð±Ñ\8bÑ\81Ñ\82аÑ\85 ÐºÑ\8dмҥÑ\8d Ñ\82Ñ\83Ñ\82Ñ\82Ñ\83ллаÑ\80 Ð°Ò»Ð°Ñ\80Ñ\8bгы оҥотторбутуҥ буолуо.",
        "resetpass-recycled": "Бука диэн, билиҥҥи киирии тылтан атыны суруй.",
        "resetpass-temp-emailed": "Быстах кэмҥэ туттуллар киирии тылынан киирдиҥ.\nТүмүктүүргэ саҥа киирии тылы суруйуохтааххын:",
-       "resetpass-temp-password": "Ð\91Ñ\8bÑ\81Ñ\82аÑ\85 ÐºÑ\8dмҥÑ\8d Ñ\82Ñ\83Ñ\82Ñ\82Ñ\83ллаÑ\80 ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bл:",
+       "resetpass-temp-password": "Ð\91Ñ\8bÑ\81Ñ\82аÑ\85 ÐºÑ\8dмҥÑ\8d Ñ\82Ñ\83Ñ\82Ñ\82Ñ\83ллаÑ\80 Ð°Ò»Ð°Ñ\80Ñ\8bк:",
        "resetpass-abort-generic": "Киирии тылы уларытыыны кэҥэтии тохтотто.",
        "resetpass-expired": "Киирии тылыҥ болдьоҕо ааспыт эбит. Бука диэн, саҥа киирии тылла туруорун.",
        "resetpass-expired-soft": "Киирии тылыҥ болдьоҕо бүппүт, онон уларытыллыахтаах эбит. Бука диэн атын киирии тылы суруй эбэтэр маня баттаан кэлин киллэрээр \"{{int:authprovider-resetpass-skip-label}}\".",
        "passwordreset-emailtitle": "{{SITENAME}} бырайыакка аатын туһунан",
        "passwordreset-emailtext-ip": "Ким эрэ (баҕар эн буолуо, бу IP-ттан $1)  {{SITENAME}} ($4) бырайыакка киирии тылы уларытар туһунан ыйытык биэрбит.\nБу электрон аадырыһы кытта бу {{PLURAL:$3|аат ситимнээх|ааттар ситимнээхтэр}}:\n\n$2\n\nБу быстах кэмҥэ аналлаах {{PLURAL:$3|киирии тыл|кирии тыллар}} {{PLURAL:$5|биир күн үлэлиэҕэ|$5 күн үлэлиэхтэрэ}}.\nЭн тиһиликкэ ааккын этэн саҥа киирии тылы киллэриэхтээххин.\nӨскө бу ыйытыгы ыыппатах буоллаххына, эбэтэр урукку киирии тылгын өйдөөн кэлбит буоллаххына \nбу биллэриини ааххайыа суоххун сөп.\nОччоҕо урукку киирии тылыҥ оннунан хаалыа.",
        "passwordreset-emailtext-user": "$1 диэн кыттааччы  {{SITENAME}} ($4) бырайыакка киирии тылгын уларытар туһунан ыйытык ыыппыт.\nБу электрон аадырыһы кытта бу {{PLURAL:$3|аат ситимнээх|ааттар ситимнээхтэр}}\n\n$2\n\nБу быстах кэмҥэ аналлаах {{PLURAL:$3|киирии тыл|кирии тыллар}} {{PLURAL:$5|биир күн үлэлиэҕэ|$5 күн үлэлиэхтэрэ}}.\nЭн тиһиликкэ ааккын этэн саҥа киирии тылы киллэриэхтээххин.\nӨскө бу ыйытыгы ыыппатах буоллаххына, эбэтэр урукку киирии тылгын өйдөөн кэлбит буоллаххына \nбу биллэриини ааххайыа суоххун сөп.\nОччоҕо урукку киирии тылыҥ оннунан хаалыа.",
-       "passwordreset-emailelement": "Ð\9aÑ\8bÑ\82Ñ\82ааÑ\87Ñ\87Ñ\8b: \n$1\n\nÐ\91Ñ\8bÑ\81Ñ\82аÑ\85 ÐºÐ¸Ð¸Ñ\80ии тыл: \n$2",
+       "passwordreset-emailelement": "Ð\9aÑ\8bÑ\82Ñ\82ааÑ\87Ñ\87Ñ\8b: \n$1\n\nÐ\91Ñ\8bÑ\81Ñ\82аÑ\85 Ð°Ò»Ð°Ñ\80Ñ\8bк тыл: \n$2",
        "passwordreset-emailsentemail": "Өскө бу Эн ааккар баайыллыбыт аадырыс буоллаҕына, аһарык тылы уларытар туһунан сурук барыа.",
        "passwordreset-emailsentusername": "Өскө бу аакка баайыллыбыт аадырыс баар буоллаҕына, аһарык тылы уларытар туһунан сурук онно барыа.",
-       "passwordreset-emailsent-capture": "Киирии тылы уларытар туһунан сурук аллара эмиэ көрдөрүлүннэ.",
-       "passwordreset-emailerror-capture": "Манна киирии тылы уларытар туһунан сурук көрдөрүлүннэ. Ол эрэн сурук бу төрүөттэн $2 кыттааччыга сатаан барбата: $1",
        "changeemail": "Аадырыһы уларытыы уонна сотуу",
        "changeemail-header": "Бу форманы толорон аадырыскын уларыт. Уларытыыны бигэргэтэргэ аһарыккын киллэриэхтээххин. Почтаҥ аадырыһыттан бэлиэ-ааккыттан араарыаххын баҕарар буоллаххына аадырыһы сотон баран бигэргэтэн кэбиһээр.",
-       "changeemail-passwordrequired": "Бу дьайыыны бигэргэтэргэ аһарык тылгын киллэриэхтээххин.",
        "changeemail-no-info": "Бу сирэйгэ чопчу тиийэргэ, тиһиликкэ бэлиэтэммит ааккын этиэхтиэххин.",
        "changeemail-oldemail": "Билиҥҥи аадырыс:",
        "changeemail-newemail": "Саҥа аадырыс:",
        "loginreqtitle": "Бэйэҕин билиһиннэр",
        "loginreqlink": "Ааккын эт",
        "loginreqpagetext": "Атын сирэйдэри көрөргө маны оҥоруохтааххын: $1.",
-       "accmailtitle": "Ð\9aииÑ\80ии Ñ\82Ñ\8bл ыытылынна.",
-       "accmailtext": "[[User talk:$1|$1]] ÐºÑ\8bÑ\82Ñ\82ааÑ\87Ñ\87Ñ\8bга Ñ\82үбÑ\8dÑ\81пиÑ\87Ñ\87Ñ\8d Ð±Ñ\8dлиÑ\8dлÑ\8dÑ\80Ñ\82Ñ\8dн Ð¾Ò¥Ð¾Ò»Ñ\83ллÑ\83бÑ\83Ñ\82 ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bл Ð±Ñ\83 Ð°Ð°Ð´Ñ\8bÑ\80Ñ\8bÑ\81ка $2 Ñ\8bÑ\8bÑ\82Ñ\8bлÑ\8bнна.\nТиһиккÑ\8d Ð±Ñ\8dлиÑ\8dÑ\82Ñ\8dнÑ\8dн Ð±Ð°Ñ\80ан ÐºÐ¸Ð¸Ñ\80ии Ñ\82Ñ\8bлгын ''[[Special:ChangePassword|уларытыаххын]]'' сөп.",
+       "accmailtitle": "Ð\90һаÑ\80Ñ\8bк ыытылынна.",
+       "accmailtext": "[[User talk:$1|$1]] ÐºÑ\8bÑ\82Ñ\82ааÑ\87Ñ\87Ñ\8bга Ñ\82үбÑ\8dÑ\81пиÑ\87Ñ\87Ñ\8d Ð±Ñ\8dлиÑ\8dлÑ\8dÑ\80Ñ\82Ñ\8dн Ð¾Ò¥Ð¾Ò»Ñ\83ллÑ\83бÑ\83Ñ\82 Ð°Ò»Ð°Ñ\80Ñ\8bк Ñ\82Ñ\8bл Ð±Ñ\83 Ð°Ð°Ð´Ñ\8bÑ\80Ñ\8bÑ\81ка $2 Ñ\8bÑ\8bÑ\82Ñ\8bлÑ\8bнна.\nТиһиккÑ\8d Ð±Ñ\8dлиÑ\8dÑ\82Ñ\8dнÑ\8dн Ð±Ð°Ñ\80ан Ð°Ò»Ð°Ñ\80Ñ\8bккын ''[[Special:ChangePassword|уларытыаххын]]'' сөп.",
        "newarticle": "(Саҥа ыстатыйа)",
        "newarticletext": "Эн суох сирэйгэ киирэ сатаатыҥ.\nМаннык ааттаах саҥа ыстатыйаны оҥорор буоллаххына, аллара баар түннүккэ суруй\n(сиһ. [$1 көмөнү] көрүөххүн сөп).\nӨскө манна сыыһа киирбит буоллаххына интэриниэтиҥ бырагыраамматын \"төнүн\" диэххин сөп.",
        "anontalkpagetext": "----''Бу аатын эппэтэх кыттааччы ырытар сирэйэ.\nIP-аадырыһа эрэ көстөр.\nБиир IP-аадырыс хас да киһиэхэ бэриллиэн сөп. Өскө атын киһиэхэ суруллубут суругу алҕас туппут буоллаххына, бэйэҥ [[Special:CreateAccount|ааккын билиһиннэр]] эбэтэр [[Special:UserLogin|киир]], оччоҕо кэлин да булкуур тахсыа суоҕа.''",
        "undo-nochange": "Бу уларытыы хайыы-үйэ сотуллубут курдук.",
        "undo-summary": "[[Special:Contributions/$2|$2]] кыттааччы ([[User talk:$2|ырытыы]] | [[Special:Contributions/$2|{{MediaWiki:Contribslink}}]]) $1 нүөмэрдээх уларытыытын сотон оннугар түһэрэргэ.",
        "undo-summary-username-hidden": "Кистэммит кыттааччы $1 уларытыытын төннөр",
-       "cantcreateaccounttitle": "Саҥа ааты киллэрэр сатаммат",
        "cantcreateaccount-text": "[[User:$3|$3]] кыттааччы бу IP-ттан ('''$1''') саҥа бэлиэтэниини бопто.\n\nБыһаарыыта: $3 - ''$2''",
        "cantcreateaccount-range-text": "Бу IP-диапазонтан <strong>$1</strong> ааты бэлиэтиири [[User:$3|$3]] боппут. Эн IP-аадырыһыҥ (<strong>$4</strong>) онно киирсэр эбит. \n\nЫйыллыбыт төрүөтэ: $2.",
        "viewpagelogs": "Бу сирэй сурунаалларын көрүү",
        "mw-widgets-dateinput-no-date": "Күнэ-дьыла ыйыллыбатах",
        "mw-widgets-titleinput-description-new-page": "сирэй суох эбит",
        "mw-widgets-titleinput-description-redirect": "манна $1 утаарыы",
-       "api-error-blacklisted": "Бука диэн өйдөнөр аатта тал дуу.",
        "randomrootpage": "Түбэһиэх төрүт сирэй."
 }
index 2ac715d..ea5f273 100644 (file)
        "sp-contributions-search": "تلاش برائے مساہمات",
        "sp-contributions-username": "آئی.پی پتہ یا اسمِ صارف:",
        "sp-contributions-toponly": "صرف حالیہ ترین نظرثانی ترمیمات دِکھاؤ",
+       "sp-contributions-hideminor": "معمولی ترامیم چھپائیں",
        "sp-contributions-submit": "تلاش",
        "whatlinkshere": "ادھر کونسا ربط ہے",
        "whatlinkshere-title": "\"$1\" سے مربوط صفحات",
index e58564c..0b01858 100644 (file)
        "unblock": "解除封鎖使用者",
        "blockip": "封鎖{{GENDER:$1|使用者}}",
        "blockip-legend": "封鎖使用者",
-       "blockiptext": "填寫以下表單可封鎖特定 IP 位址或使用者名稱的存取權限。\n這個動作應用來避免破壞行為,可根據 [[{{MediaWiki:Policy-url}}|管理政策]]。\n請在下方填寫一個具體的原因 (例如:引述一段破壞頁面的事實)。\n您可以使用 [https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing CIDR] 語法格式封鎖 IP 範圍,最大允許的範圍 IPv4 為 /$1、IPv6 為 /$2。",
+       "blockiptext": "填寫以下表單可封鎖特定 IP 位址或使用者的編輯權限。\n只有為了防止破壞,並符合[[{{MediaWiki:Policy-url}}|方針或政策]]的情況下方可採取此行動。\n請在下方填寫一個具體的原因(例如:引述一個被破壞的頁面)。\n您可以使用[//zh.wikipedia.org/wiki/无类别域间路由 CIDR]語法格式封鎖 IP 範圍,最大允許的範圍 IPv4 為 /$1、IPv6 為 /$2。",
        "ipaddressorusername": "IP 位址或使用者名稱:",
        "ipbexpiry": "期限:",
        "ipbreason": "原因:",
        "ipbreason-dropdown": "*常見的封鎖原因\n** 填寫不實資訊\n** 刪除頁面內容\n** 散佈外部廣告連結\n** 在頁面填寫無意義文字\n** 無禮的行為、攻擊/騷擾別人\n** 濫用多個帳號\n** 使用不受歡迎的使用者名稱",
        "ipb-hardblock": "禁止使用此 IP 位址登入的使用者編輯",
-       "ipbcreateaccount": "é\98²æ­¢å¸³è\99\9f建ç«\8b",
+       "ipbcreateaccount": "é\98²æ­¢å»ºç«\8bæ\96°å¸³è\99\9f",
        "ipbemailban": "禁止使用者傳送電子郵件",
        "ipbenableautoblock": "自動封鎖此使用者最後使用的 IP 位址,以及所有之後嘗試編輯使用的 IP 位址",
        "ipbsubmit": "封鎖此使用者",
        "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",
        "ipbhidename": "在編輯及清單中隱藏使用者名稱",
        "ipbwatchuser": "監視這位使用者的使用者頁面及其對話頁面",
-       "ipb-disableusertalk": "é\98²æ­¢æ­¤ä½¿ç\94¨è\80\85å\9c¨å°\81æ\9c\9fé\96\93編輯ä»\96自己的對話頁面",
+       "ipb-disableusertalk": "é\98»æ­¢æ­¤ä½¿ç\94¨è\80\85å\9c¨å°\81ç¦\81æ\9c\9fé\96\93編輯自己的對話頁面",
        "ipb-change-block": "使用現有設定重新封鎖使用者",
        "ipb-confirm": "確認封鎖",
        "badipaddress": "無效的 IP 位址",
index 3a5b002..cfaaf5f 100644 (file)
@@ -979,7 +979,6 @@ return [
                ],
                'dependencies' => [
                        'jquery.footHovzer',
-                       'jquery.tipsy',
                ],
                'position' => 'bottom',
        ],
@@ -1090,6 +1089,15 @@ return [
                ],
                'targets' => [ 'desktop', 'mobile' ],
        ],
+       'mediawiki.htmlform.ooui' => [
+               'scripts' => [
+                       'resources/src/mediawiki/htmlform/htmlform.Element.js',
+               ],
+               'dependencies' => [
+                       'oojs-ui-core',
+               ],
+               'targets' => [ 'desktop', 'mobile' ],
+       ],
        'mediawiki.htmlform.styles' => [
                'styles' => 'resources/src/mediawiki/htmlform/styles.css',
                'position' => 'top',
index 501e898..1edb9f2 100644 (file)
                                        }
 
                                } else if ( $collapsible.parent().is( 'li' ) &&
-                                       $collapsible.parent().children( '.mw-collapsible' ).size() === 1
+                                       $collapsible.parent().children( '.mw-collapsible' ).size() === 1 &&
+                                       $collapsible.find( '> .mw-collapsible-toggle' ).size() === 0
                                ) {
                                        // special case of one collapsible in <li> tag
                                        $toggleLink = buildDefaultToggleLink();
index 7b7ef3d..86018a4 100644 (file)
                border-radius: 0.1em;
                line-height: 1.275em;
                background-color: #fff;
+
+               > .oo-ui-labelElement-label {
+                       padding: 0;
+               }
        }
 
        &.oo-ui-indicatorElement .mw-widget-dateInputWidget-handle > .oo-ui-indicatorElement-indicator {
index f77e367..8efbc69 100644 (file)
@@ -11,7 +11,7 @@
                if ( $oouiNodes.length ) {
                        // The modules are preloaded (added server-side in HTMLFormField, and the individual fields
                        // which need extra ones), but this module doesn't depend on them. Wait until they're loaded.
-                       modules = [ 'oojs-ui-core' ];
+                       modules = [ 'mediawiki.htmlform.ooui' ];
                        if ( $oouiNodes.filter( '.mw-htmlform-field-HTMLTitleTextField' ).length ) {
                                // FIXME: TitleInputWidget should be in its own module
                                modules.push( 'mediawiki.widgets' );
index f739746..6460ed1 100644 (file)
@@ -4,6 +4,8 @@
  */
 ( function ( mw, $ ) {
 
+       /*jshint -W024*/
+
        /**
         * Helper function for hide-if to find the nearby form field.
         *
         * @private
         * @param {jQuery} $el
         * @param {string} name
-        * @return {jQuery|null}
+        * @return {jQuery|OO.ui.Widget|null}
         */
        function hideIfGetField( $el, name ) {
-               var $found, $p,
+               var $found, $p, $widget,
                        suffix = name.replace( /^([^\[]+)/, '[$1]' );
 
                function nameFilter() {
                for ( $p = $el.parent(); $p.length > 0; $p = $p.parent() ) {
                        $found = $p.find( '[name]' ).filter( nameFilter );
                        if ( $found.length ) {
+                               $widget = $found.closest( '.oo-ui-widget[data-ooui]' );
+                               if ( $widget.length ) {
+                                       return OO.ui.Widget.static.infuse( $widget );
+                               }
                                return $found;
                        }
                }
         * @param {jQuery} $el
         * @param {Array} spec
         * @return {Array}
-        * @return {jQuery} return.0 Dependent fields
+        * @return {Array} return.0 Dependent fields, array of jQuery objects or OO.ui.Widgets
         * @return {Function} return.1 Test function
         */
        function hideIfParse( $el, spec ) {
-               var op, i, l, v, $field, $fields, fields, func, funcs, getVal;
+               var op, i, l, v, field, $field, fields, func, funcs, getVal;
 
                op = spec[ 0 ];
                l = spec.length;
                                                throw new Error( op + ' parameters must be arrays' );
                                        }
                                        v = hideIfParse( $el, spec[ i ] );
-                                       fields = fields.concat( v[ 0 ].toArray() );
+                                       fields = fields.concat( v[ 0 ] );
                                        funcs.push( v[ 1 ] );
                                }
-                               $fields = $( fields );
 
                                l = funcs.length;
                                switch ( op ) {
                                                break;
                                }
 
-                               return [ $fields, func ];
+                               return [ fields, func ];
 
                        case 'NOT':
                                if ( l !== 2 ) {
                                        throw new Error( 'NOT parameters must be arrays' );
                                }
                                v = hideIfParse( $el, spec[ 1 ] );
-                               $fields = v[ 0 ];
+                               fields = v[ 0 ];
                                func = v[ 1 ];
-                               return [ $fields, function () {
+                               return [ fields, function () {
                                        return !func();
                                } ];
 
                                if ( l !== 3 ) {
                                        throw new Error( op + ' takes exactly two parameters' );
                                }
-                               $field = hideIfGetField( $el, spec[ 1 ] );
-                               if ( !$field ) {
-                                       return [ $(), function () {
+                               field = hideIfGetField( $el, spec[ 1 ] );
+                               if ( !field ) {
+                                       return [ [], function () {
                                                return false;
                                        } ];
                                }
                                v = spec[ 2 ];
 
-                               if ( $field.first().prop( 'type' ) === 'radio' ||
-                                       $field.first().prop( 'type' ) === 'checkbox'
-                               ) {
-                                       getVal = function () {
-                                               var $selected = $field.filter( ':checked' );
-                                               return $selected.length ? $selected.val() : '';
-                                       };
+                               if ( field instanceof OO.ui.Widget ) {
+                                       if ( field.supports( 'isSelected' ) ) {
+                                               getVal = function () {
+                                                       var selected = field.isSelected();
+                                                       return selected ? field.getValue() : '';
+                                               };
+                                       } else {
+                                               getVal = function () {
+                                                       return field.getValue();
+                                               };
+                                       }
                                } else {
-                                       getVal = function () {
-                                               return $field.val();
-                                       };
+                                       $field = $( field );
+                                       if ( $field.prop( 'type' ) === 'radio' || $field.prop( 'type' ) === 'checkbox' ) {
+                                               getVal = function () {
+                                                       var $selected = $field.filter( ':checked' );
+                                                       return $selected.length ? $selected.val() : '';
+                                               };
+                                       } else {
+                                               getVal = function () {
+                                                       return $field.val();
+                                               };
+                                       }
                                }
 
                                switch ( op ) {
                                                break;
                                }
 
-                               return [ $field, func ];
+                               return [ [ field ], func ];
 
                        default:
                                throw new Error( 'Unrecognized operation \'' + op + '\'' );
 
        mw.hook( 'htmlform.enhance' ).add( function ( $root ) {
                $root.find( '.mw-htmlform-hide-if' ).each( function () {
-                       var v, $fields, test, func,
-                               $el = $( this ),
-                               spec = $el.data( 'hideIf' );
+                       var v, i, fields, test, func, spec, self, modules,
+                               $el = $( this );
 
-                       if ( !spec ) {
-                               return;
+                       modules = [];
+                       if ( $el.is( '[data-ooui]' ) ) {
+                               modules.push( 'mediawiki.htmlform.ooui' );
+                               if ( $el.filter( '.mw-htmlform-field-HTMLTitleTextField' ).length ) {
+                                       // FIXME: TitleInputWidget should be in its own module
+                                       modules.push( 'mediawiki.widgets' );
+                               }
+                               if ( $el.filter( '.mw-htmlform-field-HTMLUserTextField' ).length ) {
+                                       modules.push( 'mediawiki.widgets.UserInputWidget' );
+                               }
+                               if (
+                                       $el.filter( '.mw-htmlform-field-HTMLSelectNamespace' ).length ||
+                                       $el.filter( '.mw-htmlform-field-HTMLSelectNamespaceWithButton' ).length
+                               ) {
+                                       // FIXME: NamespaceInputWidget should be in its own module (probably?)
+                                       modules.push( 'mediawiki.widgets' );
+                               }
                        }
 
-                       v = hideIfParse( $el, spec );
-                       $fields = v[ 0 ];
-                       test = v[ 1 ];
-                       func = function () {
-                               if ( test() ) {
-                                       $el.hide();
+                       mw.loader.using( modules ).done( function () {
+                               if ( $el.is( '[data-ooui]' ) ) {
+                                       // self should be a FieldLayout that mixes in mw.htmlform.Element
+                                       self = OO.ui.FieldLayout.static.infuse( $el );
+                                       spec = self.hideIf;
+                                       // The original element has been replaced with infused one
+                                       $el = self.$element;
                                } else {
-                                       $el.show();
+                                       self = $el;
+                                       spec = $el.data( 'hideIf' );
+                               }
+
+                               if ( !spec ) {
+                                       return;
+                               }
+
+                               v = hideIfParse( $el, spec );
+                               fields = v[ 0 ];
+                               test = v[ 1 ];
+                               // The .toggle() method works mostly the same for jQuery objects and OO.ui.Widget
+                               func = function () {
+                                       self.toggle( !test() );
+                               };
+                               for ( i = 0; i < fields.length; i++ ) {
+                                       // The .on() method works mostly the same for jQuery objects and OO.ui.Widget
+                                       fields[ i ].on( 'change', func );
                                }
-                       };
-                       $fields.on( 'change', func );
-                       func();
+                               func();
+                       } );
                } );
        } );
 
diff --git a/resources/src/mediawiki/htmlform/htmlform.Element.js b/resources/src/mediawiki/htmlform/htmlform.Element.js
new file mode 100644 (file)
index 0000000..37474f6
--- /dev/null
@@ -0,0 +1,45 @@
+( function ( mw ) {
+
+       mw.htmlform = {};
+
+       /**
+        * Allows custom data specific to HTMLFormField to be set for OOjs UI forms. This picks up the
+        * extra config from a matching PHP widget (defined in HTMLFormElement.php) when constructed using
+        * OO.ui.infuse().
+        *
+        * Currently only supports passing 'hide-if' data.
+        *
+        * @ignore
+        */
+       mw.htmlform.Element = function ( config ) {
+               // Configuration initialization
+               config = config || {};
+
+               // Properties
+               this.hideIf = config.hideIf;
+
+               // Initialization
+               if ( this.hideIf ) {
+                       this.$element.addClass( 'mw-htmlform-hide-if' );
+               }
+       };
+
+       mw.htmlform.FieldLayout = function ( config ) {
+               // Parent constructor
+               mw.htmlform.FieldLayout.parent.call( this, config );
+               // Mixin constructors
+               mw.htmlform.Element.call( this, config );
+       };
+       OO.inheritClass( mw.htmlform.FieldLayout, OO.ui.FieldLayout );
+       OO.mixinClass( mw.htmlform.FieldLayout, mw.htmlform.Element );
+
+       mw.htmlform.ActionFieldLayout = function ( config ) {
+               // Parent constructor
+               mw.htmlform.ActionFieldLayout.parent.call( this, config );
+               // Mixin constructors
+               mw.htmlform.Element.call( this, config );
+       };
+       OO.inheritClass( mw.htmlform.ActionFieldLayout, OO.ui.ActionFieldLayout );
+       OO.mixinClass( mw.htmlform.ActionFieldLayout, mw.htmlform.Element );
+
+}( mediaWiki ) );