Merge "Test ApiDisabled.php"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 21 Mar 2018 17:04:20 +0000 (17:04 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 21 Mar 2018 17:04:20 +0000 (17:04 +0000)
44 files changed:
RELEASE-NOTES-1.31
autoload.php
includes/htmlform/fields/HTMLSizeFilterField.php
includes/libs/rdbms/database/DBConnRef.php
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/database/DatabaseMssql.php
includes/libs/rdbms/database/DatabaseMysqlBase.php
includes/libs/rdbms/database/DatabasePostgres.php
includes/libs/rdbms/database/IDatabase.php
includes/libs/rdbms/encasing/Subquery.php [new file with mode: 0644]
includes/resourceloader/ResourceLoaderClientHtml.php
languages/i18n/ar.json
languages/i18n/be-tarask.json
languages/i18n/bs.json
languages/i18n/ckb.json
languages/i18n/de.json
languages/i18n/es.json
languages/i18n/fr.json
languages/i18n/he.json
languages/i18n/hr.json
languages/i18n/hu.json
languages/i18n/io.json
languages/i18n/it.json
languages/i18n/nds-nl.json
languages/i18n/nn.json
languages/i18n/sr-ec.json
languages/i18n/th.json
package.json
tests/integration/includes/http/CurlHttpRequestTest.php
tests/integration/includes/http/PhpHttpRequestTest.php
tests/integration/includes/shell/FirejailCommandTest.php
tests/parser/parserTests.txt
tests/phpunit/includes/api/ApiQueryWatchlistIntegrationTest.php
tests/phpunit/includes/http/HttpTest.php
tests/phpunit/includes/import/ImportLinkCacheIntegrationTest.php
tests/phpunit/includes/libs/rdbms/database/DatabaseSQLTest.php
tests/phpunit/includes/parser/ParserIntegrationTest.php
tests/phpunit/includes/rcfeed/RCFeedIntegrationTest.php
tests/selenium/pageobjects/createaccount.page.js
tests/selenium/pageobjects/delete.page.js
tests/selenium/pageobjects/edit.page.js
tests/selenium/pageobjects/page.js
tests/selenium/pageobjects/restore.page.js
tests/selenium/wdio.conf.jenkins.js

index e5226ec..899f8b3 100644 (file)
@@ -297,6 +297,11 @@ changes to languages because of Phabricator reports.
   wikitext table captions, wikitext table headings, wikitext table cells. HTML
   headings, HTML list items, HTML table captions, HTML table headings, HTML table cells
   will not have this trimming behavior.
+* Calling Database::begin() explicitly during an implicit transaction or when DBO_TRX
+  is set results in an exception. Calling Database::commit() explicitly for an implicit
+  transaction also results in an exception. Previously these were logged as errors.
+  The startAtomic() and endAtomic() methods, or AtomicSectionUpdate should be used
+  instead.
 
 == Compatibility ==
 MediaWiki 1.31 requires PHP 5.5.9 or later. Although HHVM 3.18.5 or later is supported,
index b5f3e4a..6386a5e 100644 (file)
@@ -1727,6 +1727,7 @@ $wgAutoloadLocalClasses = [
        'Wikimedia\\Rdbms\\SQLiteField' => __DIR__ . '/includes/libs/rdbms/field/SQLiteField.php',
        'Wikimedia\\Rdbms\\SavepointPostgres' => __DIR__ . '/includes/libs/rdbms/database/utils/SavepointPostgres.php',
        'Wikimedia\\Rdbms\\SessionConsistentConnectionManager' => __DIR__ . '/includes/libs/rdbms/connectionmanager/SessionConsistentConnectionManager.php',
+       'Wikimedia\\Rdbms\\Subquery' => __DIR__ . '/includes/libs/rdbms/encasing/Subquery.php',
        'Wikimedia\\Rdbms\\TransactionProfiler' => __DIR__ . '/includes/libs/rdbms/TransactionProfiler.php',
        'WikitextContent' => __DIR__ . '/includes/content/WikitextContent.php',
        'WikitextContentHandler' => __DIR__ . '/includes/content/WikitextContentHandler.php',
index 5ad7ee3..145a0ec 100644 (file)
@@ -41,9 +41,26 @@ class HTMLSizeFilterField extends HTMLIntField {
                return $html;
        }
 
-       // No OOUI yet
-       public function getInputOOUI( $value ) {
-               return false;
+       protected function getInputWidget( $params ) {
+               $this->mParent->getOutput()->addModuleStyles( 'mediawiki.widgets.SizeFilterWidget.styles' );
+
+               // negative numbers represent "max", positive numbers represent "min"
+               $value = $params['value'];
+
+               $params['value'] = $value ? abs( $value ) : '';
+
+               return new MediaWiki\Widget\SizeFilterWidget( [
+                       'selectMin' => $value >= 0,
+                       'textinput' => $params,
+                       'radioselectinput' => [
+                               'name' => $this->mName . '-mode',
+                               'disabled' => !empty( $this->mParams['disabled'] ),
+                       ],
+               ] );
+       }
+
+       protected function getOOUIModules() {
+               return [ 'mediawiki.widgets.SizeFilterWidget' ];
        }
 
        /**
index 6726aea..1f8e56c 100644 (file)
@@ -362,6 +362,13 @@ class DBConnRef implements IDatabase {
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
+       public function buildSelectSubquery(
+               $table, $vars, $conds = '', $fname = __METHOD__,
+               $options = [], $join_conds = []
+       ) {
+               return $this->__call( __FUNCTION__, func_get_args() );
+       }
+
        public function databasesAreIndependent() {
                return $this->__call( __FUNCTION__, func_get_args() );
        }
index 2d90be6..00bc1cb 100644 (file)
@@ -1588,8 +1588,14 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        }
 
        public function estimateRowCount(
-               $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
+               $table, $var = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
        ) {
+               $conds = $this->normalizeConditions( $conds, $fname );
+               $column = $this->extractSingleFieldFromList( $var );
+               if ( is_string( $column ) && !in_array( $column, [ '*', '1' ] ) ) {
+                       $conds[] = "$column IS NOT NULL";
+               }
+
                $res = $this->select(
                        $table, [ 'rowcount' => 'COUNT(*)' ], $conds, $fname, $options, $join_conds
                );
@@ -1599,21 +1605,76 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        }
 
        public function selectRowCount(
-               $tables, $vars = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
+               $tables, $var = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
        ) {
-               $rows = 0;
-               $sql = $this->selectSQLText( $tables, '1', $conds, $fname, $options, $join_conds );
-               // The identifier quotes is primarily for MSSQL.
-               $rowCountCol = $this->addIdentifierQuotes( "rowcount" );
-               $tableName = $this->addIdentifierQuotes( "tmp_count" );
-               $res = $this->query( "SELECT COUNT(*) AS $rowCountCol FROM ($sql) $tableName", $fname );
+               $conds = $this->normalizeConditions( $conds, $fname );
+               $column = $this->extractSingleFieldFromList( $var );
+               if ( is_string( $column ) && !in_array( $column, [ '*', '1' ] ) ) {
+                       $conds[] = "$column IS NOT NULL";
+               }
+
+               $res = $this->select(
+                       [
+                               'tmp_count' => $this->buildSelectSubquery(
+                                       $tables,
+                                       '1',
+                                       $conds,
+                                       $fname,
+                                       $options,
+                                       $join_conds
+                               )
+                       ],
+                       [ 'rowcount' => 'COUNT(*)' ],
+                       [],
+                       $fname
+               );
+               $row = $res ? $this->fetchRow( $res ) : [];
+
+               return isset( $row['rowcount'] ) ? (int)$row['rowcount'] : 0;
+       }
+
+       /**
+        * @param array|string $conds
+        * @param string $fname
+        * @return array
+        */
+       final protected function normalizeConditions( $conds, $fname ) {
+               if ( $conds === null || $conds === false ) {
+                       $this->queryLogger->warning(
+                               __METHOD__
+                               . ' called from '
+                               . $fname
+                               . ' with incorrect parameters: $conds must be a string or an array'
+                       );
+                       $conds = '';
+               }
 
-               if ( $res ) {
-                       $row = $this->fetchRow( $res );
-                       $rows = ( isset( $row['rowcount'] ) ) ? (int)$row['rowcount'] : 0;
+               if ( !is_array( $conds ) ) {
+                       $conds = ( $conds === '' ) ? [] : [ $conds ];
                }
 
-               return $rows;
+               return $conds;
+       }
+
+       /**
+        * @param array|string $var Field parameter in the style of select()
+        * @return string|null Column name or null; ignores aliases
+        * @throws DBUnexpectedError Errors out if multiple columns are given
+        */
+       final protected function extractSingleFieldFromList( $var ) {
+               if ( is_array( $var ) ) {
+                       if ( !$var ) {
+                               $column = null;
+                       } elseif ( count( $var ) == 1 ) {
+                               $column = isset( $var[0] ) ? $var[0] : reset( $var );
+                       } else {
+                               throw new DBUnexpectedError( $this, __METHOD__ . ': got multiple columns.' );
+                       }
+               } else {
+                       $column = $var;
+               }
+
+               return $column;
        }
 
        /**
@@ -1963,6 +2024,15 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                return 'CAST( ' . $field . ' AS INTEGER )';
        }
 
+       public function buildSelectSubquery(
+               $table, $vars, $conds = '', $fname = __METHOD__,
+               $options = [], $join_conds = []
+       ) {
+               return new Subquery(
+                       $this->selectSQLText( $table, $vars, $conds, $fname, $options, $join_conds )
+               );
+       }
+
        public function databasesAreIndependent() {
                return false;
        }
@@ -1985,6 +2055,13 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        }
 
        public function tableName( $name, $format = 'quoted' ) {
+               if ( $name instanceof Subquery ) {
+                       throw new DBUnexpectedError(
+                               $this,
+                               __METHOD__ . ': got Subquery instance when expecting a string.'
+                       );
+               }
+
                # Skip the entire process when we have a string quoted on both ends.
                # Note that we check the end so that we will still quote any use of
                # use of `database`.table. But won't break things if someone wants
@@ -2001,6 +2078,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                # any remote case where a word like on may be inside of a table name
                # surrounded by symbols which may be considered word breaks.
                if ( preg_match( '/(^|\s)(DISTINCT|JOIN|ON|AS)(\s|$)/i', $name ) !== 0 ) {
+                       $this->queryLogger->warning(
+                               __METHOD__ . ": use of subqueries is not supported this way.",
+                               [ 'trace' => ( new RuntimeException() )->getTraceAsString() ]
+                       );
+
                        return $name;
                }
 
@@ -2105,17 +2187,32 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
 
        /**
         * Get an aliased table name
-        * e.g. tableName AS newTableName
         *
-        * @param string $name Table name, see tableName()
-        * @param string|bool $alias Alias (optional)
+        * This returns strings like "tableName AS newTableName" for aliased tables
+        * and "(SELECT * from tableA) newTablename" for subqueries (e.g. derived tables)
+        *
+        * @see Database::tableName()
+        * @param string|Subquery $table Table name or object with a 'sql' field
+        * @param string|bool $alias Table alias (optional)
         * @return string SQL name for aliased table. Will not alias a table to its own name
         */
-       protected function tableNameWithAlias( $name, $alias = false ) {
-               if ( !$alias || $alias == $name ) {
-                       return $this->tableName( $name );
+       protected function tableNameWithAlias( $table, $alias = false ) {
+               if ( is_string( $table ) ) {
+                       $quotedTable = $this->tableName( $table );
+               } elseif ( $table instanceof Subquery ) {
+                       $quotedTable = (string)$table;
+               } else {
+                       throw new InvalidArgumentException( "Table must be a string or Subquery." );
+               }
+
+               if ( !strlen( $alias ) || $alias === $table ) {
+                       if ( $table instanceof Subquery ) {
+                               throw new InvalidArgumentException( "Subquery table missing alias." );
+                       }
+
+                       return $quotedTable;
                } else {
-                       return $this->tableName( $name ) . ' ' . $this->addIdentifierQuotes( $alias );
+                       return $quotedTable . ' ' . $this->addIdentifierQuotes( $alias );
                }
        }
 
@@ -3185,16 +3282,12 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                                $msg = "$fname: Explicit transaction already active (from {$this->trxFname}).";
                                throw new DBUnexpectedError( $this, $msg );
                        } else {
-                               // @TODO: make this an exception at some point
                                $msg = "$fname: Implicit transaction already active (from {$this->trxFname}).";
-                               $this->queryLogger->error( $msg );
-                               return; // join the main transaction set
+                               throw new DBUnexpectedError( $this, $msg );
                        }
                } elseif ( $this->getFlag( self::DBO_TRX ) && $mode !== self::TRANSACTION_INTERNAL ) {
-                       // @TODO: make this an exception at some point
                        $msg = "$fname: Implicit transaction expected (DBO_TRX set).";
-                       $this->queryLogger->error( $msg );
-                       return; // let any writes be in the main transaction
+                       throw new DBUnexpectedError( $this, $msg );
                }
 
                // Avoid fatals if close() was called
@@ -3260,10 +3353,10 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                                        "$fname: No transaction to commit, something got out of sync." );
                                return; // nothing to do
                        } elseif ( $this->trxAutomatic ) {
-                               // @TODO: make this an exception at some point
-                               $msg = "$fname: Explicit commit of implicit transaction.";
-                               $this->queryLogger->error( $msg );
-                               return; // wait for the main transaction set commit round
+                               throw new DBUnexpectedError(
+                                       $this,
+                                       "$fname: Expected mass commit of all peer transactions (DBO_TRX set)."
+                               );
                        }
                }
 
@@ -3314,7 +3407,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        } elseif ( $this->getFlag( self::DBO_TRX ) ) {
                                throw new DBUnexpectedError(
                                        $this,
-                                       "$fname: Expected mass rollback of all peer databases (DBO_TRX set)."
+                                       "$fname: Expected mass rollback of all peer transactions (DBO_TRX set)."
                                );
                        }
                }
index 885880a..1f6132b 100644 (file)
@@ -505,20 +505,26 @@ class DatabaseMssql extends Database {
         * Returns -1 if count cannot be found
         * Takes same arguments as Database::select()
         * @param string $table
-        * @param string $vars
+        * @param string $var
         * @param string $conds
         * @param string $fname
         * @param array $options
         * @param array $join_conds
         * @return int
         */
-       public function estimateRowCount( $table, $vars = '*', $conds = '',
+       public function estimateRowCount( $table, $var = '*', $conds = '',
                $fname = __METHOD__, $options = [], $join_conds = []
        ) {
+               $conds = $this->normalizeConditions( $conds, $fname );
+               $column = $this->extractSingleFieldFromList( $var );
+               if ( is_string( $column ) && !in_array( $column, [ '*', '1' ] ) ) {
+                       $conds[] = "$column IS NOT NULL";
+               }
+
                // http://msdn2.microsoft.com/en-us/library/aa259203.aspx
                $options['EXPLAIN'] = true;
                $options['FOR COUNT'] = true;
-               $res = $this->select( $table, $vars, $conds, $fname, $options, $join_conds );
+               $res = $this->select( $table, $var, $conds, $fname, $options, $join_conds );
 
                $rows = -1;
                if ( $res ) {
index 7537578..c7147e4 100644 (file)
@@ -558,18 +558,24 @@ abstract class DatabaseMysqlBase extends Database {
         * Takes same arguments as Database::select()
         *
         * @param string|array $table
-        * @param string|array $vars
+        * @param string|array $var
         * @param string|array $conds
         * @param string $fname
         * @param string|array $options
         * @param array $join_conds
         * @return bool|int
         */
-       public function estimateRowCount( $table, $vars = '*', $conds = '',
+       public function estimateRowCount( $table, $var = '*', $conds = '',
                $fname = __METHOD__, $options = [], $join_conds = []
        ) {
+               $conds = $this->normalizeConditions( $conds, $fname );
+               $column = $this->extractSingleFieldFromList( $var );
+               if ( is_string( $column ) && !in_array( $column, [ '*', '1' ] ) ) {
+                       $conds[] = "$column IS NOT NULL";
+               }
+
                $options['EXPLAIN'] = true;
-               $res = $this->select( $table, $vars, $conds, $fname, $options, $join_conds );
+               $res = $this->select( $table, $var, $conds, $fname, $options, $join_conds );
                if ( $res === false ) {
                        return false;
                }
index 49c945e..13d9158 100644 (file)
@@ -409,18 +409,24 @@ class DatabasePostgres extends Database {
         * Takes same arguments as Database::select()
         *
         * @param string $table
-        * @param string $vars
+        * @param string $var
         * @param string $conds
         * @param string $fname
         * @param array $options
         * @param array $join_conds
         * @return int
         */
-       public function estimateRowCount( $table, $vars = '*', $conds = '',
+       public function estimateRowCount( $table, $var = '*', $conds = '',
                $fname = __METHOD__, $options = [], $join_conds = []
        ) {
+               $conds = $this->normalizeConditions( $conds, $fname );
+               $column = $this->extractSingleFieldFromList( $var );
+               if ( is_string( $column ) && !in_array( $column, [ '*', '1' ] ) ) {
+                       $conds[] = "$column IS NOT NULL";
+               }
+
                $options['EXPLAIN'] = true;
-               $res = $this->select( $table, $vars, $conds, $fname, $options, $join_conds );
+               $res = $this->select( $table, $var, $conds, $fname, $options, $join_conds );
                $rows = -1;
                if ( $res ) {
                        $row = $this->fetchRow( $res );
index e5e2076..a5392c8 100644 (file)
@@ -628,6 +628,11 @@ interface IDatabase {
         * This includes the user table in the query, with the alias "a" available
         * for use in field names (e.g. a.user_name).
         *
+        * A derived table, defined by the result of selectSQLText(), requires an alias
+        * key and a Subquery instance value which wraps the SQL query, for example:
+        *
+        *    [ 'c' => new Subquery( 'SELECT ...' ) ]
+        *
         * Joins using parentheses for grouping (since MediaWiki 1.31) may be
         * constructed using nested arrays. For example,
         *
@@ -777,15 +782,15 @@ interface IDatabase {
         * doing UNION queries, where the SQL text of each query is needed. In general,
         * however, callers outside of Database classes should just use select().
         *
+        * @see IDatabase::select()
+        *
         * @param string|array $table Table name
         * @param string|array $vars Field names
         * @param string|array $conds Conditions
         * @param string $fname Caller function name
         * @param string|array $options Query options
         * @param string|array $join_conds Join conditions
-        *
-        * @return string SQL query string.
-        * @see IDatabase::select()
+        * @return string SQL query string
         */
        public function selectSQLText(
                $table, $vars, $conds = '', $fname = __METHOD__,
@@ -825,7 +830,7 @@ interface IDatabase {
         * Takes the same arguments as IDatabase::select().
         *
         * @param string $table Table name
-        * @param string $vars Unused
+        * @param string $var Column for which NULL values are not counted [default "*"]
         * @param array|string $conds Filters on the table
         * @param string $fname Function name for profiling
         * @param array $options Options for select
@@ -834,7 +839,7 @@ interface IDatabase {
         * @throws DBError
         */
        public function estimateRowCount(
-               $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
+               $table, $var = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
        );
 
        /**
@@ -847,7 +852,7 @@ interface IDatabase {
         * @since 1.27 Added $join_conds parameter
         *
         * @param array|string $tables Table names
-        * @param string $vars Unused
+        * @param string $var Column for which NULL values are not counted [default "*"]
         * @param array|string $conds Filters on the table
         * @param string $fname Function name for profiling
         * @param array $options Options for select
@@ -856,7 +861,7 @@ interface IDatabase {
         * @throws DBError
         */
        public function selectRowCount(
-               $tables, $vars = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
+               $tables, $var = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
        );
 
        /**
@@ -1087,6 +1092,25 @@ interface IDatabase {
         */
        public function buildIntegerCast( $field );
 
+       /**
+        * Equivalent to IDatabase::selectSQLText() except wraps the result in Subqyery
+        *
+        * @see IDatabase::selectSQLText()
+        *
+        * @param string|array $table Table name
+        * @param string|array $vars Field names
+        * @param string|array $conds Conditions
+        * @param string $fname Caller function name
+        * @param string|array $options Query options
+        * @param string|array $join_conds Join conditions
+        * @return Subquery
+        * @since 1.31
+        */
+       public function buildSelectSubquery(
+               $table, $vars, $conds = '', $fname = __METHOD__,
+               $options = [], $join_conds = []
+       );
+
        /**
         * Returns true if DBs are assumed to be on potentially different servers
         *
diff --git a/includes/libs/rdbms/encasing/Subquery.php b/includes/libs/rdbms/encasing/Subquery.php
new file mode 100644 (file)
index 0000000..fc118d0
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/**
+ * This file deals with database interface functions
+ * and query specifics/optimisations.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Database
+ */
+
+namespace Wikimedia\Rdbms;
+
+class Subquery {
+       /** @var string */
+       private $sql;
+
+       /**
+        * @param string $sql SQL query defining the table
+        */
+       public function __construct( $sql ) {
+               $this->sql = $sql;
+       }
+
+       /**
+        * @return string Original SQL query
+        */
+       public function __toString() {
+               return '(' . $this->sql . ')';
+       }
+}
index fe9e56f..a9e2f92 100644 (file)
@@ -131,9 +131,7 @@ class ResourceLoaderClientHtml {
                                // moduleName => state
                        ],
                        'general' => [],
-                       'styles' => [
-                               // moduleName
-                       ],
+                       'styles' => [],
                        'scripts' => [],
                        // Embedding for private modules
                        'embed' => [
@@ -182,20 +180,17 @@ class ResourceLoaderClientHtml {
                        }
 
                        // Stylesheet doesn't trigger mw.loader callback.
-                       // Set "ready" state to allow dependencies and avoid duplicate requests. (T87871)
+                       // Set "ready" state to allow script modules to depend on this module  (T87871).
+                       // And to avoid duplicate requests at run-time from mw.loader.
                        $data['states'][$name] = 'ready';
 
                        $group = $module->getGroup();
                        $context = $this->getContext( $group, ResourceLoaderModule::TYPE_STYLES );
-                       if ( $module->isKnownEmpty( $context ) ) {
-                               // Avoid needless request for empty module
-                               $data['states'][$name] = 'ready';
-                       } else {
+                       // Avoid needless request for empty module
+                       if ( !$module->isKnownEmpty( $context ) ) {
                                if ( $module->shouldEmbedModule( $this->context ) ) {
                                        // Embed via style element
                                        $data['embed']['styles'][] = $name;
-                                       // Avoid duplicate request from mw.loader
-                                       $data['states'][$name] = 'ready';
                                } else {
                                        // Load from load.php?only=styles via <link rel=stylesheet>
                                        $data['styles'][] = $name;
index 6529ef4..7c1b2ce 100644 (file)
        "wrongpasswordempty": "كلمة السر المدخلة كانت فارغة.\nمن فضلك حاول مرة أخرى.",
        "passwordtooshort": "يجب أن تتكون كلمة السر على الأقل من {{PLURAL:$1|حرف واحد|حرفين|$1 حروف|$1 حرفا|$1 حرف}}.",
        "passwordtoolong": "كلمات السر لا يجب أن تكون أطول من  {{PLURAL:$1|1 حرف|$1 حروف}}.",
-       "passwordtoopopular": "Ù\83Ù\84Ù\85ات Ø§Ù\84Ù\85رÙ\88ر Ø§Ù\84شائعة Ù\84ا Ù\8aÙ\85Ù\83Ù\86 Ø§Ø³ØªØ®Ø¯Ø§Ù\85Ù\87ا. Ø¨Ø±Ø¬Ø§Ø¡ Ø§Ø®ØªÙ\8aار Ù\83Ù\84Ù\85Ø© Ù\85رÙ\88ر Ø£Ù\83ثر Ù\81رادة.",
+       "passwordtoopopular": "Ù\84ا Ù\8aÙ\85Ù\83Ù\86 Ø§Ø³ØªØ®Ø¯Ø§Ù\85 Ù\83Ù\84Ù\85ات Ø§Ù\84Ù\85رÙ\88ر Ø§Ù\84Ù\85ختارة Ø¨Ø´Ù\83Ù\84 Ø¹Ø§Ù\85; Ù\8aÙ\8fرجÙ\8eÙ\89 Ø§Ø®ØªÙ\8aار Ù\83Ù\84Ù\85Ø© Ù\85رÙ\88ر Ù\8aصعب ØªØ®Ù\85Ù\8aÙ\86Ù\87ا.",
        "password-name-match": "يجب أن تكون كلمة المرور مختلفة عن اسم المستخدم.",
        "password-login-forbidden": "تم منع استخدام اسم المستخدم هذا وكلمة السر.",
        "mailmypassword": "أعد تعيين كلمة السر",
index ef0d078..b4fb113 100644 (file)
        "wrongpasswordempty": "Быў уведзены пусты пароль. Калі ласка, паспрабуйце яшчэ раз.",
        "passwordtooshort": "Паролі павінны ўтрымліваць ня менш за $1 {{PLURAL:$1|сымбаль|сымбалі|сымбаляў}}.",
        "passwordtoolong": "Паролі ня могуць быць даўжэй за $1 {{PLURAL:$1|сымбаль|сымбалі|сымбаляў}}.",
-       "passwordtoopopular": "Ð\9dелÑ\8cга Ð²Ñ\8bкаÑ\80Ñ\8bÑ\81Ñ\82оÑ\9eваÑ\86Ñ\8c Ð¿Ñ\80оÑ\81Ñ\82Ñ\8bÑ\8f Ð¿Ð°Ñ\80олÑ\96. Ð\9aалÑ\96 Ð»Ð°Ñ\81ка, Ð°Ð±Ñ\8fÑ\80Ñ\8bÑ\86е Ð±Ð¾Ð»Ñ\8cÑ\88 Ñ\81кладанÑ\8b Ð¿Ð°Ñ\80оль.",
+       "passwordtoopopular": "Ð\9dелÑ\8cга Ð²Ñ\8bкаÑ\80Ñ\8bÑ\81Ñ\82оÑ\9eваÑ\86Ñ\8c Ð¿Ñ\80оÑ\81Ñ\82Ñ\8bÑ\8f Ð¿Ð°Ñ\80олÑ\96. Ð\9aалÑ\96 Ð»Ð°Ñ\81ка, Ð°Ð±Ñ\8fÑ\80Ñ\8bÑ\86е Ð¿Ð°Ñ\80олÑ\8c, Ñ\8fкÑ\96 Ð·Ð½Ð°Ñ\87на Ñ\86Ñ\8fжÑ\8dй Ð¿Ð°Ð´Ð°Ð±Ñ\80аÑ\86ь.",
        "password-name-match": "Ваш пароль павінен адрозьнівацца ад Вашага імя ўдзельніка.",
        "password-login-forbidden": "Выкарыстаньне гэтага імя ўдзельніка і паролю было забароненае.",
        "mailmypassword": "Скінуць пароль",
        "right-import": "Імпарт старонак зь іншых вікі",
        "right-importupload": "Імпарт старонак праз загрузку файлаў",
        "right-patrol": "Пазначэньне рэдагаваньняў як «патруляваных»",
-       "right-autopatrol": "аўтаматычнае пазначэньне рэдагаваньняў як «патруляваных»",
+       "right-autopatrol": "Ð\90ўтаматычнае пазначэньне рэдагаваньняў як «патруляваных»",
        "right-patrolmarks": "прагляд пазначэньняў пра патруляваньне ў апошніх зьменах",
        "right-unwatchedpages": "прагляд сьпісу старонак, за якімі ніхто не назірае",
        "right-mergehistory": "аб’яднаньне гісторыі старонак",
index 378d9be..5f1419d 100644 (file)
        "undo-summary-username-hidden": "Poništi izmjenu $1 od skrivenog korisnika",
        "cantcreateaccount-text": "Pravljenje korisničkog računa sa ove IP adrese ('''$1''') je blokirano od strane [[User:$3|$3]].\n\nRazlog koji je naveo $3 je ''$2''",
        "cantcreateaccount-range-text": "Pravljenje računa sa IP adresa u rasponu <strong>$1</strong>, koji uključuje i vašu IP adresu (<strong>$4</strong>), je blokirao korisnik [[User:$3|$3]].\n\nNavedeni razlog korisnika $3 je <em>$2</em>",
-       "viewpagelogs": "Pogledaj zapisnike ove stranice",
+       "viewpagelogs": "Prikaži zapisnike ove stranice",
        "nohistory": "Ne postoji historija izmjena za ovu stranicu.",
        "currentrev": "Trenutna verzija",
        "currentrev-asof": "Trenutna verzija na dan $2 u $3",
        "emailmessage": "Poruka:",
        "emailsend": "Pošalji",
        "emailccme": "Pošalji mi kopiju moje poruke e-poštom.",
-       "emailccsubject": "Kopija Vaše poruke za $1: $2",
+       "emailccsubject": "Kopija Vaše poruke korisniku/-ci $1: $2",
        "emailsent": "Poruka poslata",
        "emailsenttext": "Vaša poruka je poslata e-poštom.",
        "emailuserfooter": "Ovu e-poruku {{GENDER:$1|poslao|poslala}} je $1 {{GENDER:$2|korisniku|korisnici}} $2 pomoću funkcije \"{{int:emailuser}}\" s {{GRAMMAR:genitiv|{{SITENAME}}}}. Ako {{GENDER:$2|odgovorite}} na ovu e-poruku, {{GENDER:$2|Vaša}} će se poruka direktno poslati {{GENDER:$1|originalnom pošiljaocu|originalnoj pošiljatejici}} i otkrit ćete {{GENDER:$1|mu|joj}} {{GENDER:$2|svoju}} adresu e-pošte.",
index 27e1729..7215225 100644 (file)
        "searchrelated": "پەیوەست",
        "searchall": "ھەموو",
        "showingresults": "لە خوارەوە {{PLURAL:$1|'''یەک''' ئەنجام|'''$1''' ئەنجام}} نیشان دراوە، بە دەست پێ کردن لە ژمارەی '''$2'''ەوە.",
+       "showingresultsinrange": "لە خوارەوە زیاتر لە <strong>$1</strong> ئەنجام لە مەودای #$2 بۆ #<strong>$3</strong> پیشان دەدرێت.",
        "search-showingresults": "{{PLURAL:$4|ئاکامی <strong>$1</strong> لە <strong>$3</strong>|ئاکامەکانی <strong>$1 - $2</strong> لە <strong>$3</strong>}}",
        "search-nonefound": "ھیچ ئاکامێک کە بە داواکارییەکەت بخوا نەدۆزرایەوە.",
        "powersearch-legend": "گەڕانی پێشکەوتوو",
index 22847e5..0873467 100644 (file)
        "wrongpasswordempty": "Es wurde kein Passwort eingegeben. Bitte versuche es erneut.",
        "passwordtooshort": "Passwörter müssen mindestens {{PLURAL:$1|1 Zeichen|$1 Zeichen}} lang sein.",
        "passwordtoolong": "Passwörter können nicht länger als {{PLURAL:$1|ein|$1}} Zeichen sein.",
-       "passwordtoopopular": "Häufig ausgewählte Passwörter können nicht verwendet werden. Bitte wähle ein einzigartigeres Passwort aus.",
+       "passwordtoopopular": "Häufig ausgewählte Passwörter können nicht verwendet werden. Bitte wähle ein Passwort aus, das schwieriger zu erraten ist.",
        "password-name-match": "Dein Passwort muss sich von deinem Benutzernamen unterscheiden.",
        "password-login-forbidden": "Die Verwendung dieses Benutzernamens und Passwortes ist nicht erlaubt.",
        "mailmypassword": "Passwort zurücksetzen",
index fb13329..2a4f1d9 100644 (file)
        "wrongpasswordempty": "No has escrito una contraseña.\nInténtalo de nuevo.",
        "passwordtooshort": "Las contraseñas deben tener al menos {{PLURAL:$1|1 carácter|$1 caracteres}}.",
        "passwordtoolong": "Las contraseñas no deben tener más de {{PLURAL:$1|1 carácter|$1 caracteres}}.",
-       "passwordtoopopular": "No se pueden usar las contraseñas más comunes. Elige una menos popular.",
+       "passwordtoopopular": "No es posible utilizar las contraseñas más comunes. Elige una que sea más difícil de descifrar.",
        "password-name-match": "Tu contraseña debe ser diferente de tu nombre de usuario.",
        "password-login-forbidden": "El uso de este nombre de usuario y contraseña han sido prohibidos.",
        "mailmypassword": "Restablecer la contraseña",
        "whatlinkshere-hideimages": "$1 enlaces a archivos",
        "whatlinkshere-filters": "Filtros",
        "whatlinkshere-submit": "Ir",
-       "autoblockid": "Bloqueo automático #$1",
+       "autoblockid": "Bloqueo automático n.º $1",
        "block": "Bloquear usuario",
        "unblock": "Desbloquear usuario",
        "blockip": "Bloquear {{GENDER:$1|al usuario|a la usuaria}}",
index ccd0a35..1095b2f 100644 (file)
        "wrongpasswordempty": "Vous n’avez entré aucun mot de passe.\nVeuillez essayer à nouveau.",
        "passwordtooshort": "Votre mot de passe doit contenir au moins $1 caractère{{PLURAL:$1||s}}.",
        "passwordtoolong": "Les mots de passe ne peuvent pas dépasser $1 caractère{{PLURAL:$1||s}}.",
-       "passwordtoopopular": "Les mots de passe trop courants ne peuvent pas être utilisés. Veuillez choisir un mot de passe plus original.",
+       "passwordtoopopular": "Les mots de passe trop courants ne peuvent pas être utilisés. Veuillez choisir un mot de passe plus difficile à deviner.",
        "password-name-match": "Votre mot de passe doit être différent de votre nom d’utilisateur.",
        "password-login-forbidden": "L’utilisation de ce nom d’utilisateur ou de ce mot de passe a été interdite.",
        "mailmypassword": "Réinitialiser le mot de passe",
index 0a665e3..c01afb9 100644 (file)
        "laggedslavemode": "<strong>אזהרה:</strong> הדף עשוי שלא להכיל עדכונים אחרונים.",
        "readonly": "בסיס הנתונים נעול",
        "enterlockreason": "יש להקליד סיבה לנעילה, כולל הערכה למועד שחרור הנעילה",
-       "readonlytext": "בסיס הנתונים נעול כרגע להזנת נתונים ולשינויים אחרים. ככל הנראה, מדובר בתחזוקה שוטפת, שלאחריה יחזור האתר לפעולתו הרגילה.\n\nמנהל המערכת שנעל את בסיס הנתונים סיפק את ההסבר הבא: $1",
+       "readonlytext": "×\91ס×\99ס ×\94נת×\95× ×\99×\9d × ×¢×\95×\9c ×\9bר×\92×¢ ×\9c×\94×\96נת × ×ª×\95× ×\99×\9d ×\97×\93ש×\99×\9d ×\95×\9cש×\99× ×\95×\99×\99×\9d ×\90×\97ר×\99×\9d. ×\9b×\9b×\9c ×\94נר×\90×\94, ×\9e×\93×\95×\91ר ×\91ת×\97×\96×\95ק×\94 ×©×\95×\98פת, ×©×\9c×\90×\97ר×\99×\94 ×\99×\97×\96×\95ר ×\94×\90תר ×\9cפע×\95×\9cת×\95 ×\94ר×\92×\99×\9c×\94.\n\n×\9e× ×\94×\9c ×\94×\9eער×\9bת ×©× ×¢×\9c ×\90ת ×\91ס×\99ס ×\94נת×\95× ×\99×\9d ×¡×\99פק ×\90ת ×\94×\94ס×\91ר ×\94×\91×\90: $1",
        "missing-article": "בסיס הנתונים לא מצא את הטקסט של הדף שהוא היה אמור למצוא, בשם \"$1\" $2.\n\nזה נגרם בדרך־כלל עקב לחיצה על קישור ישן לגרסה של דף שנמחק.\n\nאם זה אינו המקרה, זהו כנראה באג בתוכנה.\nנא לדווח על כך ל[[Special:ListUsers/sysop|מפעיל מערכת]], תוך שמירת פרטי כתובת ה־URL.",
        "missingarticle-rev": "(מספר גרסה: $1)",
        "missingarticle-diff": "(השוואת הגרסאות: $1, $2)",
        "title-invalid-interwiki": "כותרת הדף המבוקש מכילה קישור בינוויקי, שלא ניתן להשתמש בו בכותרות.",
        "title-invalid-talk-namespace": "כותרת הדף המבוקש מפנה לדף שיחה שאינו יכול להתקיים.",
        "title-invalid-characters": "כותרת הדף המבוקש מכילה תווים בלתי תקינים: \"$1\".",
-       "title-invalid-relative": "×\91×\9b×\95תרת ×\99ש × ×ª×\99×\91 ×\99×\97ס×\99. ×\9b×\95תר×\95ת ×\93פ×\99×\9d ×\99×\97ס×\99×\95ת (./, ../) ×\90×\99× ×\9f ×ª×§×\99× ×\95ת, ×\9eש×\95×\9d ×©×\9cעת×\99×\9d ×§×¨×\95×\91×\95ת ×\94×\9f ×\99×\94×\99×\95 ×\91×\9cת×\99Ö¾× ×\99תנ×\95ת ×\9c×\94ש×\92×\94 ×\9bשת×\98×\95פ×\9c× ×\94 ×¢×\9cÖ¾ידי הדפדפן של המשתמש.",
+       "title-invalid-relative": "×\91×\9b×\95תרת ×\99ש × ×ª×\99×\91 ×\99×\97ס×\99. ×\9b×\95תר×\95ת ×\93פ×\99×\9d ×\99×\97ס×\99×\95ת (./, ../) ×\90×\99× ×\9f ×ª×§×\99× ×\95ת, ×\9b×\99×\95×\95×\9f ×©×\9cעת×\99×\9d ×§×¨×\95×\91×\95ת ×\9c×\90 × ×\99ת×\9f ×\99×\94×\99×\94 ×\9c×\92שת ×\90×\9c×\99×\94×\9f ×\90×\9d ×\94×\9f ×\99×\98×\95פ×\9c×\95 ×\91ידי הדפדפן של המשתמש.",
        "title-invalid-magic-tilde": "כותרת הדף המבוקש מכילה רצף טילדות מיוחד שאינו תקין (<nowiki>~~~</nowiki>).",
        "title-invalid-too-long": "כותרת הדף המבוקש ארוכה מדי. היא צריכה להיות לכל היותר באורך של {{PLURAL:$1|בית אחד|$1 בתים}} בקידוד UTF-8.",
        "title-invalid-leading-colon": "כותרת הדף המבוקש מכילה תו נקודתיים בלתי תקין בתחילתה.",
        "wrongpasswordempty": "הסיסמה שהזנת ריקה.\nנא לנסות שוב.",
        "passwordtooshort": "סיסמאות חייבות להיות באורך {{PLURAL:$1|תו אחד|$1 תווים}} לפחות.",
        "passwordtoolong": "סיסמאות אינן יכולות להיות ארוכות {{PLURAL:$1|מתו אחד|מ־$1 תווים}}.",
-       "passwordtoopopular": "×\9c×\90 × ×\99ת×\9f ×\9c×\94שת×\9eש ×\91ס×\99ס×\9e×\90×\95ת × ×¤×\95צ×\95ת. ×\99ש ×\9c×\91×\97×\95ר ×¡×\99ס×\9e×\94 ×\99×\99×\97×\95×\93×\99ת ×\99×\95תר.",
+       "passwordtoopopular": "×\9c×\90 × ×\99ת×\9f ×\9c×\94שת×\9eש ×\91ס×\99ס×\9e×\90×\95ת × ×¤×\95צ×\95ת. ×\99ש ×\9c×\91×\97×\95ר ×¡×\99ס×\9e×\94 ×§×©×\94 ×\99×\95תר ×\9c× ×\99×\97×\95ש.",
        "password-name-match": "סיסמתך חייבת להיות שונה משם המשתמש שלך.",
        "password-login-forbidden": "השימוש בשם המשתמש והסיסמה האלה נאסר.",
        "mailmypassword": "איפוס סיסמה",
        "searchprofile-advanced": "מתקדם",
        "searchprofile-articles-tooltip": "חיפוש $1",
        "searchprofile-images-tooltip": "חיפוש קבצים",
-       "searchprofile-everything-tooltip": "×\97×\99פ×\95ש ×\91×\9b×\9c ×\94ת×\95×\9b×\9f (×\9c×\9e×¢×\98 דפי השיחה)",
+       "searchprofile-everything-tooltip": "×\97×\99פ×\95ש ×\91×\9b×\9c ×\94ת×\95×\9b×\9f (×\9b×\95×\9c×\9c דפי השיחה)",
        "searchprofile-advanced-tooltip": "חיפוש במרחבי שם מותאמים אישית",
        "search-result-size": "$1 ({{PLURAL:$2|מילה אחת|$2 מילים}})",
        "search-result-category-size": "{{PLURAL:$1|פריט אחד|$1 פריטים}} ({{PLURAL:$2|קטגוריית משנה אחת|$2 קטגוריות משנה}}, {{PLURAL:$3|קובץ אחד|$3 קבצים}})",
        "recentchanges-label-unpatrolled": "עריכה זו טרם נבדקה",
        "recentchanges-label-plusminus": "גודל הדף השתנה במספר זה של בתים",
        "recentchanges-legend-heading": "<strong>מקרא:</strong>",
-       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ({{GENDER:|ראה|ראי|ראו}} גם את [[Special:NewPages|רשימת הדפים החדשים]])",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (ר' גם את [[Special:NewPages|רשימת הדפים החדשים]])",
        "recentchanges-legend-plusminus": "(<em>±123</em>)",
        "recentchanges-submit": "הצגה",
        "rcfilters-tag-remove": "הסרת \"$1\"",
        "listfiles-latestversion-no": "לא",
        "file-anchor-link": "קובץ",
        "filehist": "היסטוריית הקובץ",
-       "filehist-help": "× ×\99ת×\9f ×\9c×\9c×\97×\95×¥ ×¢×\9c ×ª×\90ר×\99×\9a/שע×\94 ×\9b×\93×\99 ×\9cר×\90×\95ת ×\90ת ×\94ק×\95×\91×¥ ×\9bפ×\99 ×©× ×¨×\90×\94 ×\91עת ×\96×\95.",
+       "filehist-help": "× ×\99ת×\9f ×\9c×\9c×\97×\95×¥ ×¢×\9c ×ª×\90ר×\99×\9a/שע×\94 ×\9b×\93×\99 ×\9cר×\90×\95ת ×\90ת ×\94ק×\95×\91×¥ ×\9bפ×\99 ×©× ×¨×\90×\94 ×\91×\90×\95ת×\95 ×\96×\9e×\9f.",
        "filehist-deleteall": "מחיקת כל הגרסאות",
        "filehist-deleteone": "מחיקה",
        "filehist-revert": "שחזור",
        "filedelete-comment": "סיבה:",
        "filedelete-submit": "מחיקה",
        "filedelete-success": "הקובץ <strong>$1</strong> נמחק.",
-       "filedelete-success-old": "הגרסה של '''[[Media:$1|$1]]''' מ־$3, $2 נמחקה.",
-       "filedelete-nofile": "'''$1''' אינו קיים.",
-       "filedelete-nofile-old": "אין גרסה ישנה של '''$1''' עם התכונות המבוקשות.",
+       "filedelete-success-old": "הגרסה של הקובץ <strong>[[Media:$1|$1]]</strong> מ־$3, $2 נמחקה.",
+       "filedelete-nofile": "הקובץ <strong>$1</strong> אינו קיים.",
+       "filedelete-nofile-old": "אין גרסה ישנה של הקובץ <strong>$1</strong> עם התכונות המבוקשות.",
        "filedelete-otherreason": "סיבה נוספת/אחרת:",
        "filedelete-reason-otherlist": "סיבה אחרת",
        "filedelete-reason-dropdown": "* סיבות מחיקה נפוצות\n** הפרת זכויות יוצרים\n** קובץ כפול",
        "deletereasonotherlist": "סיבה אחרת",
        "deletereason-dropdown": "* סיבות מחיקה נפוצות\n** ספאם\n** השחתה\n** הפרת זכויות יוצרים\n** לבקשת הכותב\n** הפניה שבורה",
        "delete-edit-reasonlist": "עריכת סיבות המחיקה",
-       "delete-toobig": "×\9c×\93×£ ×\96×\94 ×\99ש ×\94×\99ס×\98×\95ר×\99×\99ת ×¢×¨×\99×\9b×\95ת ×\92×\93×\95×\9c×\94, ×\95×\94×\95×\90 ×\9e×\9b×\99×\9c יותר {{PLURAL:$1|מגרסה אחת|מ־$1 גרסאות}}.\nמחיקת דפים כאלה הוגבלה כדי למנוע בעיות בתפקוד של {{SITENAME}}.",
+       "delete-toobig": "×\9c×\93×£ ×\96×\94 ×\99ש ×\94×\99ס×\98×\95ר×\99×\99ת ×¢×¨×\99×\9b×\95ת ×\92×\93×\95×\9c×\94, ×©×\9e×\9b×\99×\9c×\94 יותר {{PLURAL:$1|מגרסה אחת|מ־$1 גרסאות}}.\nמחיקת דפים כאלה הוגבלה כדי למנוע בעיות בתפקוד של {{SITENAME}}.",
        "delete-warning-toobig": "דף זה כולל מעל {{PLURAL:$1|גרסה אחת|$1 גרסאות}} בהיסטוריית העריכות שלו. מחיקה שלו עלולה להפריע לפעולות בבסיס הנתונים; אנא שקלו שנית את המחיקה.",
        "deleteprotected": "אין {{GENDER:|באפשרותך|באפשרותך|באפשרותכם}} למחוק את הדף כי הוא מוגן.",
        "deleting-backlinks-warning": "<strong>אזהרה:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|דפים אחרים]] מקשרים לדף ש{{GENDER:|אתה עומד|את עומדת|אתם עומדים}} למחוק או מכלילים אותו.",
        "lockedbyandtime": "(על־ידי $1 ב־$3, $2)",
        "move-page": "העברת הדף \"$1\"",
        "move-page-legend": "העברת דף",
-       "movepagetext": "ניתן להשתמש בטופס שלהלן כדי לשנות את השם של הדף הזה ולהעביר את כל היסטוריית העריכות שלו לשם החדש.\nהשם הישן יהפוך לדף הפניה אל השם החדש.\nבאפשרותך לעדכן באופן אוטומטי דפי הפניה שכרגע מפנים לשם הנוכחי של הדף.\nנא לוודא לאחר ההעברה שאין [[Special:DoubleRedirects|הפניות כפולות]] או [[Special:BrokenRedirects|הפניות שבורות]].\nכמו כן, באחריותך לוודא שכל הקישורים ימשיכו לקשר למקומות שאליהם הם אמורים לקשר.\n\nיש לשים לב לכך שהדף <strong>לא</strong> יועבר אם כבר יש דף תחת השם החדש, אלא אם כן הדף עם השם החדש הוא הפניה ואין לו עריכות קודמות.\nזה אומר שניתן יהיה להחזיר את הדף לשם המקורי במקרה שתיעשה טעות, אבל לא ניתן \"לדרוס\" דף קיים.\n\n<strong>לתשומת לבך:</strong>\nהעברה זו עלולה להיות שינוי דרסטי ומהותי לדף פופולרי;\nיש לקחת בחשבון את התוצאות של הפעולה הזאת לפני ביצוע ההעברה.",
+       "movepagetext": "ניתן להשתמש בטופס שלהלן כדי לשנות את השם של הדף הזה ולהעביר את כל היסטוריית העריכות שלו לשם החדש.\nהשם הישן יהפוך לדף הפניה אל השם החדש.\nבאפשרותך לעדכן באופן אוטומטי דפי הפניה שכרגע מפנים לשם הנוכחי של הדף.\nנא לוודא לאחר ההעברה שאין [[Special:DoubleRedirects|הפניות כפולות]] או [[Special:BrokenRedirects|הפניות שבורות]] (אלא אם כן בחרת לבצע את העדכון האוטומטי הנ\"ל).\nכמו כן, באחריותך לוודא שכל הקישורים ימשיכו לקשר למקומות שאליהם הם אמורים לקשר.\n\nיש לשים לב לכך שהדף <strong>לא</strong> יועבר אם כבר יש דף תחת השם החדש, אלא אם כן הדף עם השם החדש הוא הפניה ואין לו עריכות קודמות.\nזה אומר שניתן יהיה להחזיר את הדף לשם המקורי במקרה שתיעשה טעות, אבל לא ניתן \"לדרוס\" דף קיים.\n\n<strong>לתשומת לבך:</strong>\nהעברה זו עלולה להיות שינוי דרסטי ומהותי לדף פופולרי;\nיש לקחת בחשבון את התוצאות של הפעולה הזאת לפני ביצוע ההעברה.",
        "movepagetext-noredirectfixer": "ניתן להשתמש בטופס שלהלן כדי לשנות את השם של הדף הזה ולהעביר את כל היסטוריית העריכות שלו לשם החדש.\nהשם הישן יהפוך לדף הפניה אל השם החדש.\nנא לוודא לאחר ההעברה שאין [[Special:DoubleRedirects|הפניות כפולות]] או [[Special:BrokenRedirects|הפניות שבורות]].\nכמו כן, באחריותך לוודא שכל הקישורים ימשיכו לקשר למקומות שאליהם הם אמורים לקשר.\n\nיש לשים לב לכך שהדף <strong>לא</strong> יועבר אם כבר יש דף תחת השם החדש, אלא אם כן הדף עם השם החדש הוא הפניה ואין לו עריכות קודמות.\nזה אומר שניתן יהיה להחזיר את הדף לשם המקורי במקרה שתיעשה טעות, אבל לא ניתן \"לדרוס\" דף קיים.\n\n<strong>לתשומת לבך:</strong>\nהעברה זו עלולה להיות שינוי דרסטי ומהותי לדף פופולרי;\nיש לקחת בחשבון את התוצאות של הפעולה הזאת לפני ביצוע ההעברה.",
        "movepagetalktext": "אם האפשרות הזאת מסומנת, דף השיחה של הדף הזה יועבר אוטומטית לשם החדש, אלא אם קיים דף שיחה שאינו ריק תחת השם החדש. במקרה כזה, יש להעביר או למזג את הדפים באופן ידני, במידת הצורך.",
        "moveuserpage-warning": "'''אזהרה:''' אתם עומדים להעביר דף משתמש. שימו לב שרק הדף יועבר וששם המשתמש '''לא''' ישתנה.",
        "tooltip-pt-login-private": "יש להיכנס לחשבון כדי להשתמש באתר הוויקי הזה",
        "tooltip-pt-logout": "יציאה מהחשבון",
        "tooltip-pt-createaccount": "מומלץ ליצור חשבון ולהיכנס אליו, אך אין חובה לעשות זאת",
-       "tooltip-ca-talk": "ש×\99×\97×\94 ×¢×\9c ×\93×£ ×\96×\94",
+       "tooltip-ca-talk": "ש×\99×\97×\94 ×¢×\9c ×\93×£ ×\94ת×\95×\9b×\9f",
        "tooltip-ca-edit": "עריכת דף זה",
        "tooltip-ca-addsection": "הוספת פסקה חדשה",
        "tooltip-ca-viewsource": "דף זה מוגן.\nבאפשרותך לצפות בקוד המקור שלו",
        "tooltip-n-currentevents": "מציאת מידע רקע על האירועים האחרונים",
        "tooltip-n-recentchanges": "רשימת השינויים האחרונים באתר",
        "tooltip-n-randompage": "טעינת דף אקראי",
-       "tooltip-n-help": "×¢×\96ר×\94 ×\91ש×\99×\9e×\95ש ×\91×\90תר",
-       "tooltip-t-whatlinkshere": "רש×\99×\9e×\94 ×©×\9c ×\9b×\9c ×\94×\93פ×\99×\9d ×©×\9e×\9b×\99×\9c×\99×\9d ×§×\99ש×\95ר×\99×\9d ×\9c×\93×£ ×\94×\96ה",
+       "tooltip-n-help": "×\94×\9eק×\95×\9d ×\9c×\9eצ×\95×\90 ×\9e×\99×\93×¢",
+       "tooltip-t-whatlinkshere": "רש×\99×\9e×\94 ×©×\9c ×\9b×\9c ×\93פ×\99 ×\94×\95×\95×\99ק×\99 ×©×\9eקשר×\99×\9d ×\94× ה",
        "tooltip-t-recentchangeslinked": "השינויים האחרונים שבוצעו בדפים המקושרים מדף זה",
        "tooltip-feed-rss": "הזנת RSS עבור דף זה",
        "tooltip-feed-atom": "הזנת Atom עבור דף זה",
index 1b66db2..2ff1f91 100644 (file)
        "category-subcat-count-limited": "Ova kategorija ima {{PLURAL:$1|podkategoriju|$1 podkategorije|$1 podkategorija}}.",
        "category-article-count": "{{PLURAL:$2|1=Ova kategorija sadržava samo sljedeću stranicu.|{{PLURAL:$1|Prikazana je $1 stranica|Prikazane su $1 stranice|Prikazano je $1 stranica}} u ovoj kategoriji, od ukupno $2.}}",
        "category-article-count-limited": "{{PLURAL:$1|stranica je|$1 stranice su|$1 stranica je}} u ovoj kategoriji.",
-       "category-file-count": "Ova kategorija sadrži $2 {{PLURAL:$2|datoteku|datoteke|datoteka}}. {{PLURAL:$1|Slijedi $1 datoteka|Slijede $1 datoteke|Slijedi $1 datoteka}}.",
+       "category-file-count": "{{PLURAL:$2|1=Ova kategorija sadržava samo sljedeću datoteku.|{{PLURAL:$1|Prikazana je $1 datoteka|Prikazane su $1 datoteke|Prikazano je $1 datoteka}} u ovoj kategoriji, od njih ukupno $2.}}",
        "category-file-count-limited": "{{PLURAL:$1|datoteka je|$1 datoteke su|$1 datoteka su}} u ovoj kategoriji.",
        "listingcontinuesabbrev": "nast.",
        "index-category": "Indeksirane stranice",
        "readonlywarning": "<strong>Upozorenje: Baza podataka je zaključana zbog održavanja, stoga trenutačno niste u mogućnosti spremiti svoja uređivanja.</strong>\nMožda biste željeli preslikati i zaljepite tekst u tekstualnu datoteku, te ju snimiti za kasnije upotrebe.'''\n\nAdministrator sustava koji je zaključao bazu ponudio je ovo objašnjenje: $1",
        "protectedpagewarning": "'''UPOZORENJE: Ova stranica je zaključana i mogu je uređivati samo suradnici s administratorskim pravima.'''\nPosljednja stavka u evidenciji navedena je niže kao napomena:",
        "semiprotectedpagewarning": "'''Napomena:''' Ova stranica je zaključana tako da je mogu uređivati samo prijavljeni suradnici.\nPosljednja stavka u evidenciji navedena je niže kao napomena:",
-       "cascadeprotectedwarning": "'''UPOZORENJE:''' Ova stranica je zaključana i mogu je uređivati samo suradnici s administratorskim pravima, jer je uključena u {{PLURAL:$1|slijedeću stranicu|slijedeće stranice}} koje su zaštićene \"prenosivom\" zaštitom:",
+       "cascadeprotectedwarning": "<strong>Upozorenje:</strong> Ova stranica je zaključana i mogu je uređivati samo suradnici s [[Special:ListGroupRights|posebnim pravima]], jer je uključena u {{PLURAL:$1|sljedeću stranicu koja je|sljedeće stranice koje su}} zaštićene \"prenosivom\" zaštitom:",
        "titleprotectedwarning": "<strong>Upozorenje: Ova je stranica zaključana i samo ju suradnici s [[Special:ListGroupRights|određenim pravima]] mogu stvoriti.</strong>\nPosljednja stavka u evidenciji navedena je niže kao napomena:",
        "templatesused": "{{PLURAL:$1|Predložak koji se rabi|Predlošci koji se rabe}} na ovoj stranici:",
        "templatesusedpreview": "{{PLURAL:$1|Predložak koji se rabi|Predlošci koji se rabe}} u ovom pretpregledu:",
        "emailmessage": "Poruka:",
        "emailsend": "Pošalji",
        "emailccme": "Pošalji mi presliku moje poruke e-poštom.",
-       "emailccsubject": "Kopija Vaše poruke za $1: $2",
+       "emailccsubject": "Kopija Vaše poruke za: $1: $2",
        "emailsent": "E-poruka je poslana!",
        "emailsenttext": "Vaša poruka je poslana.",
        "emailuserfooter": "Ovu je e-poruku {{GENDER:$1|poslao suradnik|poslala suradnica}} $1 {{GENDER:$2|suradniku $2|suradnici $2}} uporabom mogućnosti \"{{int:emailuser}}\" s projekta {{SITENAME}}. Ukoliko {{GENDER:$2|odgovorite}} na tu e-poruku, {{GENDER:$2|Vaša}} će poruka biti izravno poslana {{GENDER:$1|izvornom pošiljatelju}}, otkrivajući pritom {{GENDER:$2|Vašu}} adresu e-pošte {{GENDER:$1|pošiljatelju|pošiljateljici}}.",
index 6f59922..a4e22ce 100644 (file)
@@ -87,7 +87,7 @@
        "tog-watchlisthideminor": "Apró változtatások elrejtése",
        "tog-watchlisthideliu": "Bejelentkezett szerkesztők módosításainak elrejtése a figyelőlistáról",
        "tog-watchlistreloadautomatically": "A figyelőlista automatikus újratöltése bármelyik szűrő megváltoztatása esetén (JavaScript szükséges)",
-       "tog-watchlistunwatchlinks": "Közvetlen olvasottnak/olvasatlannak jelölő link hozzáadása a figyelőlista elemeihez (JavaScript szükséges)",
+       "tog-watchlistunwatchlinks": "Figyelőlista elemeinek eltávolítására szolgáló közvetlen link hozzáadása (JavaScript szükséges)",
        "tog-watchlisthideanons": "Névtelen szerkesztések elrejtése",
        "tog-watchlisthidepatrolled": "Az ellenőrzött szerkesztések elrejtése",
        "tog-watchlisthidecategorization": "Lapok kategorizálásának elrejtése",
index d159c91..2205dff 100644 (file)
        "nstab-media": "Media pagino",
        "nstab-special": "Specala pagino",
        "nstab-project": "Projeto pagino",
-       "nstab-image": "Failo",
+       "nstab-image": "Arkivo",
        "nstab-mediawiki": "Mesajo",
        "nstab-template": "Shablono",
        "nstab-help": "Helpo",
        "prefs-advancedwatchlist": "Progresiva selektaji (advanced options)",
        "prefs-diffs": "Diferi",
        "userrights-user-editname": "Skribez uzantonomo:",
+       "editusergroup": "Charjez grupi dil uzero",
        "userrights-groupsmember": "Membro di:",
        "group": "Grupo:",
        "group-user": "Uzanti",
index 91d6235..59aa484 100644 (file)
        "wrongpasswordempty": "Non è stata inserita alcuna password. Riprovare.",
        "passwordtooshort": "Le password devono contenere almeno {{PLURAL:$1|1 carattere|$1 caratteri}}.",
        "passwordtoolong": "La password non può contenere più di {{PLURAL:$1|1 carattere|$1 caratteri}}.",
-       "passwordtoopopular": "Password comuni non possono essere usate. Scegli una password più originale.",
+       "passwordtoopopular": "Password comuni non possono essere usate. Scegli una password più difficile da indovinare.",
        "password-name-match": "La password deve essere diversa dal nome utente.",
        "password-login-forbidden": "L'uso di questo nome utente e password è stato proibito.",
        "mailmypassword": "Reimposta password",
index e1c432c..6c5f011 100644 (file)
        "edithelp": "Hulpe mit bewarken",
        "helppage-top-gethelp": "Hulpe",
        "mainpage": "Vöärblad",
-       "mainpage-description": "Veurblad",
+       "mainpage-description": "Vöärblad",
        "policy-url": "Project:Beleid",
        "portal": "Gebrukersportål",
        "portal-url": "Project:Gebrukersportaol",
        "confirmrecreate": "Gebruker [[User:$1|$1]] ([[User talk:$1|Overleg]]) hef disse zied vortedaon naoda'j  begunnen bin mit joew wieziging, mit opgave van de volgende reden: ''$2''. Bevestig da'j t artikel herschrieven willen.",
        "confirmrecreate-noreason": "Gebruker [[User:$1|$1]] ([[User talk:$1|overleg]]) hef disse zied vortedaon naoda'j  begunnen bin mit joew wieziging. Bevestig da'j t artikel herschrieven willen.",
        "recreate": "Herschrieven",
+       "confirm-purge-title": "Herny disse syde",
        "confirm_purge_button": "Bevestig",
-       "confirm-purge-top": "Klik op 'bevestig' um t tussengeheugen van disse zied te legen.",
-       "confirm-purge-bottom": "t Leegmaken van t tussengeheugen zörgt derveur da'j de leste versie van n zied zien.",
+       "confirm-purge-top": "Klik up 'bevestig' üm et tüskengehöägen van disse syde te leagen.",
+       "confirm-purge-bottom": "Et leagmaken van et tüskengehöägen sörgt dervöär dat jy de lätste versy van een syde te syn krygen.",
        "confirm-watch-button": "Oké",
        "confirm-watch-top": "Disse zied op joew volglieste zetten?",
        "confirm-unwatch-button": "Oké",
index 0059c11..4527809 100644 (file)
        "laggedslavemode": "Åtvaring: Det er mogleg at sida ikkje er heilt oppdatert.",
        "readonly": "Databasen er skriveverna",
        "enterlockreason": "Skriv ein grunn for vernet, inkludert eit overslag for kva tid det vil bli oppheva",
-       "readonlytext": "Databasen er akkurat no skriveverna, truleg for rutinemessig vedlikehald. Administratoren som verna han har gjeve denne forklaringa:\n\n$1",
+       "readonlytext": "Databasen er nett no skriveverna for nye oppslag og andre endringar, truleg for rutinemessig vedlikehald. Etterpå vil han opnast att. Administratoren som verna han gav denne forklaringa:\n\n$1",
        "missing-article": "Databasen burde ha funne sida «$1» $2, men det gjorde han ikkje.\n\nDei vanlegaste årsakene til denne feilen er ei lenkje til ein skilnad mellom forskjellige versjonar eller lenkjer til ein gammal versjon av ei side som har vorte sletta.\n\nOm det ikkje er tilfellet kan du ha funne ein feil i programvara.\nMeld gjerne problemet til ein [[Special:ListUsers/sysop|administrator]] og oppgje då adressa til sida.",
        "missingarticle-rev": "(versjon $1)",
        "missingarticle-diff": "(jamføring av versjon $1 og $2)",
        "createacct-realname": "Sant namn (valfritt)",
        "createacct-reason": "Årsak",
        "createacct-reason-ph": "Kvifor du lagar ein ny konto",
+       "createacct-reason-help": "Melding vist i kontoopprettingsloggen",
        "createacct-submit": "Opprett kontoen din",
        "createacct-another-submit": "Opprett konto",
        "createacct-continue-submit": "Hald fram med kontooppretting",
        "wrongpasswordempty": "Du oppgav ikkje noko passord. Ver venleg og prøv igjen.",
        "passwordtooshort": "Passord må innehalda minst {{PLURAL:$1|eitt teikn|$1 teikn}}.",
        "passwordtoolong": "Passord kan ikkje vera lengre enn {{PLURAL:$1|eitt|$1}} teikn.",
-       "passwordtoopopular": "Alminneleg valde passord kan ikkje nyttast. Vel eit meir unikt passord.",
+       "passwordtoopopular": "Alminneleg valde passord kan ikkje nyttast. Ver god å velja eit passord som er vanskelegare å gissa.",
        "password-name-match": "Passordet ditt lyt vera noko anna enn brukarnamnet ditt.",
        "password-login-forbidden": "Bruk av dette brukarnamnet og passordet er vorte forbode.",
        "mailmypassword": "Attendestill passord",
        "noemail": "Det er ikkje registrert noka e-postadresse åt brukaren «$1».",
        "noemailcreate": "Du må oppgje ei gyldig e-postadresse",
        "passwordsent": "Eit nytt passord er sendt åt e-postadressa registrert på brukaren «$1».",
-       "blocked-mailpassword": "IP-adressa di er blokkert frå å endre sider, og du kan difor heller ikkje få nytt passord. Dette er for å hindre misbruk.",
-       "eauthentsent": "Ein stadfestings-e-post er sendt til den oppgjevne e-postadressa. For at adressa skal kunna brukast, må du følgje instruksjonane i e-posten for å stadfeste at ho faktisk tilhøyrer deg.",
-       "throttled-mailpassword": "Ei passordpåminning er allereie sendt {{PLURAL:$1|den siste timen|dei siste $1 timane}}. For å hindre misbruk vert det berre sendt ut nytt passord ein gong kvar {{PLURAL:$1|time|$1. time}}.",
+       "blocked-mailpassword": "IP-adressa di er blokkert frå å endre sider. For å hindre misbruk kan ein heller ikkje ikkje  få nytt passord frå denne adressa.",
+       "eauthentsent": "Det er blitt send ein stadfestings-e-post til den oppgjevne e-postadressa. \n\nFør det blir send fleire e-postar til adressa, må du følgje instruksjonane i e-posten for å stadfeste at ho faktisk tilhøyrer deg.",
+       "throttled-mailpassword": "Ei passordpåminning er allereie sendt {{PLURAL:$1|den siste timen|dei siste $1 timane}}. \nFor å hindre misbruk vert det berre sendt ut nytt passord ein gong kvar {{PLURAL:$1|time|$1. timar}}.",
        "mailerror": "Ein feil oppstod ved sending av e-post: $1",
-       "acct_creation_throttle_hit": "Vitjande på denne wikien som nytta IP-adressa di har alt oppretta {{PLURAL:$1|éin konto|$1 kontoar}} den siste dagen, noko som er det høgaste tillate talet i denne tidsperioden.\nGrunna dette vil ikkje vitjande som nyttar denne IP-adressa kunna oppretta nye kontoar nett no.",
+       "acct_creation_throttle_hit": "Vitjande på denne wikien som nytta IP-adressa di har alt oppretta {{PLURAL:$1|éin konto|$1 kontoar}} den siste $2, noko som er det høgaste tillatne talet i denne tidsperioden.\nGrunna dette vil ikkje vitjande som nyttar denne IP-adressa kunna oppretta nye kontoar nett no.",
        "emailauthenticated": "E-postadressa di vart stadfest $2 klokka $3.",
        "emailnotauthenticated": "E-postadressa di er ikkje stadfest enno. Ingen e-post vil verta send ut for desse funksjonane.",
        "noemailprefs": "Oppgje ei e-postadresse i innstillingane dine for at desse funksjonane skal verke.",
        "user-mail-no-addy": "↓Prøvde å senda e-post utan e-postadresse",
        "user-mail-no-body": "Freista å senda e-post med tom eller urimeleg stutt brødtekst.",
        "changepassword": "Skift passord",
-       "resetpass_announce": "Du logga inn med eit mellombels passord du fekk på e-post. For å fullføre innlogginga må du lage eit nytt passord her:",
+       "resetpass_announce": "For å fullføra innloggingen må du velja eit nytt passord.",
        "resetpass_text": "<!-- Legg til tekst her -->",
        "resetpass_header": "Endra passord",
        "oldpassword": "Gammalt passord",
        "retypenew": "Nytt passord om att",
        "resetpass_submit": "Oppgje passord og logg inn",
        "changepassword-success": "Passordet ditt er no endra!",
+       "changepassword-throttled": "Du har gjort for mange nylege innloggingsforsøk.\nVer god å venta $1 før du prøver igjen.",
        "botpasswords": "Botpassord",
        "resetpass_forbidden": "Passord kan ikkje endrast",
        "resetpass-no-info": "Du må vera innlogga for å få direktetilgang til denne sida.",
        "resetpass-submit-loggedin": "Endra passord",
        "resetpass-submit-cancel": "Avbryt",
        "resetpass-wrong-oldpass": "Ugyldig mellombels eller gjeldande passord.\nDu kan ha bytt passordet allereie, eller bede om å få eit nytt mellombels passord.",
+       "resetpass-recycled": "Ver god og endra passordet til noko anna enn det gjeldande passordet ditt.",
        "resetpass-temp-emailed": "Du logga inn med ein mellombels kode send med e-post.\nFor å fullføra innlogginga lyt du oppgje eit nytt passord her:",
        "resetpass-temp-password": "Mellombels passord:",
        "resetpass-abort-generic": "Passordbytet vart stogga av ei utviding.",
        "passwordreset-emailtext-ip": "Nokon (sannsynlegvis deg, frå IP-adressa $1) bad om ei nullstilling av passordet ditt for {{SITENAME}} ($4). {{PLURAL:$3|Denne brukarkontoen|Desse brukarkontoane}} er knytte til denne e-postadressa:\n\n$2\n\n{{PLURAL:$3|Dette mellombels passordet|Desse mellombels passorda}} går ut om {{PLURAL:$5|éin dag|$5 dagar}}.\nDu bør logga inn og velja eit nytt passord no. Om nokon andre enn deg bad om denne nullstillinga eller du no hugsar det opphavlege passordet og ikkje lenger ynskjer å endra det, kan du sjå bort frå denne meldinga og halda fram med å nytta det gamle passordet ditt.",
        "passwordreset-emailtext-user": "Brukaren $1 på {{SITENAME}} bad om ei påminning for kontodetaljane dine for {{SITENAME}} ($4). {{PLURAL:$3|Den fylgjande brukarkontoen|Dei fylgjande brukarkontoane}} er assosierte med denne e-postadressa:\n\n$2\n\n{{PLURAL:$3|Dette mellombels passordet|Desse mellombels passorda}} vil verta ugilde om {{PLURAL:$5|éin dag|$5 dagar}}.\nDu bør logga inn og velja eit nytt passord no. Om nokon andre enn deg bad om denne påminninga, eller du har kome i hug det opphavlege passordet og ikkje lenger ynskjer å endra det, kan du sjå bort frå denne meldinga og halda fram med å nytta det gamle passordet ditt.",
        "passwordreset-emailelement": "↓Brukarnamn: \n$1\n\nMellombels passord: \n$2",
-       "passwordreset-emailsentemail": "Ein e-post for attendestilling av passord er vorten send",
+       "passwordreset-emailsentemail": "Om denne e-postadressa er knytt til din konto, vil det verte send ein e-post for attendestilling av passordet.",
+       "passwordreset-emailsentusername": "Om ei e-postadresse er knytt til denne kontoen, vil det verte send ein e-post for attendestilling av passordet.",
+       "passwordreset-nocaller": "Du må oppgje ein brukar",
+       "passwordreset-nosuchcaller": "Brukaren finst ikkje: $1",
+       "passwordreset-ignored": "Passordtilbakestillinga vart ikkje handsama. Kanskje ingen leverandør er vorten konfigurert?",
+       "passwordreset-invalidemail": "Ugyldig e-postadresse",
+       "passwordreset-nodata": "Verken eit brukarnamn eller ei e-postadresse vart oppgjeve",
        "changeemail": "Endre eller fjern e-postadresse",
        "changeemail-header": "Fyll ut dette skjemaet for å endre e-postadressa di. Ynskjer du å fjerne tilknytinga ei e-postadresse har til kontoen din, lat feltet for ny e-postadresse stå tomt når du sender inn skjemaet.",
        "changeemail-no-info": "↓Du må vera pålogga for å få tilgang direkte til denne sida.",
        "changeemail-password": "{{SITENAME}}-passordet ditt:",
        "changeemail-submit": "Endre e-post",
        "changeemail-throttled": "Du har freista for mange gonger å logga inn. Du lyt venta $1 før du kan freista på nytt.",
+       "changeemail-nochange": "Ver god å oppgje ei ny e-postadresse.",
        "bold_sample": "Halvfeit skrift",
        "bold_tip": "Halvfeit skrift",
        "italic_sample": "Kursivskrift",
index 3fbb53f..edd2b0c 100644 (file)
        "recentchanges-legend-newpage": "[[w:sr:Посебно:НовеСтране|<u>Н</u>ова страница]]",
        "recentchanges-submit": "Прикажи",
        "rcfilters-tag-remove": "Уклоните филтер „$1”",
-       "rcfilters-legend-heading": "\n<strong>Списак скраћеница ([[w:sr:Помоћ:Надгледање страница|помоћ]]):<strong>",
+       "rcfilters-legend-heading": "\n<strong>Списак скраћеница ([[w:sr:Помоћ:Надгледање страница|помоћ]]):</strong>",
        "rcfilters-other-review-tools": "Остале алатке за преглед",
        "rcfilters-group-results-by-page": "Групиши резултате по страницама",
        "rcfilters-activefilters": "Активни филтери",
index 2533454..76a149a 100644 (file)
        "pageinfo-header-edits": "ประวัติการแก้ไข",
        "pageinfo-header-restrictions": "การล็อกหน้า",
        "pageinfo-header-properties": "คุณสมบัติหน้า",
-       "pageinfo-display-title": "หัวà¹\80รืà¹\88อà¸\87à¸\82อà¸\87หà¸\99à¹\89าà¹\80มืà¹\88อà¹\81สà¸\94à¸\87à¸\9cล",
+       "pageinfo-display-title": "à¹\81สà¸\94à¸\87à¸\9cลà¸\8aืà¹\88อà¹\80รืà¹\88อà¸\87",
        "pageinfo-default-sort": "ค่าปริยายของคำหลักในการเรียงลำดับ",
        "pageinfo-length": "ความยาวหน้า (ไบต์)",
        "pageinfo-article-id": "เลขหน้า",
index 2878eca..26a6086 100644 (file)
     "karma-firefox-launcher": "1.0.1",
     "karma-mocha-reporter": "2.2.5",
     "karma-qunit": "1.2.1",
-    "nodemw": "0.11.0",
+    "mwbot": "1.0.10",
+    "postcss-less": "1.1.3",
     "qunitjs": "2.4.1",
     "stylelint": "8.2.0",
     "stylelint-config-wikimedia": "0.4.2",
     "wdio-junit-reporter": "0.2.0",
     "wdio-mocha-framework": "0.5.8",
-    "wdio-sauce-service": "^0.3.1",
+    "wdio-sauce-service": "0.3.1",
     "wdio-spec-reporter": "0.0.5",
-    "webdriverio": "4.6.2"
+    "webdriverio": "4.12.0"
   }
 }
index 04f80f4..48a78d3 100644 (file)
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @large
+ * @covers CurlHttpRequest
+ */
 class CurlHttpRequestTest extends MWHttpRequestTestCase {
        protected static $httpEngine = 'curl';
 }
index d0222a5..90bf532 100644 (file)
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @large
+ * @covers PhpHttpRequest
+ */
 class PhpHttpRequestTest extends MWHttpRequestTestCase {
        protected static $httpEngine = 'php';
 }
index c69fa73..9ee157b 100644 (file)
@@ -7,7 +7,10 @@ use MediaWiki\Shell\Shell;
  * Integration tests to ensure that firejail actually prevents execution.
  * Meant to run on vagrant, although will probably work on other setups
  * as long as firejail and sudo has similar config.
+ *
+ * @large
  * @group Shell
+ * @covers FirejailCommand
  */
 class FirejailCommandIntegrationTest extends PHPUnit\Framework\TestCase {
 
index 261bce1..3f4ecad 100644 (file)
@@ -9776,6 +9776,10 @@ Multiple list tags generated by templates
 </li><li>b
 </li><li>c
 </li>
+!! html/parsoid
+<li about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"stx":"html","autoInsertedEnd":true,"dsr":[0,44,null,null],"pi":[[{"k":"1"}],[{"k":"1"}],[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&lt;li>"}},"i":0}},"a\n",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&lt;li>"}},"i":1}},"b\n",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&lt;li>"}},"i":2}},"c"]}'>a
+</li><li about="#mwt1">b
+</li><li about="#mwt1" data-parsoid='{"stx":"html","autoInsertedEnd":true,"dsr":[null,44,null,0]}'>c</li>
 !!end
 
 !!test
@@ -13038,10 +13042,14 @@ Templates: Wiki Tables: 1a. Fostering of entire template content
 a
 <tr><td></td></tr></table>
 
-!! html+tidy
+!! html/php+tidy
 
 a
 <table><tbody><tr><td></td></tr></tbody></table>
+!! html/parsoid
+<p about="#mwt2" typeof="mw:Transclusion" data-parsoid='{"fostered":true,"autoInsertedEnd":true,"firstWikitextNode":"TABLE","pi":[[{"k":"1"}]]}' data-mw='{"parts":["{|\n",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a"}},"i":0}},"\n|}"]}'>a</p><table about="#mwt2">
+
+</table>
 !! end
 
 !!test
@@ -17391,9 +17399,8 @@ Media link with nasty text
 !! html/php
 <a href="http://example.com/images/3/3a/Foobar.jpg" class="internal" title="Foobar.jpg">Safe Link&lt;div style="display:none"&gt;" onmouseover="alert(document.cookie)" onfoo="&lt;/div&gt;</a>
 
-!! html+php/tidy
-<p><a href="http://example.com/images/3/3a/Foobar.jpg" class="internal" title="Foobar.jpg">Safe Link</a></p>
-<div style="display:none">" onmouseover="alert(document.cookie)" onfoo="</div>
+!! html/php+tidy
+<p><a href="http://example.com/images/3/3a/Foobar.jpg" class="internal" title="Foobar.jpg">Safe Link</a></p><a href="http://example.com/images/3/3a/Foobar.jpg" class="internal" title="Foobar.jpg"><div style="display:none">" onmouseover="alert(document.cookie)" onfoo="</div></a>
 !! html/parsoid
 <p><a rel="mw:MediaLink" href="//example.com/images/3/3a/Foobar.jpg" title="Foobar.jpg" data-parsoid='{"autoInsertedEnd":true}'>Safe Link</a></p><div style="display:none" data-parsoid='{"stx":"html"}'><a rel="mw:MediaLink" href="//example.com/images/3/3a/Foobar.jpg" title="Foobar.jpg" data-parsoid='{"autoInsertedEnd":true,"autoInsertedStart":true}'>" onmouseover="alert(document.cookie)" onfoo="</a></div>
 
@@ -23129,6 +23136,7 @@ Line two</blockquote>
 Line two</p></blockquote>
 !! end
 
+# Parsoid's output is broken on this because of Tidy-compatibility cruft
 !! test
 T8200: paragraphs inside blockquotes (extra line break on close)
 !! wikitext
@@ -23524,7 +23532,7 @@ comment
 Bad images - basic functionality
 !! wikitext
 [[File:Bad.jpg]]
-!! DISABLED/html/php
+!! html/php+disabled
 !! html/parsoid
 <p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"bad-image","message":"This image is blacklisted in this context."}]}'><a href="./File:Bad.jpg"><img resource="./File:Bad.jpg" height="220" width="220"/></a></span></p>
 !! end
@@ -23535,7 +23543,7 @@ Bad images - T18039: text after bad image disappears
 Foo bar
 [[File:Bad.jpg]]
 Bar foo
-!! DISABLED/html/php
+!! html/php+disabled
 <p>Foo bar
 </p><p>Bar foo
 </p>
@@ -27703,7 +27711,7 @@ parsoid=html2wt
 !! html/parsoid
 <ul><li>a<br>b</li><li>c</li></ul>
 !! wikitext
-* a<br>b
+* a<br />b
 * c
 !! end
 
@@ -28403,9 +28411,9 @@ parsoid=html2wt,wt2wt
 |<nowiki>- </nowiki>
 |-
 |<small>-</small>
-|<br>
+|<br />
 -
-|<br>
+|<br />
 -
 |}
 !! html/php+tidy
@@ -28858,7 +28866,7 @@ parsoid={
 !! html/parsoid
 <h2>foo<br/>bar</h2>
 !! wikitext
-== foo<br> bar ==
+== foo<br /> bar ==
 !! end
 
 !! test
@@ -29938,6 +29946,9 @@ wgFragmentMode=[ 'html5', 'legacy' ]
 <h2><span class="mw-headline" id="Foo_bar">Foo&#160;bar</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Foo bar">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <p><a href="#Foo_bar">#Foo&#160;bar</a>
 </p>
+!! html/parsoid
+<h2 id="Foo_bar"> Foo<span typeof="mw:Entity" data-parsoid='{"src":"&amp;nbsp;","srcContent":" "}'> </span>bar </h2>
+<p><a rel="mw:WikiLink" href="./Main_Page#Foo_bar" data-parsoid='{"stx":"simple","a":{"href":"./Main_Page#Foo_bar"},"sa":{"href":"#Foo&amp;nbsp;bar"}}'>#Foo bar</a></p>
 !! end
 
 !! test
index 8919c5e..8417f5c 100644 (file)
@@ -4,9 +4,9 @@ use MediaWiki\Linker\LinkTarget;
 use MediaWiki\MediaWikiServices;
 
 /**
+ * @medium
  * @group API
  * @group Database
- * @group medium
  *
  * @covers ApiQueryWatchlist
  */
index 1e685bd..f80d18c 100644 (file)
@@ -2,6 +2,7 @@
 
 /**
  * @group Http
+ * @group small
  */
 class HttpTest extends MediaWikiTestCase {
        /**
index 076924c..97ea326 100644 (file)
@@ -5,8 +5,10 @@ use MediaWiki\MediaWikiServices;
  * Integration test that checks import success and
  * LinkCache integration.
  *
- * @group medium
+ * @large
  * @group Database
+ * @covers ImportStreamSource
+ * @covers ImportReporter
  *
  * @author mwjames
  */
index 009580b..b883c11 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 use Wikimedia\Rdbms\LikeMatch;
+use Wikimedia\Rdbms\Database;
 
 /**
  * Test the parts of the Database abstract class that deal
@@ -10,7 +11,7 @@ class DatabaseSQLTest extends PHPUnit\Framework\TestCase {
 
        use MediaWikiCoversValidator;
 
-       /** @var DatabaseTestHelper */
+       /** @var DatabaseTestHelper|Database */
        private $database;
 
        protected function setUp() {
@@ -239,6 +240,101 @@ class DatabaseSQLTest extends PHPUnit\Framework\TestCase {
                ];
        }
 
+       /**
+        * @covers Wikimedia\Rdbms\Subquery
+        * @dataProvider provideSelectRowCount
+        * @param $sql
+        * @param $sqlText
+        */
+       public function testSelectRowCount( $sql, $sqlText ) {
+               $this->database->selectRowCount(
+                       $sql['tables'],
+                       $sql['field'],
+                       isset( $sql['conds'] ) ? $sql['conds'] : [],
+                       __METHOD__,
+                       isset( $sql['options'] ) ? $sql['options'] : [],
+                       isset( $sql['join_conds'] ) ? $sql['join_conds'] : []
+               );
+               $this->assertLastSql( $sqlText );
+       }
+
+       public static function provideSelectRowCount() {
+               return [
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'field' => [ '*' ],
+                                       'conds' => [ 'field' => 'text' ],
+                               ],
+                               "SELECT COUNT(*) AS rowcount FROM " .
+                               "(SELECT 1 FROM table WHERE field = 'text'  ) tmp_count"
+                       ],
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'field' => [ 'column' ],
+                                       'conds' => [ 'field' => 'text' ],
+                               ],
+                               "SELECT COUNT(*) AS rowcount FROM " .
+                               "(SELECT 1 FROM table WHERE field = 'text' AND (column IS NOT NULL)  ) tmp_count"
+                       ],
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'field' => [ 'alias' => 'column' ],
+                                       'conds' => [ 'field' => 'text' ],
+                               ],
+                               "SELECT COUNT(*) AS rowcount FROM " .
+                               "(SELECT 1 FROM table WHERE field = 'text' AND (column IS NOT NULL)  ) tmp_count"
+                       ],
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'field' => [ 'alias' => 'column' ],
+                                       'conds' => '',
+                               ],
+                               "SELECT COUNT(*) AS rowcount FROM " .
+                               "(SELECT 1 FROM table WHERE (column IS NOT NULL)  ) tmp_count"
+                       ],
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'field' => [ 'alias' => 'column' ],
+                                       'conds' => false,
+                               ],
+                               "SELECT COUNT(*) AS rowcount FROM " .
+                               "(SELECT 1 FROM table WHERE (column IS NOT NULL)  ) tmp_count"
+                       ],
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'field' => [ 'alias' => 'column' ],
+                                       'conds' => null,
+                               ],
+                               "SELECT COUNT(*) AS rowcount FROM " .
+                               "(SELECT 1 FROM table WHERE (column IS NOT NULL)  ) tmp_count"
+                       ],
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'field' => [ 'alias' => 'column' ],
+                                       'conds' => '1',
+                               ],
+                               "SELECT COUNT(*) AS rowcount FROM " .
+                               "(SELECT 1 FROM table WHERE (1) AND (column IS NOT NULL)  ) tmp_count"
+                       ],
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'field' => [ 'alias' => 'column' ],
+                                       'conds' => '0',
+                               ],
+                               "SELECT COUNT(*) AS rowcount FROM " .
+                               "(SELECT 1 FROM table WHERE (0) AND (column IS NOT NULL)  ) tmp_count"
+                       ],
+               ];
+       }
+
        /**
         * @dataProvider provideUpdate
         * @covers Wikimedia\Rdbms\Database::update
index 0e1605a..c25329f 100644 (file)
@@ -8,6 +8,7 @@ use Wikimedia\ScopedCallback;
  * Note: the following groups are not used by PHPUnit.
  * The list in ParserTestFileSuite::__construct() is used instead.
  *
+ * @large
  * @group Database
  * @group Parser
  * @group ParserTests
index fdf0152..edc2eff 100644 (file)
@@ -1,7 +1,13 @@
 <?php
 
 /**
+ * @medium
  * @group Database
+ * @covers FormattedRCFeed
+ * @covers RecentChange
+ * @covers JSONRCFeedFormatter
+ * @covers MachineReadableRCFeedFormatter
+ * @covers RCFeed
  */
 class RCFeedIntegrationTest extends MediaWikiTestCase {
        protected function setUp() {
@@ -17,15 +23,6 @@ class RCFeedIntegrationTest extends MediaWikiTestCase {
                ] );
        }
 
-       /**
-        * @covers RecentChange::notifyRCFeeds
-        * @covers RecentChange::getEngine
-        * @covers RCFeed::factory
-        * @covers FormattedRCFeed::__construct
-        * @covers FormattedRCFeed::notify
-        * @covers JSONRCFeedFormatter::formatArray
-        * @covers MachineReadableRCFeedFormatter::getLine
-        */
        public function testNotify() {
                $feed = $this->getMockBuilder( RCFeedEngine::class )
                        ->setConstructorArgs( [ [ 'formatter' => JSONRCFeedFormatter::class ] ] )
index f54e31c..105f409 100644 (file)
@@ -22,54 +22,26 @@ class CreateAccountPage extends Page {
        }
 
        apiCreateAccount( username, password ) {
-               const url = require( 'url' ), // https://nodejs.org/docs/latest/api/url.html
-                       baseUrl = url.parse( browser.options.baseUrl ), // http://webdriver.io/guide/testrunner/browserobject.html
-                       Bot = require( 'nodemw' ), // https://github.com/macbre/nodemw
-                       client = new Bot( {
-                               protocol: baseUrl.protocol,
-                               server: baseUrl.hostname,
-                               port: baseUrl.port,
-                               path: baseUrl.path,
-                               debug: false
-                       } );
 
-               return new Promise( ( resolve, reject ) => {
-                       client.api.call(
-                               {
-                                       action: 'query',
-                                       meta: 'tokens',
-                                       type: 'createaccount'
-                               },
-                               /**
-                                * @param {Error|null} err
-                                * @param {Object} info Processed query result
-                                * @param {Object} next More results?
-                                * @param {Object} data Raw data
-                                */
-                               function ( err, info, next, data ) {
-                                       if ( err ) {
-                                               reject( err );
-                                               return;
-                                       }
-                                       client.api.call( {
-                                               action: 'createaccount',
-                                               createreturnurl: browser.options.baseUrl,
-                                               createtoken: data.query.tokens.createaccounttoken,
-                                               username: username,
-                                               password: password,
-                                               retype: password
-                                       }, function ( err ) {
-                                               if ( err ) {
-                                                       reject( err );
-                                                       return;
-                                               }
-                                               resolve();
-                                       }, 'POST' );
-                               },
-                               'POST'
-                       );
+               const MWBot = require( 'mwbot' ), // https://github.com/Fannon/mwbot
+                       Promise = require( 'bluebird' );
+               let bot = new MWBot();
 
-               } );
+               return Promise.coroutine( function* () {
+                       yield bot.loginGetCreateaccountToken( {
+                               apiUrl: `${browser.options.baseUrl}/api.php`,
+                               username: browser.options.username,
+                               password: browser.options.password
+                       } );
+                       yield bot.request( {
+                               action: 'createaccount',
+                               createreturnurl: browser.options.baseUrl,
+                               createtoken: bot.createaccountToken,
+                               username: username,
+                               password: password,
+                               retype: password
+                       } );
+               } ).call( this );
 
        }
 
index bd28ca8..d43cb9f 100644 (file)
@@ -19,33 +19,20 @@ class DeletePage extends Page {
        }
 
        apiDelete( name, reason ) {
-               const url = require( 'url' ), // https://nodejs.org/docs/latest/api/url.html
-                       baseUrl = url.parse( browser.options.baseUrl ), // http://webdriver.io/guide/testrunner/browserobject.html
-                       Bot = require( 'nodemw' ), // https://github.com/macbre/nodemw
-                       client = new Bot( {
-                               protocol: baseUrl.protocol,
-                               server: baseUrl.hostname,
-                               port: baseUrl.port,
-                               path: baseUrl.path,
+
+               const MWBot = require( 'mwbot' ), // https://github.com/Fannon/mwbot
+                       Promise = require( 'bluebird' );
+               let bot = new MWBot();
+
+               return Promise.coroutine( function* () {
+                       yield bot.loginGetEditToken( {
+                               apiUrl: `${browser.options.baseUrl}/api.php`,
                                username: browser.options.username,
-                               password: browser.options.password,
-                               debug: false
+                               password: browser.options.password
                        } );
+                       yield bot.delete( name, reason );
+               } ).call( this );
 
-               return new Promise( ( resolve, reject ) => {
-                       client.logIn( function ( err ) {
-                               if ( err ) {
-                                       console.log( err );
-                                       return reject( err );
-                               }
-                               client.delete( name, reason, function ( err ) {
-                                       if ( err ) {
-                                               return reject( err );
-                                       }
-                                       resolve();
-                               } );
-                       } );
-               } );
        }
 
 }
index 34f4263..33a27f0 100644 (file)
@@ -19,33 +19,20 @@ class EditPage extends Page {
        }
 
        apiEdit( name, content ) {
-               const url = require( 'url' ), // https://nodejs.org/docs/latest/api/url.html
-                       baseUrl = url.parse( browser.options.baseUrl ), // http://webdriver.io/guide/testrunner/browserobject.html
-                       Bot = require( 'nodemw' ), // https://github.com/macbre/nodemw
-                       client = new Bot( {
-                               protocol: baseUrl.protocol,
-                               server: baseUrl.hostname,
-                               port: baseUrl.port,
-                               path: baseUrl.path,
+
+               const MWBot = require( 'mwbot' ), // https://github.com/Fannon/mwbot
+                       Promise = require( 'bluebird' );
+               let bot = new MWBot();
+
+               return Promise.coroutine( function* () {
+                       yield bot.loginGetEditToken( {
+                               apiUrl: `${browser.options.baseUrl}/api.php`,
                                username: browser.options.username,
-                               password: browser.options.password,
-                               debug: false
+                               password: browser.options.password
                        } );
+                       yield bot.edit( name, content, `Created page with "${content}"` );
+               } ).call( this );
 
-               return new Promise( ( resolve, reject ) => {
-                       client.logIn( function ( err ) {
-                               if ( err ) {
-                                       console.log( err );
-                                       return reject( err );
-                               }
-                               client.edit( name, content, `Created page with "${content}"`, function ( err ) {
-                                       if ( err ) {
-                                               return reject( err );
-                                       }
-                                       resolve();
-                               } );
-                       } );
-               } );
        }
 
 }
index ed1f1bc..77bb1f4 100644 (file)
@@ -2,7 +2,7 @@
 'use strict';
 class Page {
        open( path ) {
-               browser.url( '/index.php?title=' + path );
+               browser.url( browser.options.baseUrl + '/index.php?title=' + path );
        }
 }
 module.exports = Page;
index ef47438..071f7f9 100644 (file)
@@ -8,7 +8,7 @@ class RestorePage extends Page {
        get displayedContent() { return browser.element( '#mw-content-text' ); }
 
        open( name ) {
-               browser.url( '/index.php?title=Special:Undelete/' + name );
+               super.open( 'Special:Undelete/' + name );
        }
 
        restore( name, reason ) {
index 26881eb..de2b738 100644 (file)
@@ -14,7 +14,9 @@ exports.config = merge( wdioConf.config, {
                process.env.MEDIAWIKI_PASSWORD,
        screenshotPath: '../log/',
        baseUrl: process.env.MW_SERVER + process.env.MW_SCRIPT_PATH,
-
+       exclude: [
+               './extensions/CirrusSearch/tests/selenium/specs/**/*.js'
+       ],
        reporters: [ 'spec', 'junit' ],
        reporterOptions: {
                junit: {