Merge "CSSMin: Support parenthesis and quotes in url references"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 5 May 2017 18:58:22 +0000 (18:58 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 5 May 2017 18:58:22 +0000 (18:58 +0000)
92 files changed:
RELEASE-NOTES-1.30
includes/DefaultSettings.php
includes/EditPage.php
includes/GlobalFunctions.php
includes/api/ApiQueryTags.php
includes/api/i18n/es.json
includes/changes/ChangesListBooleanFilter.php
includes/changes/ChangesListBooleanFilterGroup.php
includes/changes/ChangesListFilter.php
includes/changes/ChangesListFilterGroup.php
includes/changes/ChangesListStringOptionsFilterGroup.php
includes/config/EtcdConfig.php
includes/content/FileContentHandler.php
includes/installer/Installer.php
includes/installer/LocalSettingsGenerator.php
includes/interwiki/Interwiki.php
includes/interwiki/InterwikiLookup.php
includes/interwiki/InterwikiLookupAdapter.php
includes/jobqueue/jobs/RecentChangesUpdateJob.php
includes/libs/IEUrlExtension.php
includes/libs/mime/IEContentAnalyzer.php
includes/libs/mime/MimeAnalyzer.php
includes/libs/rdbms/database/DBConnRef.php
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/loadmonitor/LoadMonitorNull.php
includes/libs/stats/SamplingStatsdClient.php
includes/libs/xmp/XMP.php
includes/media/ExifBitmap.php
includes/media/Jpeg.php
includes/parser/Parser.php
includes/parser/ParserDiffTest.php
includes/search/SearchEngine.php
includes/services/ServiceContainer.php
includes/specialpage/ChangesListSpecialPage.php
includes/specials/SpecialRecentchanges.php
includes/user/User.php
includes/utils/AutoloadGenerator.php
includes/utils/BatchRowIterator.php
includes/widget/search/SimpleSearchResultSetWidget.php
languages/FakeConverter.php
languages/i18n/ar.json
languages/i18n/arz.json
languages/i18n/atj.json
languages/i18n/be-tarask.json
languages/i18n/bn.json
languages/i18n/bs.json
languages/i18n/da.json
languages/i18n/es.json
languages/i18n/eu.json
languages/i18n/fi.json
languages/i18n/hr.json
languages/i18n/ja.json
languages/i18n/ka.json
languages/i18n/kn.json
languages/i18n/ko.json
languages/i18n/nb.json
languages/i18n/pms.json
languages/i18n/ru.json
languages/i18n/sd.json
languages/i18n/su.json
languages/i18n/sv.json
languages/i18n/zh-hans.json
maintenance/updateCredits.php
package.json
resources/src/mediawiki.action/mediawiki.action.edit.preview.js
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterGroup.js
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js
resources/src/mediawiki.special/mediawiki.special.apisandbox.js
resources/src/mediawiki.special/mediawiki.special.search.commonsInterwikiWidget.js
resources/src/mediawiki.widgets/mw.widgets.UsersMultiselectWidget.js
resources/src/mediawiki/mediawiki.confirmCloseWindow.js
resources/src/mediawiki/mediawiki.inspect.js
tests/phpunit/data/media/adobergb.jpg [new file with mode: 0644]
tests/phpunit/data/media/missingprofile.jpg [new file with mode: 0644]
tests/phpunit/data/media/srgb.jpg
tests/phpunit/data/media/tinyrgb.jpg
tests/phpunit/includes/changes/ChangesListFilterTest.php
tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
tests/phpunit/includes/deferred/DeferredUpdatesTest.php
tests/phpunit/includes/interwiki/InterwikiLookupAdapterTest.php
tests/phpunit/includes/libs/DnsSrvDiscovererTest.php
tests/phpunit/includes/media/ExifBitmapTest.php
tests/phpunit/includes/media/JpegTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php
tests/phpunit/includes/search/SearchIndexFieldTest.php
tests/phpunit/includes/specialpage/AbstractChangesListSpecialPageTestCase.php
tests/phpunit/includes/specialpage/ChangesListSpecialPageTest.php
tests/phpunit/includes/specials/SpecialRecentchangesTest.php
tests/phpunit/includes/specials/SpecialWatchlistTest.php
tests/qunit/suites/resources/mediawiki.rcfilters/dm.FiltersViewModel.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.loader.test.js
tests/selenium/.eslintrc.json

index 8b6a932..cdf8ba4 100644 (file)
@@ -6,7 +6,12 @@ MediaWiki 1.30 is an alpha-quality branch and is not recommended for use in
 production.
 
 === Configuration changes in 1.30 ===
-* …
+* The C.UTF-8 locale should be used for $wgShellLocale, if available, to avoid
+  unexpected behavior when things use local-sensitive string comparisons. For
+  example, Scribunto considers "bar" < "Foo" in most locales since it ignores
+  case.
+* $wgShellLocale now affects LC_ALL rather than only LC_CTYPE. See
+  documentation of $wgShellLocale for details.
 
 === New features in 1.30 ===
 * …
index ac2261c..7c18fcc 100644 (file)
@@ -8162,11 +8162,41 @@ $wgShellCgroup = false;
 $wgPhpCli = '/usr/bin/php';
 
 /**
- * Locale for LC_CTYPE, to work around https://bugs.php.net/bug.php?id=45132
- * For Unix-like operating systems, set this to to a locale that has a UTF-8
- * character set. Only the character set is relevant.
- */
-$wgShellLocale = 'en_US.utf8';
+ * Locale for LC_ALL, to provide a known environment for locale-sensitive operations
+ *
+ * For Unix-like operating systems, this should be set to C.UTF-8 or an
+ * equivalent to provide the most consistent behavior for locale-sensitive
+ * C library operations across different-language wikis. If that locale is not
+ * available, use another locale that has a UTF-8 character set.
+ *
+ * This setting mainly affects the behavior of C library functions, including:
+ *  - String collation (order when sorting using locale-sensitive comparison)
+ *    - For example, whether "Å" and "A" are considered to be the same letter or
+ *      different letters and if different whether it comes after "A" or after
+ *      "Z", and whether sorting is case sensitive.
+ *  - String character set (how characters beyond basic ASCII are represented)
+ *    - We need this to be a UTF-8 character set to work around
+ *      https://bugs.php.net/bug.php?id=45132
+ *  - Language used for low-level error messages.
+ *  - Formatting of date/time and numeric values (e.g. '.' versus ',' as the
+ *    decimal separator)
+ *
+ * MediaWiki provides its own methods and classes to perform many
+ * locale-sensitive operations, which are designed to be able to vary locale
+ * based on wiki language or user preference:
+ *  - MediaWiki's Collation class should generally be used instead of the C
+ *    library collation functions when locale-sensitive sorting is needed.
+ *  - MediaWiki's Message class should be used for localization of messages
+ *    displayed to the user.
+ *  - MediaWiki's Language class should be used for formatting numeric and
+ *    date/time values.
+ *
+ * @note If multiple wikis are being served from the same process (e.g. the
+ *  same fastCGI or Apache server), this setting must be the same on all those
+ *  wikis.
+ * @see wfInitShellLocale()
+ */
+$wgShellLocale = 'C.UTF-8';
 
 /** @} */ # End shell }
 
index 6424ca6..0d3c74f 100644 (file)
@@ -3170,7 +3170,6 @@ class EditPage {
                        );
                        $wgOut->addHTML( "{$label} {$input}" );
                }
-
        }
 
        /**
index 4325328..d21cc1d 100644 (file)
@@ -1436,7 +1436,6 @@ function wfMsgReplaceArgs( $message, $args ) {
 function wfHostname() {
        static $host;
        if ( is_null( $host ) ) {
-
                # Hostname overriding
                global $wgOverrideHostname;
                if ( $wgOverrideHostname !== false ) {
@@ -2535,8 +2534,15 @@ function wfShellExecWithStderr( $cmd, &$retval = null, $environ = [], $limits =
 }
 
 /**
- * Workaround for https://bugs.php.net/bug.php?id=45132
- * escapeshellarg() destroys non-ASCII characters if LANG is not a UTF-8 locale
+ * Set the locale for locale-sensitive operations
+ *
+ * Sets LC_ALL to a known value to work around issues like the following:
+ * - https://bugs.php.net/bug.php?id=45132 escapeshellarg() destroys non-ASCII
+ *   characters if LANG is not a UTF-8 locale
+ * - T107128 Scribunto string comparison works case insensitive while the
+ *   standard Lua case sensitive
+ *
+ * @see $wgShellLocale
  */
 function wfInitShellLocale() {
        static $done = false;
@@ -2545,8 +2551,8 @@ function wfInitShellLocale() {
        }
        $done = true;
        global $wgShellLocale;
-       putenv( "LC_CTYPE=$wgShellLocale" );
-       setlocale( LC_CTYPE, $wgShellLocale );
+       putenv( "LC_ALL=$wgShellLocale" );
+       setlocale( LC_ALL, $wgShellLocale );
 }
 
 /**
index be67dd2..1b154fa 100644 (file)
@@ -53,37 +53,24 @@ class ApiQueryTags extends ApiQueryBase {
                $softwareDefinedTags = array_fill_keys( ChangeTags::listSoftwareDefinedTags(), 0 );
                $explicitlyDefinedTags = array_fill_keys( ChangeTags::listExplicitlyDefinedTags(), 0 );
                $softwareActivatedTags = array_fill_keys( ChangeTags::listSoftwareActivatedTags(), 0 );
+               $tagStats = ChangeTags::tagUsageStatistics();
 
-               $definedTags = array_merge( $softwareDefinedTags, $explicitlyDefinedTags );
+               $tagHitcounts = array_merge( $softwareDefinedTags, $explicitlyDefinedTags, $tagStats );
+               $tags = array_keys( $tagHitcounts );
 
                # Fetch defined tags that aren't past the continuation
                if ( $params['continue'] !== null ) {
                        $cont = $params['continue'];
-                       $tags = array_filter( array_keys( $definedTags ), function ( $v ) use ( $cont ) {
+                       $tags = array_filter( $tags, function ( $v ) use ( $cont ) {
                                return $v >= $cont;
                        } );
-                       $tags = array_fill_keys( $tags, 0 );
-               } else {
-                       $tags = $definedTags;
-               }
-
-               # Merge in all used tags
-               $this->addTables( 'change_tag' );
-               $this->addFields( 'ct_tag' );
-               $this->addFields( [ 'hitcount' => $fld_hitcount ? 'COUNT(*)' : '0' ] );
-               $this->addOption( 'LIMIT', $limit + 1 );
-               $this->addOption( 'GROUP BY', 'ct_tag' );
-               $this->addWhereRange( 'ct_tag', 'newer', $params['continue'], null );
-               $res = $this->select( __METHOD__ );
-               foreach ( $res as $row ) {
-                       $tags[$row->ct_tag] = (int)$row->hitcount;
                }
 
                # Now make sure the array is sorted for proper continuation
-               ksort( $tags );
+               sort( $tags );
 
                $count = 0;
-               foreach ( $tags as $tagName => $hitcount ) {
+               foreach ( $tags as $tagName ) {
                        if ( ++$count > $limit ) {
                                $this->setContinueEnumParameter( 'continue', $tagName );
                                break;
@@ -102,7 +89,7 @@ class ApiQueryTags extends ApiQueryBase {
                        }
 
                        if ( $fld_hitcount ) {
-                               $tag['hitcount'] = $hitcount;
+                               $tag['hitcount'] = intval( $tagHitcounts[$tagName] );
                        }
 
                        $isSoftware = isset( $softwareDefinedTags[$tagName] );
index bbd7c2d..bf7d81d 100644 (file)
        "apihelp-query+imageinfo-param-urlwidth": "Si se establece $2prop=url, se devolverá una URL a una imagen escalada a este ancho.\nPor razones de rendimiento, si se utiliza esta opción, no se devolverán más de $1 imágenes escaladas.",
        "apihelp-query+imageinfo-param-urlheight": "Similar a $1urlwidth.",
        "apihelp-query+imageinfo-param-metadataversion": "Versión de los metadatos que se utilizará. Si se especifica <kbd>latest</kbd>, utilizará la última versión. El valor predeterminado es <kbd>1</kbd>, por motivo de retrocompatibilidad.",
-       "apihelp-query+imageinfo-param-extmetadatalanguage": "¿Qué idioma buscar  en extmetadata. Esto afecta a qué traducción buscar, si hay varias disponibles, así como la forma en que cosas como números y varios valores son formateados.",
+       "apihelp-query+imageinfo-param-extmetadatalanguage": "En qué idioma obtener «extmetadata». Esto afecta tanto la traducción que se obtendrá ―si hay varias― como el formato de elementos como los números y algunos valores.",
        "apihelp-query+imageinfo-param-extmetadatamultilang": "Si las traducciones para la propiedad extmetadata están disponibles, busque todas ellas.",
        "apihelp-query+imageinfo-param-extmetadatafilter": "Si se especifica y no vacío, sólo estas claves serán devueltos por $1prop=extmetadata.",
        "apihelp-query+imageinfo-param-urlparam": "Un controlador específico de la cadena de parámetro. Por ejemplo, los archivos Pdf pueden utilizar <kbd>page15-100px</kbd>. <var>$1urlwidth</var> debe ser utilizado y debe ser consistente con <var>$1urlparam</var>.",
index 1c116ab..73c0fb0 100644 (file)
@@ -30,12 +30,6 @@ use Wikimedia\Rdbms\IDatabase;
  * @since 1.29
  */
 class ChangesListBooleanFilter extends ChangesListFilter {
-       /**
-        * Name.  Used as URL parameter
-        *
-        * @var string $name
-        */
-
        // This can sometimes be different on Special:RecentChanges
        // and Special:Watchlist, due to the double-legacy hooks
        // (SpecialRecentChangesFilters and SpecialWatchlistFilters)
@@ -84,32 +78,31 @@ class ChangesListBooleanFilter extends ChangesListFilter {
         * it's for.
         *
         * @param array $filterDefinition ChangesListFilter definition
-        *
-        * $filterDefinition['name'] string Name.  Used as URL parameter.
-        * $filterDefinition['group'] ChangesListFilterGroup Group.  Filter group this
-        *  belongs to.
-        * $filterDefinition['label'] string i18n key of label for structured UI.
-        * $filterDefinition['description'] string i18n key of description for structured
-        *  UI.
-        * $filterDefinition['showHide'] string Main i18n key used for unstructured UI.
-        * $filterDefinition['isReplacedInStructuredUi'] bool Whether there is an
-        *  equivalent feature available in the structured UI; this is optional, defaulting
-        *  to true.  It does not need to be set if the exact same filter is simply visible
-        *  on both.
-        * $filterDefinition['default'] bool Default
-        * $filterDefinition['priority'] int Priority integer.  Higher value means higher
-        *  up in the group's filter list.
-        * $filterDefinition['queryCallable'] callable Callable accepting parameters, used
-        *  to implement filter's DB query modification.  Callback parameters:
-        *   string $specialPageClassName Class name of current special page
-        *   IContextSource $context Context, for e.g. user
-        *   IDatabase $dbr Database, for addQuotes, makeList, and similar
-        *   array &$tables Array of tables; see IDatabase::select $table
-        *   array &$fields Array of fields; see IDatabase::select $vars
-        *   array &$conds Array of conditions; see IDatabase::select $conds
-        *   array &$query_options Array of query options; see IDatabase::select $options
-        *   array &$join_conds Array of join conditions; see IDatabase::select $join_conds
-        *   Optional only for legacy filters that still use the query hooks directly
+        * * $filterDefinition['name'] string Name.  Used as URL parameter.
+        * * $filterDefinition['group'] ChangesListFilterGroup Group.  Filter group this
+        *     belongs to.
+        * * $filterDefinition['label'] string i18n key of label for structured UI.
+        * * $filterDefinition['description'] string i18n key of description for structured
+        *     UI.
+        * * $filterDefinition['showHide'] string Main i18n key used for unstructured UI.
+        * * $filterDefinition['isReplacedInStructuredUi'] bool Whether there is an
+        *     equivalent feature available in the structured UI; this is optional, defaulting
+        *     to true.  It does not need to be set if the exact same filter is simply visible
+        *     on both.
+        * * $filterDefinition['default'] bool Default
+        * * $filterDefinition['priority'] int Priority integer.  Higher value means higher
+        *     up in the group's filter list.
+        * * $filterDefinition['queryCallable'] callable Callable accepting parameters, used
+        *     to implement filter's DB query modification.  Required, except for legacy
+        *     filters that still use the query hooks directly.  Callback parameters:
+        *      * string $specialPageClassName Class name of current special page
+        *      * IContextSource $context Context, for e.g. user
+        *      * IDatabase $dbr Database, for addQuotes, makeList, and similar
+        *      * array &$tables Array of tables; see IDatabase::select $table
+        *      * array &$fields Array of fields; see IDatabase::select $vars
+        *      * array &$conds Array of conditions; see IDatabase::select $conds
+        *      * array &$query_options Array of query options; see IDatabase::select $options
+        *      * array &$join_conds Array of join conditions; see IDatabase::select $join_conds
         */
        public function __construct( $filterDefinition ) {
                parent::__construct( $filterDefinition );
@@ -150,7 +143,7 @@ class ChangesListBooleanFilter extends ChangesListFilter {
        /**
         * Sets default
         *
-        * @param bool Default value
+        * @param bool $defaultValue
         */
        public function setDefault( $defaultValue ) {
                $this->defaultValue = $defaultValue;
index 1f4b211..951c407 100644 (file)
@@ -19,21 +19,21 @@ class ChangesListBooleanFilterGroup extends ChangesListFilterGroup {
         * @param array $groupDefinition Configuration of group
         * * $groupDefinition['name'] string Group name
         * * $groupDefinition['title'] string i18n key for title (optional, can be omitted
-        * *  only if none of the filters in the group display in the structured UI)
+        *     only if none of the filters in the group display in the structured UI)
         * * $groupDefinition['priority'] int Priority integer.  Higher means higher in the
-        * *  group list.
+        *     group list.
         * * $groupDefinition['filters'] array Numeric array of filter definitions, each of which
-        * *  is an associative array to be passed to the filter constructor.  However,
-        * *  'priority' is optional for the filters.  Any filter that has priority unset
-        * *  will be put to the bottom, in the order given.
+        *     is an associative array to be passed to the filter constructor.  However,
+        *    'priority' is optional for the filters.  Any filter that has priority unset
+        *     will be put to the bottom, in the order given.
         * * $groupDefinition['whatsThisHeader'] string i18n key for header of "What's
-        * *  This" popup (optional).
+        *     This" popup (optional).
         * * $groupDefinition['whatsThisBody'] string i18n key for body of "What's This"
-        * *  popup (optional).
+        *     popup (optional).
         * * $groupDefinition['whatsThisUrl'] string URL for main link of "What's This"
-        * *  popup (optional).
+        *     popup (optional).
         * * $groupDefinition['whatsThisLinkText'] string i18n key of text for main link of
-        * *  "What's This" popup (optional).
+        *     "What's This" popup (optional).
         */
        public function __construct( array $groupDefinition ) {
                $groupDefinition['isFullCoverage'] = true;
index 9af9adc..bd895bb 100644 (file)
@@ -74,25 +74,25 @@ abstract class ChangesListFilter {
        protected $description;
 
        /**
-        * List of conflicting groups
+        * Array of associative arrays with conflict information.  See
+        * setUnidirectionalConflict
         *
-        * @var array $conflictingGroups Array of associative arrays with conflict
-        *   information.  See setUnidirectionalConflict
+        * @var array $conflictingGroups
         */
        protected $conflictingGroups = [];
 
        /**
-        * List of conflicting filters
+        * Array of associative arrays with conflict information.  See
+        * setUnidirectionalConflict
         *
-        * @var array $conflictingFilters Array of associative arrays with conflict
-        *   information.  See setUnidirectionalConflict
+        * @var array $conflictingFilters
         */
        protected $conflictingFilters = [];
 
        /**
-        * List of filters that are a subset of the current filter
+        * Array of associative arrays with subset information
         *
-        * @var array $subsetFilters Array of associative arrays with subset information
+        * @var array $subsetFilters
         */
        protected $subsetFilters = [];
 
@@ -117,23 +117,22 @@ abstract class ChangesListFilter {
         * UI it's for.
         *
         * @param array $filterDefinition ChangesListFilter definition
-        *
-        * $filterDefinition['name'] string Name of filter; use lowercase with no
-        *  punctuation
-        * $filterDefinition['cssClassSuffix'] string CSS class suffix, used to mark
-        *  that a particular row belongs to this filter (when a row is included by the
-        *  filter) (optional)
-        * $filterDefinition['isRowApplicableCallable'] Callable taking two parameters, the
-        *  IContextSource, and the RecentChange object for the row, and returning true if
-        *  the row is attributed to this filter.  The above CSS class will then be
-        *  automatically added (optional, required if cssClassSuffix is used).
-        * $filterDefinition['group'] ChangesListFilterGroup Group.  Filter group this
-        *  belongs to.
-        * $filterDefinition['label'] string i18n key of label for structured UI.
-        * $filterDefinition['description'] string i18n key of description for structured
-        *  UI.
-        * $filterDefinition['priority'] int Priority integer.  Higher value means higher
-        *  up in the group's filter list.
+        * * $filterDefinition['name'] string Name of filter; use lowercase with no
+        *     punctuation
+        * * $filterDefinition['cssClassSuffix'] string CSS class suffix, used to mark
+        *     that a particular row belongs to this filter (when a row is included by the
+        *     filter) (optional)
+        * * $filterDefinition['isRowApplicableCallable'] Callable taking two parameters, the
+        *     IContextSource, and the RecentChange object for the row, and returning true if
+        *     the row is attributed to this filter.  The above CSS class will then be
+        *     automatically added (optional, required if cssClassSuffix is used).
+        * * $filterDefinition['group'] ChangesListFilterGroup Group.  Filter group this
+        *     belongs to.
+        * * $filterDefinition['label'] string i18n key of label for structured UI.
+        * * $filterDefinition['description'] string i18n key of description for structured
+        *     UI.
+        * * $filterDefinition['priority'] int Priority integer.  Higher value means higher
+        *     up in the group's filter list.
         */
        public function __construct( array $filterDefinition ) {
                if ( isset( $filterDefinition['group'] ) ) {
@@ -251,7 +250,7 @@ abstract class ChangesListFilter {
         * This means that anything in the results for the other filter is also in the
         * results for this one.
         *
-        * @param ChangesListFilter The filter the current instance is a superset of
+        * @param ChangesListFilter $other The filter the current instance is a superset of
         */
        public function setAsSupersetOf( ChangesListFilter $other ) {
                if ( $other->getGroup() !== $this->getGroup() ) {
@@ -346,7 +345,7 @@ abstract class ChangesListFilter {
         *
         * @param IContextSource $ctx Context source
         * @param RecentChange $rc Recent changes object
-        * @param Non-associative array of CSS class names; appended to if needed
+        * @param array &$classes Non-associative array of CSS class names; appended to if needed
         */
        public function applyCssClassIfNeeded( IContextSource $ctx, RecentChange $rc, array &$classes ) {
                if ( $this->isRowApplicableCallable === null ) {
index 71c474a..3555158 100644 (file)
@@ -106,18 +106,18 @@ abstract class ChangesListFilterGroup {
        protected $isFullCoverage;
 
        /**
-        * List of conflicting groups
+        * Array of associative arrays with conflict information.  See
+        * setUnidirectionalConflict
         *
-        * @var array $conflictingGroups Array of associative arrays with conflict
-        *   information.  See setUnidirectionalConflict
+        * @var array $conflictingGroups
         */
        protected $conflictingGroups = [];
 
        /**
-        * List of conflicting filters
+        * Array of associative arrays with conflict information.  See
+        * setUnidirectionalConflict
         *
-        * @var array $conflictingFilters Array of associative arrays with conflict
-        *   information.  See setUnidirectionalConflict
+        * @var array $conflictingFilters
         */
        protected $conflictingFilters = [];
 
@@ -131,25 +131,25 @@ abstract class ChangesListFilterGroup {
         * @param array $groupDefinition Configuration of group
         * * $groupDefinition['name'] string Group name; use camelCase with no punctuation
         * * $groupDefinition['title'] string i18n key for title (optional, can be omitted
-        * *  only if none of the filters in the group display in the structured UI)
+        *     only if none of the filters in the group display in the structured UI)
         * * $groupDefinition['type'] string A type constant from a subclass of this one
         * * $groupDefinition['priority'] int Priority integer.  Higher value means higher
-        * *  up in the group list (optional, defaults to -100).
+        *     up in the group list (optional, defaults to -100).
         * * $groupDefinition['filters'] array Numeric array of filter definitions, each of which
-        * *  is an associative array to be passed to the filter constructor.  However,
-        * *  'priority' is optional for the filters.  Any filter that has priority unset
-        * *  will be put to the bottom, in the order given.
+        *     is an associative array to be passed to the filter constructor.  However,
+        *     'priority' is optional for the filters.  Any filter that has priority unset
+        *     will be put to the bottom, in the order given.
         * * $groupDefinition['isFullCoverage'] bool Whether the group is full coverage;
-        * *  if true, this means that checking every item in the group means no
-        * *  changes list entries are filtered out.
+        *     if true, this means that checking every item in the group means no
+        *     changes list entries are filtered out.
         * * $groupDefinition['whatsThisHeader'] string i18n key for header of "What's
-        * *  This" popup (optional).
+        *     This" popup (optional).
         * * $groupDefinition['whatsThisBody'] string i18n key for body of "What's This"
-        * *  popup (optional).
+        *     popup (optional).
         * * $groupDefinition['whatsThisUrl'] string URL for main link of "What's This"
-        * *  popup (optional).
+        *     popup (optional).
         * * $groupDefinition['whatsThisLinkText'] string i18n key of text for main link of
-        * *  "What's This" popup (optional).
+        *     "What's This" popup (optional).
         */
        public function __construct( array $groupDefinition ) {
                if ( strpos( $groupDefinition['name'], self::RESERVED_NAME_CHAR ) !== false ) {
@@ -315,7 +315,8 @@ abstract class ChangesListFilterGroup {
        }
 
        /**
-        * @return array Associative array of ChangesListFilter objects, with filter name as key
+        * @return ChangesListFilter[] Associative array of ChangesListFilter objects, with
+        *   filter name as key
         */
        public function getFilters() {
                return $this->filters;
index 1abf637..86b4a8b 100644 (file)
@@ -60,12 +60,6 @@ class ChangesListStringOptionsFilterGroup extends ChangesListFilterGroup {
         */
        const NONE = '';
 
-       /**
-        * Group name; used as form parameter.
-        *
-        * @var string $name
-        */
-
        /**
         * Defaul parameter value
         *
@@ -86,35 +80,35 @@ class ChangesListStringOptionsFilterGroup extends ChangesListFilterGroup {
         * @param array $groupDefinition Configuration of group
         * * $groupDefinition['name'] string Group name
         * * $groupDefinition['title'] string i18n key for title (optional, can be omitted
-        * *  only if none of the filters in the group display in the structured UI)
+        *     only if none of the filters in the group display in the structured UI)
         * * $groupDefinition['priority'] int Priority integer.  Higher means higher in the
-        * *  group list.
+        *     group list.
         * * $groupDefinition['filters'] array Numeric array of filter definitions, each of which
-        * *  is an associative array to be passed to the filter constructor.  However,
-        * *  'priority' is optional for the filters.  Any filter that has priority unset
-        * *  will be put to the bottom, in the order given.
+        *     is an associative array to be passed to the filter constructor.  However,
+        *     'priority' is optional for the filters.  Any filter that has priority unset
+        *     will be put to the bottom, in the order given.
         * * $groupDefinition['default'] string Default for group.
         * * $groupDefinition['isFullCoverage'] bool Whether the group is full coverage;
-        * *  if true, this means that checking every item in the group means no
-        * *  changes list entries are filtered out.
+        *     if true, this means that checking every item in the group means no
+        *     changes list entries are filtered out.
         * * $groupDefinition['queryCallable'] callable Callable accepting parameters:
-        *  string $specialPageClassName Class name of current special page
-        *  IContextSource $context Context, for e.g. user
-        *  IDatabase $dbr Database, for addQuotes, makeList, and similar
-        *  array &$tables Array of tables; see IDatabase::select $table
-        *  array &$fields Array of fields; see IDatabase::select $vars
-        *  array &$conds Array of conditions; see IDatabase::select $conds
-        *  array &$query_options Array of query options; see IDatabase::select $options
-        *  array &$join_conds Array of join conditions; see IDatabase::select $join_conds
-        *  array $selectedValues The allowed and requested values, lower-cased and sorted
+        *      * string $specialPageClassName Class name of current special page
+        *      * IContextSource $context Context, for e.g. user
+        *      * IDatabase $dbr Database, for addQuotes, makeList, and similar
+        *      * array &$tables Array of tables; see IDatabase::select $table
+        *      * array &$fields Array of fields; see IDatabase::select $vars
+        *      * array &$conds Array of conditions; see IDatabase::select $conds
+        *      * array &$query_options Array of query options; see IDatabase::select $options
+        *      * array &$join_conds Array of join conditions; see IDatabase::select $join_conds
+        *      * array $selectedValues The allowed and requested values, lower-cased and sorted
         * * $groupDefinition['whatsThisHeader'] string i18n key for header of "What's
-        * *  This" popup (optional).
+        *     This" popup (optional).
         * * $groupDefinition['whatsThisBody'] string i18n key for body of "What's This"
-        * *  popup (optional).
+        *     popup (optional).
         * * $groupDefinition['whatsThisUrl'] string URL for main link of "What's This"
-        * *  popup (optional).
+        *     popup (optional).
         * * $groupDefinition['whatsThisLinkText'] string i18n key of text for main link of
-        * *  "What's This" popup (optional).
+        *     "What's This" popup (optional).
         */
        public function __construct( array $groupDefinition ) {
                if ( !isset( $groupDefinition['isFullCoverage'] ) ) {
index fd5c3f7..880cf9f 100644 (file)
@@ -73,7 +73,7 @@ class EtcdConfig implements Config, LoggerAwareInterface {
                        'encoding' => 'JSON',
                        'cacheTTL' => 10,
                        'skewTTL' => 1,
-                       'timeout' => 10
+                       'timeout' => 2
                ];
 
                $this->host = $params['host'];
@@ -215,7 +215,7 @@ class EtcdConfig implements Config, LoggerAwareInterface {
                        }
 
                        // Avoid the server next time if that failed
-                       $dsd->removeServer( $server, $servers );
+                       $servers = $dsd->removeServer( $server, $servers );
                } while ( $servers );
 
                return [ $config, $error, $retry ];
index 843d540..3028dfd 100644 (file)
@@ -6,7 +6,7 @@
  * but instead manually called by WikitextHandler.
  * This should be fixed in the future.
  */
-class FileContentHandler extends WikitextContentHandler  {
+class FileContentHandler extends WikitextContentHandler {
 
        public function getFieldsForSearchIndex( SearchEngine $engine ) {
                $fields['file_media_type'] =
index 12e8dd1..7028224 100644 (file)
@@ -1016,7 +1016,7 @@ abstract class Installer {
                }
 
                # Try the most common ones.
-               $commonLocales = [ 'en_US.UTF-8', 'en_US.utf8', 'de_DE.UTF-8', 'de_DE.utf8' ];
+               $commonLocales = [ 'C.UTF-8', 'en_US.UTF-8', 'en_US.utf8', 'de_DE.UTF-8', 'de_DE.utf8' ];
                foreach ( $commonLocales as $commonLocale ) {
                        if ( isset( $candidatesByLocale[$commonLocale] ) ) {
                                $this->setVar( 'wgShellLocale', $commonLocale );
index 697188e..7df1009 100644 (file)
@@ -241,7 +241,7 @@ class LocalSettingsGenerator {
                }
 
                if ( !$this->values['wgShellLocale'] ) {
-                       $this->values['wgShellLocale'] = 'en_US.UTF-8';
+                       $this->values['wgShellLocale'] = 'C.UTF-8';
                        $locale = '#';
                } else {
                        $locale = '';
index 558e32c..8dd6193 100644 (file)
@@ -92,12 +92,12 @@ class Interwiki {
        }
 
        /**
-        * Returns all interwiki prefixes
+        * Returns all interwiki prefix definitions.
         *
         * @deprecated since 1.28, unused. Use InterwikiLookup instead.
         *
         * @param string|null $local If set, limits output to local/non-local interwikis
-        * @return array List of prefixes
+        * @return array[] List of interwiki rows
         * @since 1.19
         */
        public static function getAllPrefixes( $local = null ) {
index d0a7719..697e39d 100644 (file)
@@ -47,10 +47,21 @@ interface InterwikiLookup {
        public function fetch( $prefix );
 
        /**
-        * Returns all interwiki prefixes
+        * Returns information about all interwiki prefixes, in the form of rows
+        * of the interwiki table. Each row may have the following keys:
+        *
+        * - iw_prefix: the prefix. Always present.
+        * - iw_url: the URL to use for linking, with $1 as a placeholder for the target page.
+        *           Always present.
+        * - iw_api: the URL of the API. Optional.
+        * - iw_wikiid: the wiki ID (usually the database name for local wikis). Optional.
+        * - iw_local: whether the wiki is local, and the "magic redirect" mechanism should apply.
+        *             Defaults to false.
+        * - iw_trans: whether "scary transclusion" is allowed for this site.
+        *             Defaults to false.
         *
         * @param string|null $local If set, limits output to local/non-local interwikis
-        * @return string[] List of prefixes
+        * @return array[] interwiki rows.
         */
        public function getAllPrefixes( $local = null );
 
index 60d6f43..3baea1a 100644 (file)
@@ -87,16 +87,20 @@ class InterwikiLookupAdapter implements InterwikiLookup {
         * See InterwikiLookup::getAllPrefixes
         *
         * @param string|null $local If set, limits output to local/non-local interwikis
-        * @return string[] List of prefixes
+        * @return array[] interwiki rows
         */
        public function getAllPrefixes( $local = null ) {
-               if ( $local === null ) {
-                       return array_keys( $this->getInterwikiMap() );
-               }
                $res = [];
                foreach ( $this->getInterwikiMap() as $interwikiId => $interwiki ) {
-                       if ( $interwiki->isLocal() === $local ) {
-                               $res[] = $interwikiId;
+                       if ( $local === null || $interwiki->isLocal() === $local ) {
+                               $res[] = [
+                                       'iw_prefix' => $interwikiId,
+                                       'iw_url' => $interwiki->getURL(),
+                                       'iw_api' => $interwiki->getAPI(),
+                                       'iw_wikiid' => $interwiki->getWikiID(),
+                                       'iw_local' => $interwiki->isLocal(),
+                                       'iw_trans' => $interwiki->isTranscludable(),
+                               ];
                        }
                }
                return $res;
index c123619..eb367af 100644 (file)
@@ -231,7 +231,6 @@ class RecentChangesUpdateJob extends Job {
                                        ],
                                        __METHOD__
                                );
-
                        },
                        __METHOD__
                );
index 4a6e3fb..e55bebc 100644 (file)
@@ -63,8 +63,8 @@ class IEUrlExtension {
                // Check QUERY_STRING or REQUEST_URI
                if ( isset( $vars['SERVER_SOFTWARE'] )
                        && isset( $vars['REQUEST_URI'] )
-                       && self::haveUndecodedRequestUri( $vars['SERVER_SOFTWARE'] ) )
-               {
+                       && self::haveUndecodedRequestUri( $vars['SERVER_SOFTWARE'] )
+               {
                        $urlPart = $vars['REQUEST_URI'];
                } elseif ( isset( $vars['QUERY_STRING'] ) ) {
                        $urlPart = $vars['QUERY_STRING'];
@@ -79,8 +79,8 @@ class IEUrlExtension {
                // Some servers have PATH_INFO but not REQUEST_URI, so we check both
                // to be on the safe side.
                if ( isset( $vars['PATH_INFO'] )
-                       && self::isUrlExtensionBad( $vars['PATH_INFO'], $extWhitelist ) )
-               {
+                       && self::isUrlExtensionBad( $vars['PATH_INFO'], $extWhitelist )
+               {
                        return true;
                }
 
@@ -223,8 +223,8 @@ class IEUrlExtension {
                                // If the extension is NOT exe, dll or cgi, return it
                                $extension = substr( $url, $pos, $nextPos - $pos );
                                if ( strcasecmp( $extension, 'exe' ) && strcasecmp( $extension, 'dll' ) &&
-                                       strcasecmp( $extension, 'cgi' ) )
-                               {
+                                       strcasecmp( $extension, 'cgi' )
+                               {
                                        return $extension;
                                }
                                // Else continue looking
index 0d1e527..badcb2b 100644 (file)
@@ -399,8 +399,8 @@ class IEContentAnalyzer {
                $proposedFormat = $this->getDataFormat( $version, $proposed );
                if ( $proposedFormat == 'unknown'
                        && $proposed != 'multipart/mixed'
-                       && $proposed != 'multipart/x-mixed-replace' )
-               {
+                       && $proposed != 'multipart/x-mixed-replace'
+               {
                        return $proposed;
                }
                if ( strval( $chunk ) === '' ) {
@@ -426,15 +426,15 @@ class IEContentAnalyzer {
                        return 'image/gif';
                }
                if ( ( $proposed == 'image/pjpeg' || $proposed == 'image/jpeg' )
-                       && $binaryType == 'image/pjpeg' )
-               {
+                       && $binaryType == 'image/pjpeg'
+               {
                        return $proposed;
                }
                // PNG check added in IE 7
                if ( $version >= 'ie07'
                        && ( $proposed == 'image/x-png' || $proposed == 'image/png' )
-                       && $binaryType == 'image/x-png' )
-               {
+                       && $binaryType == 'image/x-png'
+               {
                        return $proposed;
                }
 
@@ -450,8 +450,8 @@ class IEContentAnalyzer {
                }
                if ( isset( $sampleFound['rdf-tag'] )
                        && isset( $sampleFound['rdf-url'] )
-                       && isset( $sampleFound['rdf-purl'] ) )
-               {
+                       && isset( $sampleFound['rdf-purl'] )
+               {
                        return 'application/rss+xml';
                }
                if ( isset( $sampleFound['atom'] ) ) {
@@ -497,8 +497,8 @@ class IEContentAnalyzer {
                // Freaky heuristics to determine if the data is text or binary
                // The heuristic is of course broken for non-ASCII text
                if ( $counters['ctrl'] != 0 && ( $counters['ff'] + $counters['low'] )
-                       < ( $counters['ctrl'] + $counters['high'] ) * 16 )
-               {
+                       < ( $counters['ctrl'] + $counters['high'] ) * 16
+               {
                        $kindOfBinary = true;
                        $type = $binaryType ? $binaryType : $textType;
                        if ( $type === false ) {
@@ -599,13 +599,13 @@ class IEContentAnalyzer {
 
                if ( $chunk2 == 'BM'
                        && substr( $chunk, 6, 2 ) == "\000\000"
-                       && substr( $chunk, 8, 2 ) == "\000\000" )
-               {
+                       && substr( $chunk, 8, 2 ) == "\000\000"
+               {
                        return 'image/bmp'; // another non-standard MIME
                }
                if ( $chunk4 == 'RIFF'
-                       && substr( $chunk, 8, 4 ) == 'WAVE' )
-               {
+                       && substr( $chunk, 8, 4 ) == 'WAVE'
+               {
                        return 'audio/wav';
                }
                // These were integer literals in IE
@@ -613,8 +613,8 @@ class IEContentAnalyzer {
                if ( $chunk4 == ".sd\000"
                        || $chunk4 == ".snd"
                        || $chunk4 == "\000ds."
-                       || $chunk4 == "dns." )
-               {
+                       || $chunk4 == "dns."
+               {
                        return 'audio/basic';
                }
                if ( $chunk3 == "MM\000" ) {
@@ -648,8 +648,8 @@ class IEContentAnalyzer {
                        return 'video/mpeg';
                }
                if ( $chunk4 == "\001\000\000\000"
-                       && substr( $chunk, 40, 4 ) == ' EMF' )
-               {
+                       && substr( $chunk, 40, 4 ) == ' EMF'
+               {
                        return 'image/x-emf';
                }
                if ( $chunk4 == "\xd7\xcd\xc6\x9a" ) {
@@ -789,8 +789,8 @@ class IEContentAnalyzer {
                        if ( !strncasecmp( $remainder, $rdfUrl, strlen( $rdfUrl ) ) ) {
                                $found['rdf-url'] = true;
                                if ( isset( $found['rdf-tag'] )
-                                       && isset( $found['rdf-purl'] ) // [sic]
-                               {
+                                       && isset( $found['rdf-purl'] ) // [sic]
+                               {
                                        break;
                                }
                                continue;
@@ -798,8 +798,8 @@ class IEContentAnalyzer {
 
                        if ( !strncasecmp( $remainder, $rdfPurl, strlen( $rdfPurl ) ) ) {
                                if ( isset( $found['rdf-tag'] )
-                                       && isset( $found['rdf-url'] ) // [sic]
-                               {
+                                       && isset( $found['rdf-url'] ) // [sic]
+                               {
                                        break;
                                }
                                continue;
index 6ea3c21..d03bc48 100644 (file)
@@ -735,8 +735,8 @@ EOT;
                        ( strpos( $head, "<\x00?\x00 " ) !== false ) ||
                        ( strpos( $head, "<\x00?\x00\n" ) !== false ) ||
                        ( strpos( $head, "<\x00?\x00\t" ) !== false ) ||
-                       ( strpos( $head, "<\x00?\x00=" ) !== false ) ) {
-
+                       ( strpos( $head, "<\x00?\x00=" ) !== false )
+               ) {
                        $this->logger->info( __METHOD__ . ": recognized $file as application/x-php\n" );
                        return 'application/x-php';
                }
@@ -1035,7 +1035,6 @@ EOT;
                // Special code for ogg - detect if it's video (theora),
                // else label it as sound.
                if ( $mime == 'application/ogg' && file_exists( $path ) ) {
-
                        // Read a chunk of the file
                        $f = fopen( $path, "rt" );
                        if ( !$f ) {
index 6481c92..c15572c 100644 (file)
@@ -8,7 +8,7 @@ use InvalidArgumentException;
  * Helper class to handle automatically marking connections as reusable (via RAII pattern)
  * as well handling deferring the actual network connection until the handle is used
  *
- * @note: proxy methods are defined explicity to avoid interface errors
+ * @note: proxy methods are defined explicitly to avoid interface errors
  * @ingroup Database
  * @since 1.22
  */
index 88a883a..3bb7e6a 100644 (file)
@@ -833,9 +833,10 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        $sql,
                        $matches
                ) ) {
+                       $isTemp = isset( $this->mSessionTempTables[$matches[1]] );
                        unset( $this->mSessionTempTables[$matches[1]] );
 
-                       return true;
+                       return $isTemp;
                } elseif ( preg_match(
                        '/^(?:INSERT\s+(?:\w+\s+)?INTO|UPDATE|DELETE\s+FROM)\s+[`"\']?(\w+)[`"\']?/i',
                        $sql,
index 613dac5..8bbf9e5 100644 (file)
@@ -28,14 +28,12 @@ class LoadMonitorNull implements ILoadMonitor {
        public function __construct(
                ILoadBalancer $lb, BagOStuff $sCache, BagOStuff $cCache, array $options = []
        ) {
-
        }
 
        public function setLogger( LoggerInterface $logger ) {
        }
 
        public function scaleLoads( array &$loads, $domain ) {
-
        }
 
        public function getLagTimes( array $serverIndexes, $domain ) {
@@ -43,6 +41,5 @@ class LoadMonitorNull implements ILoadMonitor {
        }
 
        public function clearCaches() {
-
        }
 }
index dd1976c..a8af714 100644 (file)
@@ -69,7 +69,7 @@ class SamplingStatsdClient extends StatsdClient {
                return $data;
        }
 
-       /*
+       /**
         * Send the metrics over UDP
         * Sample the metrics according to their sample rate and send the remaining ones.
         *
index f1df7f1..9d886bf 100644 (file)
@@ -272,7 +272,6 @@ class XMPReader implements LoggerAwareInterface {
                if ( isset( $data['xmp-exif']['GPSAltitudeRef'] )
                        && isset( $data['xmp-exif']['GPSAltitude'] )
                ) {
-
                        // Must convert to a real before multiplying by -1
                        // XMPValidate guarantees there will always be a '/' in this value.
                        list( $nom, $denom ) = explode( '/', $data['xmp-exif']['GPSAltitude'] );
@@ -1004,7 +1003,6 @@ class XMPReader implements LoggerAwareInterface {
         */
        private function startElementModeInitial( $ns, $tag, $attribs ) {
                if ( $ns !== self::NS_RDF ) {
-
                        if ( isset( $this->items[$ns][$tag] ) ) {
                                if ( isset( $this->items[$ns][$tag]['structPart'] ) ) {
                                        // If this element is supposed to appear only as
@@ -1066,7 +1064,6 @@ class XMPReader implements LoggerAwareInterface {
         */
        private function startElementModeStruct( $ns, $tag, $attribs ) {
                if ( $ns !== self::NS_RDF ) {
-
                        if ( isset( $this->items[$ns][$tag] ) ) {
                                if ( isset( $this->items[$ns][$this->ancestorStruct]['children'] )
                                        && !isset( $this->items[$ns][$this->ancestorStruct]['children'][$tag] )
index 7aeefa0..0e10abb 100644 (file)
@@ -30,7 +30,6 @@
 class ExifBitmapHandler extends BitmapHandler {
        const BROKEN_FILE = '-1'; // error extracting metadata
        const OLD_BROKEN_FILE = '0'; // outdated error extracting metadata.
-       const SRGB_ICC_PROFILE_NAME = 'IEC 61966-2.1 Default RGB colour space - sRGB';
 
        function convertMetadataVersion( $metadata, $version = 1 ) {
                // basically flattens arrays.
@@ -243,75 +242,4 @@ class ExifBitmapHandler extends BitmapHandler {
 
                return 0;
        }
-
-       protected function transformImageMagick( $image, $params ) {
-               global $wgUseTinyRGBForJPGThumbnails;
-
-               $ret = parent::transformImageMagick( $image, $params );
-
-               if ( $ret ) {
-                       return $ret;
-               }
-
-               if ( $params['mimeType'] === 'image/jpeg' && $wgUseTinyRGBForJPGThumbnails ) {
-                       // T100976 If the profile embedded in the JPG is sRGB, swap it for the smaller
-                       // (and free) TinyRGB
-
-                       $this->swapICCProfile(
-                               $params['dstPath'],
-                               self::SRGB_ICC_PROFILE_NAME,
-                               realpath( __DIR__ ) . '/tinyrgb.icc'
-                       );
-               }
-
-               return false;
-       }
-
-       /**
-        * Swaps an embedded ICC profile for another, if found.
-        * Depends on exiftool, no-op if not installed.
-        * @param string $filepath File to be manipulated (will be overwritten)
-        * @param string $oldProfileString Exact name of color profile to look for
-        *  (the one that will be replaced)
-        * @param string $profileFilepath ICC profile file to apply to the file
-        * @since 1.26
-        * @return bool
-        */
-       public function swapICCProfile( $filepath, $oldProfileString, $profileFilepath ) {
-               global $wgExiftool;
-
-               if ( !$wgExiftool || !is_executable( $wgExiftool ) ) {
-                       return false;
-               }
-
-               $cmd = wfEscapeShellArg( $wgExiftool,
-                       '-DeviceModelDesc',
-                       '-S',
-                       '-T',
-                       $filepath
-               );
-
-               $output = wfShellExecWithStderr( $cmd, $retval );
-
-               if ( $retval !== 0 || strcasecmp( trim( $output ), $oldProfileString ) !== 0 ) {
-                       // We can't establish that this file has the expected ICC profile, don't process it
-                       return false;
-               }
-
-               $cmd = wfEscapeShellArg( $wgExiftool,
-                       '-overwrite_original',
-                       '-icc_profile<=' . $profileFilepath,
-                       $filepath
-               );
-
-               $output = wfShellExecWithStderr( $cmd, $retval );
-
-               if ( $retval !== 0 ) {
-                       $this->logErrorForExternalProcess( $retval, $output, $cmd );
-
-                       return false;
-               }
-
-               return true;
-       }
 }
index c9f0dfa..5822699 100644 (file)
@@ -31,6 +31,8 @@
  * @ingroup Media
  */
 class JpegHandler extends ExifBitmapHandler {
+       const SRGB_EXIF_COLOR_SPACE = 'sRGB';
+       const SRGB_ICC_PROFILE_DESCRIPTION = 'sRGB IEC61966-2.1';
 
        function normaliseParams( $image, &$params ) {
                if ( !parent::normaliseParams( $image, $params ) ) {
@@ -171,4 +173,118 @@ class JpegHandler extends ExifBitmapHandler {
 
                return $params;
        }
+
+       /**
+        * {@inheritdoc}
+        */
+       protected function transformImageMagick( $image, $params ) {
+               global $wgUseTinyRGBForJPGThumbnails;
+
+               $ret = parent::transformImageMagick( $image, $params );
+
+               if ( $ret ) {
+                       return $ret;
+               }
+
+               if ( $wgUseTinyRGBForJPGThumbnails ) {
+                       // T100976 If the profile embedded in the JPG is sRGB, swap it for the smaller
+                       // (and free) TinyRGB
+
+                       /**
+                        * We'll want to replace the color profile for JPGs:
+                        * * in the sRGB color space, or with the sRGB profile
+                        *   (other profiles will be left untouched)
+                        * * without color space or profile, in which case browsers
+                        *   should assume sRGB, but don't always do (e.g. on wide-gamut
+                        *   monitors (unless it's meant for low bandwith)
+                        * @see https://phabricator.wikimedia.org/T134498
+                        */
+                       $colorSpaces = [ self::SRGB_EXIF_COLOR_SPACE, '-' ];
+                       $profiles = [ self::SRGB_ICC_PROFILE_DESCRIPTION ];
+
+                       // we'll also add TinyRGB profile to images lacking a profile, but
+                       // only if they're not low quality (which are meant to save bandwith
+                       // and we don't want to increase the filesize by adding a profile)
+                       if ( $params['quality'] > 30 ) {
+                               $profiles[] = '-';
+                       }
+
+                       $this->swapICCProfile(
+                               $params['dstPath'],
+                               $colorSpaces,
+                               $profiles,
+                               realpath( __DIR__ ) . '/tinyrgb.icc'
+                       );
+               }
+
+               return false;
+       }
+
+       /**
+        * Swaps an embedded ICC profile for another, if found.
+        * Depends on exiftool, no-op if not installed.
+        * @param string $filepath File to be manipulated (will be overwritten)
+        * @param array $colorSpaces Only process files with this/these Color Space(s)
+        * @param array $oldProfileStrings Exact name(s) of color profile to look for
+        *  (the one that will be replaced)
+        * @param string $profileFilepath ICC profile file to apply to the file
+        * @since 1.26
+        * @return bool
+        */
+       public function swapICCProfile( $filepath, array $colorSpaces,
+                                                                       array $oldProfileStrings, $profileFilepath
+       ) {
+               global $wgExiftool;
+
+               if ( !$wgExiftool || !is_executable( $wgExiftool ) ) {
+                       return false;
+               }
+
+               $cmd = wfEscapeShellArg( $wgExiftool,
+                       '-EXIF:ColorSpace',
+                       '-ICC_Profile:ProfileDescription',
+                       '-S',
+                       '-T',
+                       $filepath
+               );
+
+               $output = wfShellExecWithStderr( $cmd, $retval );
+
+               // Explode EXIF data into an array with [0 => Color Space, 1 => Device Model Desc]
+               $data = explode( "\t", trim( $output ) );
+
+               if ( $retval !== 0 ) {
+                       return false;
+               }
+
+               // Make a regex out of the source data to match it to an array of color
+               // spaces in a case-insensitive way
+               $colorSpaceRegex = '/'.preg_quote( $data[0], '/' ).'/i';
+               if ( empty( preg_grep( $colorSpaceRegex, $colorSpaces ) ) ) {
+                       // We can't establish that this file matches the color space, don't process it
+                       return false;
+               }
+
+               $profileRegex = '/'.preg_quote( $data[1], '/' ).'/i';
+               if ( empty( preg_grep( $profileRegex, $oldProfileStrings ) ) ) {
+                       // We can't establish that this file has the expected ICC profile, don't process it
+                       return false;
+               }
+
+               $cmd = wfEscapeShellArg( $wgExiftool,
+                       '-overwrite_original',
+                       '-icc_profile<=' . $profileFilepath,
+                       $filepath
+               );
+
+               $output = wfShellExecWithStderr( $cmd, $retval );
+
+               if ( $retval !== 0 ) {
+                       $this->logErrorForExternalProcess( $retval, $output, $cmd );
+
+                       return false;
+               }
+
+               return true;
+       }
 }
index 19f368a..5b1e86d 100644 (file)
@@ -3476,7 +3476,7 @@ class Parser {
 
                if ( !$title->equals( $cacheTitle ) ) {
                        $this->mTplRedirCache[$cacheTitle->getPrefixedDBkey()] =
-                               [ $title->getNamespace(), $cdb = $title->getDBkey() ];
+                               [ $title->getNamespace(), $title->getDBkey() ];
                }
 
                return [ $dom, $title ];
index d0b66f8..353825a 100644 (file)
@@ -24,8 +24,7 @@
 /**
  * @ingroup Parser
  */
-class ParserDiffTest
-{
+class ParserDiffTest {
        public $parsers;
        public $conf;
        public $shortOutput = false;
index 6bb4e5a..4473bb2 100644 (file)
@@ -455,8 +455,8 @@ abstract class SearchEngine {
                        $title = Title::newFromText( $search . 'Dummy' );
                        if ( $title && $title->getText() == 'Dummy'
                                        && $title->getNamespace() != NS_MAIN
-                                       && !$title->isExternal() )
-                       {
+                                       && !$title->isExternal()
+                       {
                                $ns = [ $title->getNamespace() ];
                                $search = '';
                        } else {
index bad0ef9..633cfc9 100644 (file)
@@ -303,7 +303,7 @@ class ServiceContainer implements DestructibleService {
 
                $instance = $this->peekService( $name );
 
-               if ( $destroy && $instance instanceof DestructibleService )  {
+               if ( $destroy && $instance instanceof DestructibleService ) {
                        $instance->destroy();
                }
 
index 3f6d865..7e70df2 100644 (file)
@@ -255,79 +255,79 @@ abstract class ChangesListSpecialPage extends SpecialPage {
                        // reviewStatus (conditional)
 
                        [
-                               'name' => 'lastRevision',
-                               'title' => 'rcfilters-filtergroup-lastRevision',
+                               'name' => 'significance',
+                               'title' => 'rcfilters-filtergroup-significance',
                                'class' => ChangesListBooleanFilterGroup::class,
-                               'priority' => -7,
+                               'priority' => -6,
                                'filters' => [
                                        [
-                                               'name' => 'hidelastrevision',
-                                               'label' => 'rcfilters-filter-lastrevision-label',
-                                               'description' => 'rcfilters-filter-lastrevision-description',
+                                               'name' => 'hideminor',
+                                               'label' => 'rcfilters-filter-minor-label',
+                                               'description' => 'rcfilters-filter-minor-description',
+                                               // rcshowhideminor-show, rcshowhideminor-hide,
+                                               // wlshowhideminor
+                                               'showHideSuffix' => 'showhideminor',
                                                'default' => false,
                                                'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
                                                        &$query_options, &$join_conds ) {
-                                                       $conds[] = 'rc_this_oldid <> page_latest';
+
+                                                       $conds[] = 'rc_minor = 0';
                                                },
-                                               'cssClassSuffix' => 'last',
+                                               'cssClassSuffix' => 'minor',
                                                'isRowApplicableCallable' => function ( $ctx, $rc ) {
-                                                       return $rc->getAttribute( 'rc_this_oldid' ) === $rc->getAttribute( 'page_latest' );
+                                                       return $rc->getAttribute( 'rc_minor' );
                                                }
                                        ],
                                        [
-                                               'name' => 'hidepreviousrevisions',
-                                               'label' => 'rcfilters-filter-previousrevision-label',
-                                               'description' => 'rcfilters-filter-previousrevision-description',
+                                               'name' => 'hidemajor',
+                                               'label' => 'rcfilters-filter-major-label',
+                                               'description' => 'rcfilters-filter-major-description',
                                                'default' => false,
                                                'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
                                                        &$query_options, &$join_conds ) {
-                                                       $conds[] = 'rc_this_oldid = page_latest';
+
+                                                       $conds[] = 'rc_minor = 1';
                                                },
-                                               'cssClassSuffix' => 'previous',
+                                               'cssClassSuffix' => 'major',
                                                'isRowApplicableCallable' => function ( $ctx, $rc ) {
-                                                       return $rc->getAttribute( 'rc_this_oldid' ) !== $rc->getAttribute( 'page_latest' );
+                                                       return !$rc->getAttribute( 'rc_minor' );
                                                }
                                        ]
                                ]
                        ],
 
                        [
-                               'name' => 'significance',
-                               'title' => 'rcfilters-filtergroup-significance',
+                               'name' => 'lastRevision',
+                               'title' => 'rcfilters-filtergroup-lastRevision',
                                'class' => ChangesListBooleanFilterGroup::class,
-                               'priority' => -6,
+                               'priority' => -7,
                                'filters' => [
                                        [
-                                               'name' => 'hideminor',
-                                               'label' => 'rcfilters-filter-minor-label',
-                                               'description' => 'rcfilters-filter-minor-description',
-                                               // rcshowhideminor-show, rcshowhideminor-hide,
-                                               // wlshowhideminor
-                                               'showHideSuffix' => 'showhideminor',
+                                               'name' => 'hidelastrevision',
+                                               'label' => 'rcfilters-filter-lastrevision-label',
+                                               'description' => 'rcfilters-filter-lastrevision-description',
                                                'default' => false,
                                                'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
                                                        &$query_options, &$join_conds ) {
-
-                                                       $conds[] = 'rc_minor = 0';
+                                                       $conds[] = 'rc_this_oldid <> page_latest';
                                                },
-                                               'cssClassSuffix' => 'minor',
+                                               'cssClassSuffix' => 'last',
                                                'isRowApplicableCallable' => function ( $ctx, $rc ) {
-                                                       return $rc->getAttribute( 'rc_minor' );
+                                                       return $rc->getAttribute( 'rc_this_oldid' ) === $rc->getAttribute( 'page_latest' );
                                                }
                                        ],
                                        [
-                                               'name' => 'hidemajor',
-                                               'label' => 'rcfilters-filter-major-label',
-                                               'description' => 'rcfilters-filter-major-description',
+                                               'name' => 'hidepreviousrevisions',
+                                               'label' => 'rcfilters-filter-previousrevision-label',
+                                               'description' => 'rcfilters-filter-previousrevision-description',
                                                'default' => false,
                                                'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
                                                        &$query_options, &$join_conds ) {
-
-                                                       $conds[] = 'rc_minor = 1';
+                                                       $conds[] = 'rc_this_oldid = page_latest';
                                                },
-                                               'cssClassSuffix' => 'major',
+                                               'cssClassSuffix' => 'previous',
                                                'isRowApplicableCallable' => function ( $ctx, $rc ) {
-                                                       return !$rc->getAttribute( 'rc_minor' );
+                                                       return $rc->getAttribute( 'rc_this_oldid' ) !== $rc->getAttribute( 'page_latest' );
                                                }
                                        ]
                                ]
@@ -730,10 +730,10 @@ abstract class ChangesListSpecialPage extends SpecialPage {
        /**
         * Get filter group definition from legacy custom filters
         *
-        * @param array Custom filters from legacy hooks
+        * @param array $customFilters Custom filters from legacy hooks
         * @return array Group definition
         */
-       protected function getFilterGroupDefinitionFromLegacyCustomFilters( $customFilters ) {
+       protected function getFilterGroupDefinitionFromLegacyCustomFilters( array $customFilters ) {
                // Special internal unstructured group
                $unstructuredGroupDefinition = [
                        'name' => 'unstructured',
@@ -960,7 +960,86 @@ abstract class ChangesListSpecialPage extends SpecialPage {
         * @param FormOptions $opts
         */
        public function validateOptions( FormOptions $opts ) {
-               // nothing by default
+               if ( $this->fixContradictoryOptions( $opts ) ) {
+                       $query = wfArrayToCgi( $this->convertParamsForLink( $opts->getChangedValues() ) );
+                       $this->getOutput()->redirect( $this->getPageTitle()->getCanonicalURL( $query ) );
+               }
+       }
+
+       /**
+        * Fix invalid options by resetting pairs that should never appear together.
+        *
+        * @param FormOptions $opts
+        * @return bool True if any option was reset
+        */
+       private function fixContradictoryOptions( FormOptions $opts ) {
+               $contradictorySets = [];
+
+               $fixed = $this->fixBackwardsCompatibilityOptions( $opts );
+
+               foreach ( $this->filterGroups as $filterGroup ) {
+                       if ( $filterGroup instanceof ChangesListBooleanFilterGroup ) {
+                               $filters = $filterGroup->getFilters();
+                               $allInGroupEnabled = array_reduce(
+                                       $filters,
+                                       function ( $carry, $filter ) use ( $opts ) {
+                                               return $carry && $opts[ $filter->getName() ];
+                                       },
+                                       /* initialValue */ count( $filters ) > 0
+                               );
+
+                               if ( $allInGroupEnabled ) {
+                                       foreach ( $filters as $filter ) {
+                                               $opts->reset( $filter->getName() );
+                                       }
+
+                                       $fixed = true;
+                               }
+                       }
+               }
+
+               return $fixed;
+       }
+
+       /**
+        * Fix a special case (hideanons=1 and hideliu=1) in a special way, for backwards
+        * compatibility.
+        *
+        * This is deprecated and may be removed.
+        *
+        * @param FormOptions $opts
+        * @return bool True if this change was mode
+        */
+       private function fixBackwardsCompatibilityOptions( FormOptions $opts ) {
+               if ( $opts['hideanons'] && $opts['hideliu'] ) {
+                       $opts->reset( 'hideanons' );
+                       if ( !$opts['hidebots'] ) {
+                               $opts->reset( 'hideliu' );
+                               $opts['hidehumans'] = 1;
+                       }
+
+                       return true;
+               }
+
+               return false;
+       }
+
+       /**
+        * Convert parameters values from true/false to 1/0
+        * so they are not omitted by wfArrayToCgi()
+        * Bug 36524
+        *
+        * @param array $params
+        * @return array
+        */
+       protected function convertParamsForLink( $params ) {
+               foreach ( $params as &$value ) {
+                       if ( $value === false ) {
+                               $value = '0';
+                       }
+               }
+               unset( $value );
+               return $params;
        }
 
        /**
@@ -1049,15 +1128,6 @@ abstract class ChangesListSpecialPage extends SpecialPage {
                        ''
                );
 
-               // It makes no sense to hide both anons and logged-in users. When this occurs, try a guess on
-               // what the user meant and either show only bots or force anons to be shown.
-
-               // -------
-
-               // XXX: We're no longer doing this handling.  To preserve back-compat, we need to complete
-               // T151873 (particularly the hideanons/hideliu/hidebots/hidehumans part) in conjunction
-               // with merging this.
-
                if ( !$this->runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds,
                        $opts )
                ) {
@@ -1251,6 +1321,8 @@ abstract class ChangesListSpecialPage extends SpecialPage {
         * @param array &$query_options Array of query options; see IDatabase::select $options
         * @param array &$join_conds Array of join conditions; see IDatabase::select $join_conds
         * @param array $selectedExpLevels The allowed active values, sorted
+        * @param int $now Number of seconds since the UNIX epoch, or 0 if not given
+        *   (optional)
         */
        public function filterOnUserExperienceLevel( $specialPageClassName, $context, $dbr,
                &$tables, &$fields, &$conds, &$query_options, &$join_conds, $selectedExpLevels, $now = 0 ) {
index a47d91b..c10dbdd 100644 (file)
@@ -167,7 +167,7 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
                        $jsData = $this->getStructuredFilterJsData();
 
                        $messages = [];
-                       foreach ( $jsData['messageKeys'] as $key ){
+                       foreach ( $jsData['messageKeys'] as $key ) {
                                $messages[$key] = $this->msg( $key )->plain();
                        }
 
@@ -814,16 +814,7 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
         * @return string
         */
        function makeOptionsLink( $title, $override, $options, $active = false ) {
-               $params = $override + $options;
-
-               // T38524: false values have be converted to "0" otherwise
-               // wfArrayToCgi() will omit it them.
-               foreach ( $params as &$value ) {
-                       if ( $value === false ) {
-                               $value = '0';
-                       }
-               }
-               unset( $value );
+               $params = $this->convertParamsForLink( $override + $options );
 
                if ( $active ) {
                        $title = new HtmlArmor( '<strong>' . htmlspecialchars( $title ) . '</strong>' );
index bb1e751..5dd4be1 100644 (file)
@@ -522,7 +522,6 @@ class User implements IDBAccessObject {
                                }
 
                                return $data;
-
                        },
                        [ 'pcTTL' => $cache::TTL_PROC_LONG, 'version' => self::VERSION ]
                );
index 1dac0b1..54a8677 100644 (file)
@@ -212,7 +212,6 @@ global \${$this->variableName};
 ];
 
 EOD;
-
        }
 
        /**
index e107fb1..cab6a3d 100644 (file)
@@ -87,9 +87,9 @@ class BatchRowIterator implements RecursiveIterator {
 
        /**
         * @param IDatabase $db The database to read from
-        * @param string|array $table      The name or names of the table to read from
+        * @param string|array $table The name or names of the table to read from
         * @param string|array $primaryKey The name or names of the primary key columns
-        * @param integer      $batchSize  The number of rows to fetch per iteration
+        * @param integer $batchSize The number of rows to fetch per iteration
         * @throws InvalidArgumentException
         */
        public function __construct( IDatabase $db, $table, $primaryKey, $batchSize ) {
index 04e1e21..4df2eb5 100644 (file)
@@ -14,7 +14,7 @@ use Html;
  * interwiki prefix. Includes a per-wiki header indicating where
  * the results are from.
  */
-class SimpleSearchResultSetWidget implements SearchResultSetWidget{
+class SimpleSearchResultSetWidget implements SearchResultSetWidget {
        /** @var SpecialSearch */
        protected $specialSearch;
        /** @var SearchResultWidget */
index 6f2117c..0cddc99 100644 (file)
  */
 
 /**
- * A fake language converter
+ * A fake language variant converter. Languages which do not implement variant
+ * conversion, for example, English, should return a FakeConverter rather than a
+ * LanguageConverter when asked for their converter. The fake converter just
+ * returns text unchanged, i.e. it doesn't do any conversion.
+ *
+ * See https://www.mediawiki.org/wiki/Writing_systems#LanguageConverter.
  *
  * @ingroup Language
  */
index 4002e30..9204a44 100644 (file)
        "tooltip-t-recentchangeslinked": "أحدث التغييرات في الصفحات الموصولة من هذه الصفحة",
        "tooltip-feed-rss": "تلقيم أر إس إس لهذه الصفحة",
        "tooltip-feed-atom": "تلقيم أتوم لهذه الصفحة",
-       "tooltip-t-contributions": "رؤية قائمة مساهمات {{GENDER:$1|this user}}",
+       "tooltip-t-contributions": "رؤية قائمة مساهمات {{GENDER:$1|هذا المستخدم|هذه المستخدمة}}",
        "tooltip-t-emailuser": "أرسل رسالة {{GENDER:$1|لهذا المستخدم|لهذه المستخدمة}}",
        "tooltip-t-info": "المزيد من المعلومات عن هذه الصفحة",
        "tooltip-t-upload": "ارفع ملفات",
        "htmlform-user-not-valid": "اسم المستخدم <strong>$1</strong> غير صالح.",
        "logentry-delete-delete": "{{GENDER:$2|حذف|حذفت}} $1 صفحة $3",
        "logentry-delete-delete_redir": "$1 {{GENDER:$2|حذف|حذفت}} التحويلة $3 بواسطة إعادة الكتابة",
-       "logentry-delete-restore": "{{GENDER:$2|استرجع|استرجعت}} الصفحة $3 ($4)",
+       "logentry-delete-restore": "$1 {{GENDER:$2|استرجع|استرجعت}} الصفحة $3 ($4)",
        "logentry-delete-restore-nocount": "$1 {{GENDER:$2|استرجع|استرجعت}} الصفحة $3",
        "restore-count-revisions": "{{PLURAL:$1|1 مراجعة|$1 مراجعة}}",
        "restore-count-files": "{{PLURAL:$1|1 ملف|$1 ملف}}",
index 1c4b210..e10bd39 100644 (file)
        "anoneditwarning": "<strong>تحذير:'</strong> انت ما عملتش لوجين. عنوان الاى  بى  بتاعك هايتسجل ف تاريخ الصفحه. لو  <strong>[$1 عملت لوجين ]</strong> او <strong>[$2 فتحت حساب ]</strong>,   اليوزرنيم بتاعك هايتسجل ف تاريخ الصفحه.",
        "missingsummary": "'''خد بالك:''' انت ما كتبتش ملخص للتعديل.\nلو دوست على سييڤ الصفحه مرة تانية التعديل بتاعك ح يتحفظ من غير ملخص.",
        "missingcommenttext": "لو سمحت اكتب تعليق تحت.",
-       "missingcommentheader": "'''.خد بالك:''' انت ما كتبتش عنوان\\موضوع للتعليق دا\nلو دوست على $1 مرة تانيه، تعليقك ح يتحفظ من غير عنوان.",
+       "missingcommentheader": "<strong>خد بالك:</strong> انت ما كتبتش عنوان\\موضوع للتعليق دا\nلو دوست على $1 مرة تانيه، تعليقك ح يتحفظ من غير عنوان.",
        "summary-preview": "بروفه للملخص:",
        "subject-preview": "بروفة للعنوان/للموضوع",
        "blockedtitle": "اليوزر ممنوع",
index 7ec3a56..5f53772 100644 (file)
@@ -78,6 +78,7 @@
        "subcategories": "Awocamec ke ici arimotcikateki",
        "hidden-categories": "{{PLURAL:$1|Ka katcictek|Ka katcicteki}}",
        "category-subcat-count": "Nohwe tipanictawin {{PLURAL:$2|0=nama takon e ki koski tipanictakaniwok|1=tepirak e ki koski tipanictakaniwok nta takon|takon $2 koski tipanictawina, nte {{PLURAL:$1|0=nama takon|1=nohwe|neki $1}}nta nitc}}.",
+       "category-article-count": "nohwe tipanictawin {{PLURAL:$2|0=nama takon paskickwemakan|1=Enkon nohwe tepirak paskickwemakan|takon $2 paskickwemakana,ohwe tca {{PLURAL:$1|0=nama takon|1=ohwi|nehi $1}} nihi nitc}}.",
        "listingcontinuesabbrev": "minawatc",
        "about": "Taci we otciparik",
        "newwindow": "(cepita kotak ocki osapwakan)",
        "createacct-yourpassword-ph": "Acta pitakesinihikan",
        "createacct-yourpasswordagain": "Naskamowicta pitakesinihikan",
        "createacct-yourpasswordagain-ph": "Minawatc acta pitakesinihikan",
+       "userlogin-remembermypassword": "Kitci cetik mekwact ka ici otamirohian",
        "login": "Posi",
        "logout": "Piskeapikenakan",
        "userlogout": "Piskeapikenakan",
        "createacct-email-ph": "Pitakesinaha ki pamikicikwepitcikan matcetcicihikan",
        "createacct-submit": "Masinahotiso",
        "createacct-benefit-heading": "{{SITENAME}} Iskwewok,iriniwok ka orisinihiketcik mitowi kir.",
+       "createacct-benefit-body1": "{{PLURAL:$1|ki meckotcitakiniwok|ki meckotcitakiniwoki}}",
        "createacct-benefit-body2": "{{PLURAL:$1|masinhikan|masinahikana}}",
+       "createacct-benefit-body3": "ocki {{PLURAL:$1|ka witcihietc|ka witcihietcik}}",
        "loginlanguagelabel": "arimwewin:$1",
        "pt-login": "Posi",
        "pt-login-button": "Posi",
        "anoneditwarning": "<strong>Ekwa :</strong> nama kipitikeapikecinin. Nokon e tatosinatek kit irapitcikan ka pamikicikwakein kaskina wec ici nokon  kecpin e kweskisinihikein. Kecpin tca <strong>[$1wi pitikeapikecinine]</strong> ou <strong>[$2 ocita kata pitakesinasowin]</strong>,nohwe ka kweskisinihikein ki ka masinason e icinikatitisowin ,acit awacimec ki ka ici titamihikowin",
        "loginreqlink": "posi",
        "noarticletext": "Mekwatc nama takon atisokesinihikan nta paskickwemakanik.\nke ki totaman[[Special:Search/{{PAGENAME}}|nantowapaha ohwe icinikatamowin ]] kotakahikw paskickwemakanik,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|paskickwemakan={{FULLPAGENAMEE}}}} nantowapata ka ici  mikowapihikemikak]\nkekotc [{{fullurl:{{FULLPAGENAME}}|tota=orocowata}} ocita paskickwemakan]</span>.",
+       "noarticletext-nopermission": "Mekwatc nama takon atisokesinihikan nta paskickwemakanik.\nke ki totaman[[Special:Search/{{PAGENAME}}|nantowapaha ohwe icinikatamowin ]] kotakahikw paskickwemakanik,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|paskickwemakan={{FULLPAGENAMEE}}}} nantowapaha kotakihi wapatcikaniwoca ohwe ]</span>,nama aric ki mirikwin ohwe kata ocitain paskickwemakan.",
        "editing": "Meckotcita $1",
+       "creating": "$1 Wir tipirowe ka ki ocitatc",
+       "editingsection": "Ka ki meckotcitatc $1 (tipanitakiniwok)",
        "templatesused": "{{PLURAL:$1|tapapitcikan ka apatak |tapapitcikan ka apatak}} nta paskickwemakanik:",
        "template-protected": "(nakataweritcikatew)",
        "template-semiprotected": "(apita nakatoweritakon)",
+       "hiddencategories": "{{PLURAL:$1|tipanictawin katcitin|tipanictawina katcitano}} paskickwemakan tca nohwe nte ici actew :",
        "permissionserrorstext-withaction": "Nama ki ki toten $2 osam {{PLURAL:$1|}} nohwe ka witcikatek kekotc nihi ka wawitcikateki:",
        "moveddeleted-notice": "Paskickwemakan ka ki wepinikatek.\nOhwe wapatcikan nitc ici nokon paskickwemakanik ka ki wepinikateki acit ka ki atcipitcikateki.",
        "content-model-javascript": "JavaScript",
        "viewpagelogs": "Kinawapta kekwan kaki isparik ota masinhikanik",
+       "currentrev-asof": "Owe mekwatc ka icinakok ni apitc ka ocitakiniwokipan $1",
        "revisionasof": "Kiwe kanawapata $1",
        "revision-info": "E tato konekisitc ka koski kanawapatcikatek $1 nohwe {{GENDER:$6|$2}}$7",
        "previousrevision": "← Nictam ka ki masinatek",
        "revdelete-show-file-submit": "Ehe",
        "pagehist": "Ka ki pe icinakok owe masinhikan",
        "history-title": "Kotakihi e itatcitcikatekai $1",
+       "difference-title": "$1 E ci papitoc icinakok",
        "lineno": "E tatosinatek $1 :",
        "editundo": "nama ntwatc",
        "searchresults": "Ka ki nta kiskeritakok",
        "recentchanges-label-unpatrolled": "Nama moci koski tapwatcikatew ka ki meckotcipirik",
        "recentchanges-label-plusminus": " Irikik e tacitcik bytes meckotcipirin e irikwak",
        "recentchanges-legend-heading": "<strong>itekesinihikan:</strong>",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (kirika kanawapata nohwe [[Special:NewPages|taci e ici masinihikatek ocki paskickwemakana]]).",
        "recentchanges-submit": "Wapata",
        "rclistfrom": "Nokota ka ki mameckotciparik nta e otci kitciparik $2$3",
        "rcshowhideminor": "$1 memantcic meckotcipirino",
        "newpages": "Ocki matcecikinakanik",
        "newpages-submit": "Wapata",
        "newpages-username": "Icinikasowin:",
+       "pager-older-n": "{{PLURAL:$1|1 mawtci weckat|$1 mawtci weckat}}",
        "booksources": "E otciparik",
        "booksources-search-legend": "Nantowapata nta kotakahi wapatcikana",
        "booksources-search": "Nanto kiskeritcikatek",
        "namespace_association": "Taci e mamowisinasonaniwok",
        "tooltip-namespace_association": "Tcikisinaha nohwe kikesinahikan kata acotcisinatek kirika taci e mamowisinasinaniwok e aimihitonaniwok kekotc kekwan,taci ka ki orapitcikateki icinikatewina",
        "blanknamespace": "(Ka ici ocitakiniwok)",
+       "contributions": "Wir ka ki witcihietc {{GENDER:$1|User}}",
        "mycontris": "Witcihewin",
        "anoncontribs": "E ki witcihehin",
        "uctop": "(mekwatc)",
        "ipblocklist-submit": "Nantokaskeritcikatek",
        "blocklink": "nokipita",
        "contribslink": "Kaki witcihehin",
+       "movelogpage": "Tipatcimosanihikan ka ki meckotcicinikatcikateki",
        "movesubpagetalktext": "Neta ka arimotcikatek tipatcimosanikanik $1 {{PLURAL:$1|Nota paskickwemakan|Nota paskickwemakana}} kita masinatewa ota.",
        "export": "Matcetciciha masinahikana",
        "allmessages-filter-all": "Kaskina",
        "previousdiff": "Nictam meckotcisinihikan",
        "nextdiff": "Tec meckotcisinihikan",
        "file-info-size": "$1x$2pixels, e irikweckamikak mawtockwemikan:$3nohwe MIME:$4",
+       "svg-long-desc": "SVG kinokewoc, erikokwactepirik $1 × $2 kawactecik, kinokewoc ehitakok: $3",
        "show-big-image": "E otciparik masinahikaniwoc",
        "show-big-image-preview": "E irikweckwemakisitc$1",
+       "show-big-image-other": "Kotak {{PLURAL:$2|erikokowactepirik|erikokowactepiriki}}: $1.",
        "show-big-image-size": "$1 x $2 pixels",
        "ilsubmit": "Nantokaskeritcikatek",
        "monday-at": "ockorkananiwon $1",
        "redirect-submit": "Tapowata",
        "fileduplicatesearch-submit": "Nantokaskeritcikatek",
        "specialpages": "Ka ici wectakaniwok",
+       "tag-filter": "Nihipita nehi[[Special:Tags|balises]] :",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Kicawatcikanicic|Kicawatcikanica}}]] : $2)",
        "tags-source-header": "Ite wetciparik",
        "tags-active-yes": "Ehe",
index 4eb689e..e268345 100644 (file)
        "rcfilters-filter-minor-description": "Праўкі, якія аўтар пазначыў як дробныя.",
        "rcfilters-filter-major-label": "Звычайныя праўкі",
        "rcfilters-filter-major-description": "Праўкі, не пазначаныя як дробныя.",
+       "rcfilters-filtergroup-watchlist": "Старонкі ў сьпісах назіраньня",
        "rcfilters-filtergroup-changetype": "Тып зьмены",
        "rcfilters-filter-pageedits-label": "Рэдагаваньні старонкі",
        "rcfilters-filter-pageedits-description": "Рэдагаваньні вікізьместу, абмеркаваньняў, апісаньняў катэгорыяў…",
index d2529f2..996d234 100644 (file)
        "mergehistory-merge": "[[:$1]]-এর নিচের সংশোধনগুলি [[:$2]]-এর সাথে একত্র করা যাবে। রেডিও বোতাম কলামটি ব্যবহার করে কেবলমাত্র নির্দেশিত সময় ও তার আগের সমস্ত সংশোধন একত্র করুন। লক্ষ্য করুন, পরিভ্রমণ সংযোগ ব্যবহার করলে কলামটি আদি অবস্থায় ফেরত যাবে।",
        "mergehistory-go": "একত্রীকরণযোগ্য সম্পাদনাগুলি দেখানো হোক",
        "mergehistory-submit": "সংশোধনগুলি একত্রীত করুন",
-       "mergehistory-empty": "কোন সংশোধন একত্র করা যাবে না.",
+       "mergehistory-empty": "কোন সংশোধন একত্র করা যাবে না",
        "mergehistory-done": "$1-এর $3{{PLURAL:$3|টি সংশোধন}} [[:$2]]-এর সাথে একত্রিত করা হয়েছে।",
        "mergehistory-fail": "ইতিহাস একত্র করা গেল না। অনুগ্রহ করে পাতাটি ও সময়ের প্যারামিটারগুলি আবার পরীক্ষা করে দেখুন।",
        "mergehistory-fail-bad-timestamp": "সময়তারিখ অবৈধ।",
        "search-section": "($1 পরিচ্ছেদ)",
        "search-category": "($1 বিষয়শ্রেণী)",
        "search-file-match": "(ফাইলের বিষয়বস্তুর সাথে মিলে যায়)",
-       "search-suggest": "আপনি কি \"$1\" বোঝাতে চাচ্ছেন?",
+       "search-suggest": "আপনি কি বোঝাতে চাচ্ছেন: $1",
        "search-rewritten": "$1-এর জন্য অনুসন্ধানের ফলাফল দেখানো হচ্ছে। এর পরিবর্তে $2-এর জন্য অনুসন্ধান করুন।",
        "search-interwiki-caption": "সহপ্রকল্পসমূহ",
        "search-interwiki-default": "$1 থেকে প্রাপ্ত ফলাফলসমূহ:",
index dd7d921..b69719b 100644 (file)
        "api-error-stashfailed": "Unutrašnja greška: server nije mogao da spremi privremenu datoteku.",
        "api-error-unknown-warning": "Nepoznato upozorenje: \"$1\".",
        "api-error-unknownerror": "Nepoznata greška: \"$1\"",
-       "duration-seconds": "$1 {{PLURAL:$1|sekunda|sekunde}}",
+       "duration-seconds": "$1 {{PLURAL:$1|sekunda|sekunde|sekundi}}",
        "duration-minutes": "$1 {{PLURAL:$1|minut|minute|minuta}}",
        "duration-hours": "$1 {{PLURAL:$1|sat|sata|sati}}",
        "duration-days": "$1 {{PLURAL:$1|dan|dana}}",
index d864bb9..4de20a8 100644 (file)
        "botpasswords-label-delete": "Slet",
        "botpasswords-label-resetpassword": "Nulstil adgangskode",
        "botpasswords-label-grants": "Tilgængelige bevillinger:",
+       "botpasswords-updated-title": "Bot kodeord opdateret",
+       "botpasswords-deleted-title": "Bot kodeord slettet",
        "resetpass_forbidden": "Adgangskoder kan ikke ændres",
+       "resetpass_forbidden-reason": "Adgangskoder kan ikke ændres: $1",
        "resetpass-no-info": "Du skal være logget på for at komme direkte til denne side.",
        "resetpass-submit-loggedin": "Skift adgangskode",
        "resetpass-submit-cancel": "Annuller",
        "passwordreset-emailelement": "Brugernavn: \n$1\n\nMidlertidig adgangskode: \n$2",
        "passwordreset-emailsentemail": "Hvis denne e-mailadresse er knyttet til din konto, så vil en e-mail om nulstilling af adgangskoden blive sendt.",
        "passwordreset-emailsentusername": "Hvis der er en e-mailadresse forbundet med dette brugernavn, så vil en e-mail om nulstilling af adgangskoden blive sendt.",
+       "passwordreset-invalidemail": "Ugyldig e-mailadresse",
+       "passwordreset-nodata": "Hverken et brugernavn eller en e-mailadresse blev angivet",
        "changeemail": "Ændr eller fjern e-mailadresse",
        "changeemail-header": "Udfyld denne formular for at ændre din e-mailadresse. Hvis du gerne vil fjerne forbindelsen af en e-mailadresse fra din konto, så lad den nye e-mailadresse være blank, når du sender formularen.",
        "changeemail-no-info": "Du skal være logget på for at komme direkte til denne side.",
        "blockedtitle": "Du eller din IP-adresse er blokeret",
        "blockedtext": "'''Dit brugernavn eller din IP-adresse er blevet blokeret.'''\n\nBlokeringen er foretaget af $1.\nDen anførte grund er ''$2''.\n\nBlokeringen starter: $8\nBlokeringen udløber: $6\nBlokeringen er rettet mod: $7\n\nDu kan kontakte $1 eller en af de andre [[{{MediaWiki:Grouppage-sysop}}|administratorer]] for at diskutere blokeringen.\nDu kan ikke bruge funktionen 'e-mail til denne bruger' medmindre der er angivet en gyldig e-mailadresse i dine\n[[Special:Preferences|kontoindstillinger]], og du ikke er blevet blokeret fra at bruge den.\n\nDin nuværende IP-adresse er $3, og blokerings-id er #$5.\nAngiv venligst alle ovenstående detaljer ved henvendelser om blokeringen.",
        "autoblockedtext": "Din IP-adresse er blevet blokeret automatisk fordi den blev brugt af en anden bruger som er blevet blokeret af $1.\nBegrundelsen for det er:\n\n:''$2''\n\n* Blokeringsperiodens start: $8\n* Blokeringen udløber: $6\n* Blokeringen er ment for: $7\n\nDu kan kontakte $1 eller en af de andre [[{{MediaWiki:Grouppage-sysop}}|administratorer]] for at diskutere blokeringen.\n\nBemærk at du ikke kan bruge funktionen \"e-mail til denne bruger\" medmindre du har en gyldig e-mailadresse registreret i din [[Special:Preferences|brugerindstilling]], og du ikke er blevet blokeret fra at bruge den.\n\nDin nuværende IP-adresse er $3, og blokerings-id'et er #$5.\nAngiv venligst alle de ovenstående detaljer ved eventuelle henvendelser.",
+       "systemblockedtext": "Dit brugernavn eller din IP-adresse er automatisk blokeret af MediaWiki.\nBegrundelsen for det er:\n\n:<em>$2</em>\n\n* Blokeringsperiodens start: $8\n* Blokeringen udløber: $6\n* Blokeringen er ment for: $7\n\nDin nuværende IP-adresse er $3.\nAngiv venligst alle de ovenstående detaljer ved eventuelle henvendelser.\")",
        "blockednoreason": "ingen begrundelse givet",
        "whitelistedittext": "Du skal $1 for at kunne redigere sider.",
        "confirmedittext": "Du skal først bekræfte din e-mailadresse, før du kan redigere sider. Udfyld og bekræft din e-mailadresse i dine [[Special:Preferences|indstillinger]].",
        "userrights-unchangeable-col": "Uredigerbare grupper",
        "userrights-expiry-current": "Udløber $1",
        "userrights-expiry-none": "Udløber ikke",
+       "userrights-expiry": "Udløber:",
+       "userrights-expiry-existing": "Nugældende udløbstid: $2 $3",
+       "userrights-expiry-othertime": "Anden tid:",
        "userrights-expiry-options": "1 dag:1 day,1 uge:1 week,1 måned:1 month,3 måneder:3 months,6 måneder:6 months,1 år:1 year",
+       "userrights-invalid-expiry": "Udløbstiden for gruppen \"$1\" er ugyldig.",
+       "userrights-expiry-in-past": "Udløbstiden for gruppen \"$1\" er i fortiden.",
        "userrights-conflict": "Konflikt i ændringer af brugerrettigheder!\nVær venlig at gennemse og bekræft dine ændringer.",
        "group": "Gruppe:",
        "group-user": "Brugere",
        "action-writeapi": "bruge skrive-API'et",
        "action-delete": "slette denne side",
        "action-deleterevision": "slette siderevisioner",
+       "action-deletelogentry": "slet logposter",
        "action-deletedhistory": "se en sides slettede historik",
+       "action-deletedtext": "se slettet revisionstekst",
        "action-browsearchive": "søge i slettede sider",
        "action-undelete": "gendanne sider",
        "action-suppressrevision": "se og gendanne skjulte siderevisioner",
        "recentchanges-legend-plusminus": "(''±123'')",
        "recentchanges-submit": "Vis",
        "rcfilters-activefilters": "Aktive filtre",
+       "rcfilters-restore-default-filters": "Gendan standardfiltre",
+       "rcfilters-clear-all-filters": "Ryd alle filtre",
        "rcfilters-invalid-filter": "Ugyldigt filter",
        "rcfilters-filterlist-title": "Filtre",
+       "rcfilters-filterlist-whatsthis": "Hvad er dette?",
+       "rcfilters-highlightmenu-title": "Vælg en farve",
+       "rcfilters-highlightmenu-help": "Vælg en farve for at fremhæve denne egenskab",
+       "rcfilters-filterlist-noresults": "Ingen filtre fundet",
+       "rcfilters-filtergroup-registration": "Brugerregistrering",
+       "rcfilters-filter-registered-label": "Registreret",
+       "rcfilters-filter-unregistered-label": "Uregistreret",
+       "rcfilters-filter-unregistered-description": "Redaktører, der ikke er logget ind.",
+       "rcfilters-filter-editsbyself-label": "Ændringer af dig",
+       "rcfilters-filter-editsbyself-description": "Dine egne bidrag.",
+       "rcfilters-filter-editsbyother-label": "Ændringer af andre",
+       "rcfilters-filter-editsbyother-description": "Alle ændringer undtagen din egen.",
+       "rcfilters-filtergroup-userExpLevel": "Erfaringsniveau (kun for registrerede brugere)",
        "rcfilters-filter-user-experience-level-experienced-label": "Erfarne brugere",
        "rcnotefrom": "Nedenfor er op til '''$1''' {{PLURAL:$5|ændring|ændringer}} siden '''$2''' vist.",
        "rclistfrom": "Vis nye ændringer startende fra den $3 kl. $2",
index 0017d66..296406a 100644 (file)
        "internalerror_info": "Error interno: $1",
        "internalerror-fatal-exception": "Excepción grave de tipo \"$1\"",
        "filecopyerror": "No se ha podido copiar el archivo «$1» a «$2».",
-       "filerenameerror": "No se ha podido renombrar el archivo «$1» a «$2».",
+       "filerenameerror": "No se pudo cambiar el nombre del archivo «$1» a «$2».",
        "filedeleteerror": "No se ha podido borrar el archivo «$1».",
        "directorycreateerror": "No se ha podido crear el directorio «$1».",
        "directoryreadonlyerror": "El directorio «$1» es de solo lectura.",
index 3c4892b..d98d15e 100644 (file)
        "userrights-nodatabase": "$1 datubasea ez da existitzen edo ez dago lokalki.",
        "userrights-changeable-col": "Alda ditzakezun taldeak",
        "userrights-unchangeable-col": "Aldatu ezin ditzakezun taldeak",
+       "userrights-expiry-none": "Ez da iraungitzen",
        "userrights-expiry-options": "Egun 1:Egun 1,Aste 1:Aste 1,Hilabete 1:Hilabete 1,3 hilabete:3 hilabete,6 hilabete:6 hilabete,Urte 1:Urte 1",
        "userrights-conflict": "Gatazka gertatu da erabiltzaile eskubideak aldatzean. Mesedez, berrikusi eta baieztatu zure aldaketak.",
        "group": "Taldea:",
        "rcfilters-filtergroup-significance": "Munta",
        "rcfilters-filter-minor-label": "Aldaketa txikiak",
        "rcfilters-filter-major-label": "Aldaketa ez Txikiak",
+       "rcfilters-filter-watchlist-watched-label": "Jarraipen-zerrendan",
        "rcfilters-filtergroup-changetype": "Aldaketa mota",
        "rcfilters-filter-pageedits-label": "Orrialde aldaketak",
        "rcfilters-filter-newpages-label": "Orrialde berriak",
index 970d656..563646d 100644 (file)
        "preview": "Esikatselu",
        "showpreview": "Esikatsele",
        "showdiff": "Näytä muutokset",
-       "blankarticle": "<strong>Varoitus:</strong> Sivu, jota olet luomassa, on tyhjä.\nJos napsautat \"$1\" uudelleen, sivu luodaan ilman sisältöä.",
+       "blankarticle": "<strong>Varoitus:</strong> Sivu, jota olet luomassa on tyhjä.\nJos napsautat \"$1\" uudelleen, sivu luodaan ilman sisältöä.",
        "anoneditwarning": "<strong>Varoitus:</strong> Et ole kirjautunut sisään. IP-osoitteesi näkyy julkisesti kaikille, jos muokkaat. Jos <strong>[$1 kirjaudut sisään]</strong> tai <strong>[$2 luot tunnuksen]</strong>, muokkauksesi kirjataan käyttäjätunnuksesi tekemiksi ja samalla saat käyttöösi hyödyllisiä välineitä.",
        "anonpreviewwarning": "''Et ole kirjautunut sisään. Tallentaminen kirjaa IP-osoitteesi tämän sivun muutoshistoriaan.''",
        "missingsummary": "Et ole antanut yhteenvetoa. Jos valitset Tallenna uudelleen, niin muokkauksesi tallennetaan ilman yhteenvetoa.",
        "rcfilters-filterlist-noresults": "Ei löytynyt suodattimia",
        "rcfilters-noresults-conflict": "Tuloksia ei löytynyt, koska hakuehdot ovat ristiriidassa",
        "rcfilters-state-message-subset": "Tällä suodattimella ei ole vaikutusta, koska sen tulokset sisältyvät seuraaviin laajempiin suodattimiin (kokeile korostusta sen erottamiseksi): $1",
-       "rcfilters-state-message-fullcoverage": "Ryhmän kaikkien suodattimien valitseminen on sama, kuin ei valitse mitään. Ryhmään sisältyy: $ 1",
+       "rcfilters-state-message-fullcoverage": "Ryhmän kaikkien suodattimien valitseminen on sama, kuin ei valitse mitään, joten tällä suodattimella ei ole vaikutusta. Ryhmään sisältyy: $ 1",
        "rcfilters-filtergroup-registration": "Käyttäjän rekisteröinti",
        "rcfilters-filter-registered-label": "Rekisteröitynyt",
        "rcfilters-filter-registered-description": "Sisäänkirjautuneiden muokkaukset.",
        "rcfilters-filter-unregistered-label": "Rekisteröimätön",
        "rcfilters-filter-unregistered-description": "Muokkaajat, jotka eivät ole kirjautuneet sisään.",
-       "rcfilters-filter-unregistered-conflicts-user-experience-level": "Tämä suodatin on ristiriidassa seuraavien kokemustaso suodattimien kanssa, jotka löytävät vain rekisteröityneitä käyttäjiä: $1",
-       "rcfilters-filtergroup-authorship": "Muokkausten tekijä",
-       "rcfilters-filter-editsbyself-label": "Omat muokkauksesi",
-       "rcfilters-filter-editsbyself-description": "Itse tekemäsi muokkaukset.",
-       "rcfilters-filter-editsbyother-label": "Muiden muokkaukset",
-       "rcfilters-filter-editsbyother-description": "Muiden käyttäjien tekemät muokkaukset.",
+       "rcfilters-filter-unregistered-conflicts-user-experience-level": "Tämä suodatin on ristiriidassa seuraavien kokemustaso {{PLURAL:$2|suodattimen|suodattimien}} kanssa,  {{PLURAL:$2|joka|jotka}} löytävät vain rekisteröityneitä käyttäjiä: $1",
+       "rcfilters-filtergroup-authorship": "Muutoksen tekijä",
+       "rcfilters-filter-editsbyself-label": "Muutoksesi",
+       "rcfilters-filter-editsbyself-description": "Tekemäsi muutokset.",
+       "rcfilters-filter-editsbyother-label": "Muiden muutokset",
+       "rcfilters-filter-editsbyother-description": "Muiden käyttäjien tekemät muutokset.",
        "rcfilters-filtergroup-userExpLevel": "Kokemustaso (vain rekisteröityneet käyttäjät)",
        "rcfilters-filtergroup-user-experience-level-conflicts-unregistered": "Kokemustaso suodattimet löytävät vain rekisteröityneitä käyttäjiä, joten tämä suodatin on ristiriidassa \"Rekisteröimätön\" -suodattimen kanssa.",
        "rcfilters-filtergroup-user-experience-level-conflicts-unregistered-global": "\"Rekisteröimätön\" -suodatin on ristiriidassa yhden tai useamman kokemustaso suodattimen kanssa, joka löytää vain rekisteröityneitä käyttäjiä.  Ristiriidassa oleva suodatin on merkittynä Aktiivisissa suodattimissa, yläpuolella.",
        "rcfilters-filter-minor-description": "Muokkaukset, jotka on merkitty pieniksi.",
        "rcfilters-filter-major-label": "Ei-pienet muutokset",
        "rcfilters-filter-major-description": "Muokkaukset joita ei ole merkitty pieniksi.",
+       "rcfilters-filtergroup-watchlist": "Tarkkailulistalla olevat sivut",
+       "rcfilters-filter-watchlist-watched-label": "Tarkkailulistalla",
+       "rcfilters-filter-watchlist-watched-description": "Muutokset tarkkailulistalla oleviin sivuihin.",
+       "rcfilters-filter-watchlist-notwatched-label": "Ei tarkkailulistalla",
        "rcfilters-filtergroup-changetype": "Muutoksen tyyppi",
        "rcfilters-filter-pageedits-label": "Sivun muokkaukset",
        "rcfilters-filter-pageedits-description": "Muokkaukset wikin sisältöön, keskusteluihin, luokkakuvauksiin....",
        "rcfilters-hideminor-conflicts-typeofchange-global": "\"Pienet muutokset\" -suodatin on ristiriidassa yhden tai useamman Muutoksen tyyppi suodattimen kanssa, koska joitain muutostyyppejä ei voida pitää \"pieninä\". Ristiriidassa oleva suodatin on merkittynä Aktiivisissa suodattimissa, yläpuolella.",
        "rcfilters-hideminor-conflicts-typeofchange": "Joitain muutostyyppejä ei voida määrittää \"pieneksi\", joten tämä suodatin on ristiriidassa seuraavien Muutoksen tyyppi suodattimien kanssa: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "\"Muutoksen tyyppi\" on ristiriidassa \"Pienet muutokset\" -suodattimen kanssa. Joitain muutostyyppejä ei voida merkitä \"pieniksi\".",
+       "rcfilters-filtergroup-lastRevision": "Viimeisin versio",
+       "rcfilters-filter-lastrevision-label": "Viimeisin versio",
+       "rcfilters-filter-previousrevision-label": "Aikaisemman versiot",
        "rcnotefrom": "Alla ovat muutokset <strong>$3, $4</strong> lähtien. (Enintään <strong>$1</strong> näytetään.)",
        "rclistfrom": "Näytä uudet muutokset $3 kello $2 alkaen",
        "rcshowhideminor": "$1 pienet muutokset",
        "rcshowhidecategorization": "$1 sivujen luokkien muutokset",
        "rcshowhidecategorization-show": "Näytä",
        "rcshowhidecategorization-hide": "Piilota",
-       "rclinks": "Näytä $1 tuoretta muutosta viimeisten $2 päivän ajalta.",
+       "rclinks": "Näytä $1 muutosta viimeisten $2 päivän ajalta.",
        "diff": "ero",
        "hist": "historia",
        "hide": "Piilota",
        "enotif_body_intro_moved": "{{GENDER:$2|$2}} siirsi {{GRAMMAR:inessive|{{SITENAME}}}} sivun $1 $PAGEEDITDATE. Sivun nykyinen versio on osoitteessa $3.",
        "enotif_body_intro_restored": "{{GENDER:$2|$2}} palautti {{GRAMMAR:inessive|{{SITENAME}}}} sivun $1 $PAGEEDITDATE. Sivun nykyinen versio on osoitteessa $3.",
        "enotif_body_intro_changed": "{{GENDER:$2|$2}} muutti {{GRAMMAR:inessive|{{SITENAME}}}} sivua $1 $PAGEEDITDATE. Sivun nykyinen versio on osoitteessa $3.",
-       "enotif_lastvisited": "Osoitteessa $1 on kaikki muutokset viimeisen käyntisi jälkeen.",
+       "enotif_lastvisited": "Kaikki muutokset viimeisimmän vierailusi jälkeen näet täältä $1",
        "enotif_lastdiff": "Muutos on osoitteessa $1.",
        "enotif_anon_editor": "kirjautumaton käyttäjä $1",
        "enotif_body": "$WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nMuokkaajan yhteenveto: $PAGESUMMARY $PAGEMINOREDIT\n\nOta yhteyttä muokkaajaan:\nsähköposti: $PAGEEDITOR_EMAIL\nwiki: $PAGEEDITOR_WIKI\n\nUusia ilmoituksia tästä sivusta ei tule kunnes vierailet sivulla sisään kirjautuneena. Voit myös nollata ilmoitukset kaikille tarkkailemillesi sivuille tarkkailulistallasi.\n\n             {{GRAMMAR:genitive|{{SITENAME}}}} ilmoitusjärjestelmä\n\n--\nVoit muuttaa sähköpostimuistutusten asetuksia osoitteessa:\n{{canonicalurl:{{#special:Preferences}}}}\n\nVoit muuttaa tarkkailulistasi asetuksia osoitteessa:\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nVoit poistaa sivun tarkkailulistalta osoitteessa:\n$UNWATCHURL\n\nPalaute ja lisäapu osoitteessa:\n$HELPPAGE",
        "confirmrecreate-noreason": "Käyttäjä [[User:$1|$1]] ([[User talk:$1|keskustelu]]) {{GENDER:$1|on poistanut}} tämän sivun sen jälkeen, kun aloit muokata. Varmista, että haluat tosiaan luoda sivun uudelleen.",
        "recreate": "Luo uudelleen",
        "unit-pixel": " px",
+       "confirm-purge-title": "Tyhjennä välimuistista",
        "confirm_purge_button": "Poista",
        "confirm-purge-top": "Poistetaanko tämän sivun välimuistikopiot?",
        "confirm-purge-bottom": "Välimuistikopioiden poistaminen tyhjentää välimuistin ja pakottaa sivun uusimman version näkyviin.",
index b9e2c4c..7814998 100644 (file)
        "rcfilters-filter-unregistered-label": "Neprijavljeni",
        "rcfilters-filter-unregistered-description": "Suradnici koji nisu prijavljeni.",
        "rcfilters-filtergroup-authorship": "Doprinosi prema autorima",
+       "rcfilters-filter-editsbyself-label": "Uređivanja koja ste Vi napravili",
        "rcfilters-filter-editsbyself-description": "Vaša uređivanja.",
        "rcfilters-filter-editsbyother-label": "Promjene drugih suradnika",
        "rcfilters-filter-editsbyother-description": "Sve promjene osim Vaših.",
        "rcfilters-filter-newpages-label": "Stvaranje stranica",
        "rcfilters-filter-newpages-description": "Uređivanja kojima su stvorene nove stranice.",
        "rcfilters-filter-categorization-label": "Promjene kategorija",
+       "rcfilters-filter-categorization-description": "Uređivanja kojima se dodaju ili uklanjanju stranice iz kategorija.",
        "rcfilters-filter-logactions-label": "Radnje zabilježene u zapisnike",
        "rcfilters-filter-logactions-description": "Administrativne radnje, stvaranja računa, brisanje stranica, postavljanja datoteka...",
        "rcnotefrom": "Slijede promjene od <b>$2</b> (prikazano ih je do <b>$1</b>).",
index 4ef4b9d..91c076a 100644 (file)
        "rcfilters-filter-major-description": "細部とマークされていない編集。",
        "rcfilters-filtergroup-changetype": "変更の種類",
        "rcfilters-filter-pageedits-label": "ページの編集",
-       "rcfilters-filter-pageedits-description": "Wikiの項目編集、議論、カテゴリ変更など",
+       "rcfilters-filter-pageedits-description": "ウィキの本文、議論、カテゴリの説明などの編集",
        "rcfilters-filter-newpages-label": "ページの作成",
        "rcfilters-filter-newpages-description": "ページを新規作成する編集。",
        "rcfilters-filter-categorization-label": "カテゴリ変更",
        "rcfilters-filter-categorization-description": "ページがカテゴリから追加または削除された記録",
-       "rcfilters-filter-logactions-label": "操作ログ",
+       "rcfilters-filter-logactions-label": "操作記録",
        "rcfilters-filter-logactions-description": "アカウント作成、削除、アップロードなどのログに残る管理操作",
        "rcfilters-hideminor-conflicts-typeofchange-global": "「細部の編集」として絞り込めない項目を「細部の編集」として絞り込もうとしています。競合している項目は項目選択欄で強調表示されています。",
        "rcfilters-hideminor-conflicts-typeofchange": "細部の編集として絞り込めない以下の項目を絞り込もうとしています: $1",
index 5ae1445..65ed3b1 100644 (file)
        "redirectedfrom": "(გადმომისამართდა $1-დან)",
        "redirectpagesub": "გადამისამართება გვერდზე",
        "redirectto": "გადამისამართება:",
-       "lastmodifiedat": "á\83\94á\83¡ á\83\92á\83\95á\83\94á\83 á\83\93á\83\98 á\83\91á\83\9dá\83\9aá\83\9dá\83¡ á\83\92á\83\90á\83\9cá\83\90á\83®á\83\9aá\83\93á\83\90 $2, $1.",
+       "lastmodifiedat": "á\83\94á\83¡ á\83\92á\83\95á\83\94á\83 á\83\93á\83\98 á\83\91á\83\9dá\83\9aá\83\9dá\83¡ á\83\93á\83\90á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\98á\83 á\83\93á\83\90: $2, $1.",
        "viewcount": "ეს გვერდი შემოწმდა {{PLURAL:$1|ერთხელ|$1-ჯერ}}.",
        "protectedpage": "დაბლოკილი გვერდი",
        "jumpto": "გადასვლა:",
        "page_first": "პირველი",
        "page_last": "ბოლო",
        "histlegend": "ვერსიების შედარება: აირჩიეთ სასურველი ვერსიები რადიო-რგოლების მონიშვნით და დააწკაპუნეთ შედარების ღილაკზე.<br />\nლეგენდა: '''({{int:cur}})''' = სხვაობა მიმდინარე ვერსიასთან, '''({{int:last}})''' = სხვაობა წინა ვერსიასთან, '''{{int:minoreditletter}}''' = მცირე შესწორება.",
-       "history-fieldset-title": "á\83\93á\83\90á\83\97á\83\95á\83\90á\83\9aá\83\98á\83\94á\83 á\83\94á\83\91á\83\98á\83¡ á\83\98á\83¡á\83¢á\83\9dá\83 á\83\98ა",
-       "history-show-deleted": "მხოლოდ წაშლილი",
+       "history-fieldset-title": "á\83\95á\83\94á\83 á\83¡á\83\98á\83\94á\83\91á\83\98á\83¡ á\83«á\83\98á\83\94á\83\91ა",
+       "history-show-deleted": "მხოლოდ წაშლილი ვერსიები",
        "histfirst": "უძველესი",
        "histlast": "უახლესი",
        "historysize": "({{PLURAL:$1|$1 ბაიტი|$1 ბაიტი}})",
        "search-interwiki-caption": "დობილი პროექტები",
        "search-interwiki-default": "შედეგები $1-დან:",
        "search-interwiki-more": "(გაგრძელება)",
+       "search-interwiki-more-results": "მეტი შედეგი",
        "search-relatedarticle": "დაკავშირებული",
        "searchrelated": "მიბმული",
        "searchall": "ყველა",
        "prefs-help-recentchangescount": "შეიცავს ახალ შესწორებებს, გვერდების ისტორიებს, ჟურნალებს.",
        "prefs-help-watchlist-token2": "ეს არის საიდუმლო გასაღები თქვენი კონტროლის სიის ვებ-არხისთვის. ნებისმიერს, ვინც იცის ის, შეუძლია წაიკითხოს თქვენი კონტროლის სია, ამიტომ არ გაუზიაროთ იგი სხვებს. [[Special:ResetTokens|თქვენ შეგიძლიათ ჩამოყაროთ ის]].",
        "savedprefs": "თქვენ მიერ შერჩეული პარამეტრები დამახსოვრებულია.",
-       "savedrights": "á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\9aá\83\98á\83¡ {{GENDER:$1|$1}} á\83£á\83¤á\83\9aá\83\94á\83\91ები შენახულია",
+       "savedrights": "á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\9aá\83\98á\83¡ {{GENDER:$1|$1}} á\83¯á\83\92á\83£á\83¤ები შენახულია",
        "timezonelegend": "სასაათო სარტყელი:",
        "localtime": "ადგილობრივი დრო:",
        "timezoneuseserverdefault": "გამოიყენე ნაგულისხმევი პარამეტრები ($1)",
        "username": "{{GENDER:$1|მომხმარებლის სახელი}}:",
        "prefs-memberingroups": "{{PLURAL:$1|ჯგუფის|ჯგუფების}} {{GENDER:$2|წევრი}}:",
        "prefs-memberingroups-type": "$1",
+       "group-membership-link-with-expiry": "$1 ($2-მდე)",
        "prefs-registration": "რეგისტრაციის თარიღი",
        "prefs-registration-date-time": "$1",
        "yourrealname": "ნამდვილი სახელი:",
        "prefs-help-prefershttps": "ამ კონფიგურაციის არჩევა შედეგს გამოიღებს შემდგომი ავტორიზაციის შედმეგ.",
        "prefswarning-warning": "თქვენ შეიტანეთ ცვლილება თქვენ პარამეტრებში, რომელიც ჯერ კიდევ არ არის შენახული. თუ თქვენ დატოვებთ ამ გვერდს და არ დააჭერთ \"$1\"-ს, პარამეტრები არ იქნება განახლებული.",
        "prefs-tabs-navigation-hint": "რჩევა: თქვენ შეგიძლიათ გამოიყენოთ ისრის კლავიშები მარცხნივ ან მარჯვნივ ჩანართებსა და ჩანართბის სიას შორის არსებული გადასვლებისათვის",
-       "userrights": "მომხმარებელთა უფლებების მართვა",
-       "userrights-lookup-user": "á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\97á\83\90 á\83¯á\83\92á\83£á\83¤á\83\94á\83\91á\83\98á\83¡ á\83\9bá\83\90á\83 á\83\97ვა",
+       "userrights": "მომხმარებელთა უფლებები",
+       "userrights-lookup-user": "á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\9aá\83\98á\83¡ á\83\90á\83 á\83©á\83\94ვა",
        "userrights-user-editname": "შეიყვანეთ მომხმარებლის სახელი:",
-       "editusergroup": "{{GENDER:$1|მომხმარებელთა}} ჯგუფების რედაქტირება",
+       "editusergroup": "მომხმარებელთა ჯგუფების ჩატვირთვა",
        "editinguser": "უფლებების შეცვლა {{GENDER:$1|მომხმარებლისთვის}} <strong>[[User:$1|$1]]</strong> $2",
        "viewinguserrights": "{{GENDER:$1|მომხმარებლის}} უფლებების ხილვა <strong>[[User:$1|$1]]</strong> $2",
-       "userrights-editusergroup": "დაარედაქტირეთ მომხმარებელთა ჯგუფები",
+       "userrights-editusergroup": "{{GENDER:$1|მომხმარებელთა}} ჯგუფების რედაქტირება",
        "userrights-viewusergroup": "{{GENDER:$1|მომხმარებლის}} ჯგუფების ხილვა",
        "saveusergroups": "{{GENDER:$1|მომხმარებელთა}} ჯგუფების შენახვა",
        "userrights-groupsmember": "ჯგუფის წევრი:",
        "action-userrights-interwiki": "მომხმარებლების უფლებების შეცვლა სხვა ვიკიებში",
        "action-siteadmin": "მონაცემთა ბაზის დაბლოკვა და განბლოკვა",
        "action-sendemail": "ელ-ფოსტების გაგზავნა",
+       "action-editmyoptions": "თქვენი კონფიგურაციის რედაქტირება",
        "action-editmywatchlist": "თქვენი კონტროლის სიის რედაქტირება",
        "action-viewmywatchlist": "თქვენი კონტროლის სიის ხილვა",
        "action-viewmyprivateinfo": "თქვენი პირადი ინფორმაციის ხილვა",
        "rcfilters-activefilters": "აქტიური ფილტრები",
        "rcfilters-clear-all-filters": "ყველა ფილტრის გაწმენდა",
        "rcfilters-search-placeholder": "ფილტრის ბოლო ცვლილებები (დაათვალიერეთ ან დაიწყეთ შეყვანა)",
+       "rcfilters-invalid-filter": "არასწორი ფილტრი",
        "rcfilters-filterlist-title": "ფილტრები",
+       "rcfilters-filterlist-whatsthis": "ეს რა არის?",
        "rcfilters-filterlist-feedbacklink": "შეტყობინების დატოვება ახალი (ბეტა) ფილტრების შესახებ",
        "rcfilters-highlightbutton-title": "შედეგების მონიშვნა",
        "rcfilters-highlightmenu-title": "ფერის არჩევა",
        "rcfilters-highlightmenu-help": "აირჩიეთ ფერი, რათა მონიშნოთ ეს თვისება",
+       "rcfilters-filterlist-noresults": "ფილტრები ვერ მოძებნა",
        "rcfilters-filtergroup-registration": "მომხმარებლის რეგისტრაცია",
        "rcfilters-filter-registered-label": "რეგისტრირებულები",
        "rcfilters-filter-registered-description": "შესული რედაქტორები.",
        "upload-dialog-disabled": "ფაილის ატვირთვა ამ დიალოგური ფანჯრით გათიშულია ამ ვიკიზე.",
        "upload-dialog-title": "ფაილის ატვირთვა",
        "upload-dialog-button-cancel": "გაუქმება",
+       "upload-dialog-button-back": "უკან",
        "upload-dialog-button-done": "შესრულდა",
        "upload-dialog-button-save": "შენახვა",
        "upload-dialog-button-upload": "ატვირთვა",
        "apisandbox-results-fixtoken-fail": "ვერ მოხერხდა $1 ტოკენის მოძიება.",
        "apisandbox-alert-page": "ველები ამ გვერდზე არ არის ვალიდური",
        "apisandbox-alert-field": "ამ ველის მნიშვნელობა არ არის ვალიდური",
+       "apisandbox-continue": "გაგრძელება",
+       "apisandbox-continue-clear": "გასუფთავება",
+       "apisandbox-multivalue-all-namespaces": "$1 (ყველა სახელთა სივრცე)",
+       "apisandbox-multivalue-all-values": "$1 (ყველა მნიშვნელობა)",
        "booksources": "წიგნის წყაროები",
        "booksources-search-legend": "წიგნის წყაროს ძებნა",
        "booksources-isbn": "ISBN:",
        "enotif_body_intro_restored": "$PAGEEDITDATE {{gender:$2|მომხმარებელმა}} $2 აღადგინა გვერდი პროექტიდან „{{SITENAME}}“ სახელწოდებით „$1“, მიმდინარე ვერსია იხილიეთ ბმულზე: $3",
        "enotif_body_intro_changed": "$PAGEEDITDATE {{gender:$2|მომხმარებელმა}} $2 შეცვალა გვერდი პროექტიდან „{{SITENAME}}“ სახელწოდებით „$1“, მიმდინარე ვერსია იხილიეთ ბმულზე: $3",
        "enotif_lastvisited": "იხ. $1 ყველა ცვლილებისთვის თქვენი ბოლო შემოსვლის შემდეგ.",
-       "enotif_lastdiff": "á\83\98á\83®á\83\98á\83\9aá\83\94á\83\97 $1 á\83\90á\83\9b á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\98á\83¡ á\83¡á\83\90á\83\9cá\83\90á\83®á\83\90á\83\95á\83\90á\83\93.",
+       "enotif_lastdiff": "á\83\90á\83\9b á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\98á\83¡ á\83¡á\83\90á\83\9cá\83\90á\83®á\83\90á\83\95á\83\90á\83\93, á\83\98á\83®á\83\98á\83\9aá\83\94á\83\97 $1.",
        "enotif_anon_editor": "ანონიმური მომხმარებელი $1",
        "enotif_body": "ძვირფასო $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nცვლილების მოკლე აღწერა: $PAGESUMMARY $PAGEMINOREDIT\n\nდაუკავშირდით რედაქტორს:\nელ.ფოსტა: $PAGEEDITOR_EMAIL\nვიკი: $PAGEEDITOR_WIKI\n\nშემდგომი ცვლილებების შესახებ შეტყობინებების მისაღებად ამ გვერდს კვლავ უნდა ესტუმროთ. თქვენ აგრეთვე შეგიძლიათ თქვენ კონტროლის სიაში გათიშოთ შეტყობინების ფუნქცია ყველა გვერდისათვის.\n\n\t\t\t {{SITENAME}} შეტყობინებათა სისტემა\n\n--\nშეტყობინების პარამეტრების ცვლილება\n{{canonicalurl:{{#special:Preferences}}}}\n\nთქვენი კონტროლის სიის პარამეტრების ცვლილება\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nგვერდების ამოშლა თქვენი კონტროლის სიიდან\n$UNWATCHURL\n\nდამატებითი ინფორმაცია\n$HELPPAGE",
        "created": "შექმნილია",
        "modifiedarticleprotection": "შეცვლილია დაცვის დონე გვერდისთვის „[[$1]]“",
        "unprotectedarticle": "„[[$1]]“-დან დაცვა მოხსნილია",
        "movedarticleprotection": "დაცვის პარამეტრების გადატანა გვერდიდან „[[$2]]“ გვერდზე „[[$1]]“",
+       "protectedarticle-comment": "მომხმარებელმა {{GENDER:$2|დაიცვა}} „[[$1]]“",
+       "modifiedarticleprotection-comment": "მომხმარებელმა {{GENDER:$2|შეცვალა დაცვის დონე}} „[[$1]]“-ზე",
+       "unprotectedarticle-comment": "მომხარებელმა {{GENDER:$2|მოხსნა დაცვა}} „[[$1]]“-დან",
        "protect-title": "დაცვის დონის შეცვლა გვერდისთვის „$1“",
        "protect-title-notallowed": "დაცვის დონის ხილვა გვერდისთვის „$1“",
        "prot_1movedto2": "[[$1]] გადატანილია გვერდზე [[$2]]",
        "sp-contributions-uploads": "ატვირთვები",
        "sp-contributions-logs": "ჟურნალები",
        "sp-contributions-talk": "განხილვა",
-       "sp-contributions-userrights": "á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\97á\83\90 á\83£á\83¤á\83\9aá\83\94á\83\91á\83\94á\83\91á\83\98á\83¡ მართვა",
+       "sp-contributions-userrights": "á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\9aá\83\98á\83¡ {{GENDER:$1|á\83£á\83¤á\83\9aá\83\94á\83\91á\83\94á\83\91á\83\98á\83¡}} მართვა",
        "sp-contributions-blocked-notice": "ეს მომხმარებელი ამჟამად დაბლოკილია. ქვემოთ მოყვანილია ამონაწერი წაშლათა ჟურნალიდან:",
        "sp-contributions-blocked-notice-anon": "ეს მომხმარებელი ამჟამად დაბლოკილია.\nქვემოთ მოყვანილია ამონაწერი წაშლათა ჟურნალიდან:",
        "sp-contributions-search": "წვლილის ძიება",
        "unblocked-id": "ბლოკი $1 მოიხსნა",
        "unblocked-ip": "[[Special:Contributions/$1|$1]] განიბლოკა.",
        "blocklist": "დაბლოკილი მომხმარებლები",
+       "autoblocklist": "ავტობლოკირება",
+       "autoblocklist-submit": "ძიება",
+       "autoblocklist-legend": "ავტობლოკირებების სია",
+       "autoblocklist-localblocks": "ადგილობრივი {{PLURAL:$1|ავტობლოკი|ავტობლოკირებები}}",
+       "autoblocklist-empty": "ავტობლოკირებების სია ცარიელია.",
+       "autoblocklist-otherblocks": "სხვა {{PLURAL:$1|ავტობლოკი|ავტობლოკირებები}}",
        "ipblocklist": "დაბლოკილი მომხმარებლები",
        "ipblocklist-legend": "დაბლოკილი მომხმარებლის პოვნა",
        "blocklist-userblocks": "დამალე ანგარიშის ბლოკირებები",
        "anonymous": "{{SITENAME}}-ის ანონიმური {{PLURAL:$1|მომხმარებელი|მომხმარებლები}}",
        "siteuser": "{{SITENAME}} მომხმარებელი $1",
        "anonuser": "{{SITENAME}} ანონიმური მომხმარებელი $1",
-       "lastmodifiedatby": "á\83\94á\83¡ á\83\92á\83\95á\83\94á\83 á\83\93á\83\98 á\83\91á\83\9dá\83\9aá\83\9dá\83¡ á\83¨á\83\94á\83\98á\83ªá\83\95á\83\90á\83\9aá\83\90 $2, $1  $3-á\83\98á\83\97.",
+       "lastmodifiedatby": "á\83\94á\83¡ á\83\92á\83\95á\83\94á\83 á\83\93á\83\98 á\83\91á\83\9dá\83\9aá\83\9dá\83¡ á\83\93á\83\90á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\98á\83 á\83\93á\83\90: $2, $1  á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\94á\83\91á\83\98á\83¡ á\83\90á\83\95á\83¢á\83\9dá\83 á\83\98 â\80\94 $3.",
        "othercontribs": "$1-ს ნამუშევრის მიხედვით.",
        "others": "სხვები",
        "siteusers": "{{SITENAME}}-ის {{PLURAL:$2|{{GENDER:$1|მომხმარებელი}}|მომხმარებლები}} $1",
        "pageinfo-length": "გვერდის სიგრძე (ბაიტებში)",
        "pageinfo-article-id": "გვერდის ID",
        "pageinfo-language": "გვერდის შინაარსის ენა",
+       "pageinfo-language-change": "შეცვლა",
        "pageinfo-content-model": "გვერდის შინაარსის მოდელი",
+       "pageinfo-content-model-change": "შეცვლა",
        "pageinfo-robot-policy": "ინდექსაცია საძიებო რობოტებით",
        "pageinfo-robot-index": "დაშვებულია",
        "pageinfo-robot-noindex": "არ არის დაშვებული",
        "pageinfo-category-pages": "გვერდების რაოდენობა",
        "pageinfo-category-subcats": "ქვეკატეგორიების რაოდენობა",
        "pageinfo-category-files": "ფაილების რაოდენობა",
+       "pageinfo-user-id": "მომხმარებლის იდენტიფიკატორი",
        "markaspatrolleddiff": "მონიშნე როგორც პატრულირებული",
        "markaspatrolledtext": "მონიშნე ეს სტატია როგორც პატრულირებული",
        "markaspatrolledtext-file": "მონიშნეთ ამ ფაილის ვერსია, როგორც პატრულირებული",
        "patrol-log-header": "ეს არის პატრულირებულ ვერსიათა ჟურნალი.",
        "log-show-hide-patrol": "$1 პატრულირების ჟურნალი",
        "log-show-hide-tag": "$1 დასათაურების ჟურნალი",
+       "confirm-markpatrolled-button": "კარგი",
        "deletedrevision": "წაშლილია ძველი ვერსია $1.",
        "filedeleteerror-short": "შეცდომა ფაილის $1 წაშლისას",
        "filedeleteerror-long": "ფაილის წაშლისას წარმოიშვა შეცდომები:\n\n$1",
        "newimages-summary": "ეს სპეცგვერდი აჩვენებს ბოლო დროს ატვირთულ ფაილებს.",
        "newimages-legend": "ფილტრი",
        "newimages-label": "ფაილის (ან მისი სახელის) ნაწილი",
+       "newimages-user": "IP მისამართი ან მომხმარებლის სახელი",
        "newimages-showbots": "ბოტის ატვირთვების ჩვენება",
        "newimages-hidepatrolled": "დამალე შემოწმებული ატვირთვები",
        "noimages": "გადასახედი არაფერია.",
        "htmlform-cloner-create": "მეტის დამატება",
        "htmlform-cloner-delete": "წაშლა",
        "htmlform-cloner-required": "აუცილებელია სულ მცირე ერთი მნიშვნელობა.",
+       "htmlform-date-placeholder": "წწწწ-თთ-დდ",
+       "htmlform-time-placeholder": "სთ:წთ:წმ",
+       "htmlform-datetime-placeholder": "წწწწ-თთ-დდ სთ:წთ:წმ",
        "htmlform-title-badnamespace": "[[:$1]] არ მდებარეობს \"{{ns:$2}}\"-ის სახელთა სივრცეში.",
        "htmlform-title-not-creatable": "$1\" არ არის მართებული გვერდის სათაური",
        "htmlform-title-not-exists": "$1 არ არსებობს.",
        "htmlform-user-not-valid": "<strong>$1</strong> არ არის სწორი მომხმარებლის სახელი.",
        "logentry-delete-delete": "მომხმარებელმა $1 {{GENDER:$2|წაშალა}} გვერდი: „$3“",
        "logentry-delete-delete_redir": "მომხმარებელმა $1 {{GENDER:$2|წაშალა}} გადამისამართება $3 გადაწერით",
-       "logentry-delete-restore": "მომხმარებელმა $1 {{GENDER:$2|აღადგინა}} გვერდი $3",
+       "logentry-delete-restore": "მომხმარებელმა $1 {{GENDER:$2|აღადგინა}} გვერდი $3 ($4)",
+       "logentry-delete-restore-nocount": "მომხმარებელმა $1 {{GENDER:$2|აღადგინა}} გვერდი $3",
+       "restore-count-revisions": "{{PLURAL:$1|1 ვერსია|$1 ვერსია}}",
+       "restore-count-files": "{{PLURAL:$1|1 ფაილი|$1 ფაილი}}",
        "logentry-delete-event": "მომხმარებელმა $1 {{GENDER:$2|შეცვალა}} {{PLURAL:$5|ჟურნალის ჩანაწერის|$5 ჟურნალის ჩანაწერების}} ხილვადობა $3-ზე: $4",
        "logentry-delete-revision": "მომხმარებელმა $1 {{GENDER:$2|შეცვალა}} {{PLURAL:$5|$5 ვერსიის|$5 ვერსიის}} ხილვადობა გვერდისათვის $3: $4",
        "logentry-delete-event-legacy": "მომხმარებელმა $1 {{GENDER:$2|შეცვალა}} ჩანაწერების ჟურნალის ხილვადობა $3-ზე",
        "pagelang-language": "ენა",
        "pagelang-use-default": "საწყისი ენის გამოყენება",
        "pagelang-select-lang": "აირჩიეთ ენა",
+       "pagelang-reason": "მიზეზი",
        "pagelang-submit": "გაგზავნა",
+       "pagelang-nonexistent-page": "გვერდი $1 არ არსებობს.",
        "right-pagelang": "გვერდის ენის შეცვლა",
        "action-pagelang": "გვერდის ენის შეცვლა",
        "log-name-pagelang": "ენის ცვლილებების ჟურნალი",
        "special-characters-group-thai": "ტაილანდური",
        "special-characters-group-lao": "ლაოსური",
        "special-characters-group-khmer": "ქჰმერული",
+       "special-characters-group-canadianaboriginal": "კანადური აბორიგენული",
        "special-characters-title-endash": "ტირე",
        "special-characters-title-emdash": "გრძელი ტირე",
        "special-characters-title-minus": "მინუსის ნიშანი",
        "mw-widgets-dateinput-no-date": "თარიღი არ არის არჩეული",
        "mw-widgets-dateinput-placeholder-day": "წწწწ-თთ-დდ",
        "mw-widgets-dateinput-placeholder-month": "წწწწ-თთ",
+       "mw-widgets-mediasearch-input-placeholder": "მულტიმედიის ძიება",
        "mw-widgets-mediasearch-noresults": "შედეგები ვერ მოიძებნა.",
        "mw-widgets-titleinput-description-new-page": "გვერდი ჯერ არ არსებობს",
        "mw-widgets-titleinput-description-redirect": "გადამისამართება $1-ზე",
+       "mw-widgets-categoryselector-add-category-placeholder": "კატეგორიის დამატება...",
+       "mw-widgets-usersmultiselect-placeholder": "კიდევ დამატება...",
        "sessionmanager-tie": "შეუძლებელია მრავალი მოთხოვნის ავთენთიფიკაციის ტიპების გაერთიანება: $1.",
        "sessionprovider-generic": "$1 სესიები",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "cookie-სთან დაკავშირებული სესიები",
index def8db2..be09de7 100644 (file)
@@ -30,7 +30,8 @@
                        "రహ్మానుద్దీన్",
                        "ಶಿವಕುಮಾರ್ ನಾಯಕ್",
                        "Yogesh",
-                       "Lokesha kunchadka"
+                       "Lokesha kunchadka",
+                       "Anoop rao"
                ]
        },
        "tog-underline": "ಕೊಂಡಿಗಳ ಕೆಳಗೆ ಗೆರೆ ತೋರಿಸಿ",
        "redirectedfrom": "($1 ಇಂದ ಪುನರ್ನಿರ್ದೇಶಿತ)",
        "redirectpagesub": "ಪುನರ್ನಿರ್ದೇಶನ ಪುಟ",
        "redirectto": "ಪುನರ್ನಿರ್ದೇಶನ ಇದಕ್ಕೆ:",
-       "lastmodifiedat": "ಈ ಪುಟವನ್ನು ಕೊನೆಯಾಗಿ $2, $1 ರಂದು ಬದಲಾಯಿಸಲಾಗಿತ್ತು.",
+       "lastmodifiedat": "ಈ ಪುಟವನ್ನು $ 2 ರಂದು ಕೊನೆಯಾಗಿ $ 2 ರಲ್ಲಿ ಸಂಪಾದಿಸಲಾಯಿತು.",
        "viewcount": "ಈ ಪುಟವನ್ನು {{PLURAL:$1|೧ ಬಾರಿ|$1 ಬಾರಿ}} ವೀಕ್ಷಿಸಲಾಗಿದೆ.",
        "protectedpage": "ಸಂರಕ್ಷಿತ ಪುಟ",
        "jumpto": "ಇಲ್ಲಿಗೆ ಹೋಗು:",
        "right-upload": "ಕಡತಗಳನ್ನು ಅಪ್ಲೋಡ್ ಮಾಡು",
        "right-reupload": "ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಫೈಲ್ ಗಳ ಕಡತಗಳ ಮೇಲೆ ಬರೆಯಿರಿ",
        "right-reupload-own": "ವತಃ ತಾವೇ ನಕಲೆರಿಸಿರುವ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಫೈಲ್ ಗಳ ಕಡತಗಳ ಮೇಲೆ ಬರೆಯಿರಿ",
-       "right-writeapi": "ಬರà³\8aವà³\81â\80\8dà²\9fà³\8d à²\87à²\82ದà³\86ನà³\8d à²¬à²²à²\95à³\86 à²®à²¾à²²à³\8dಪà³\81ಲà³\86 API",
+       "right-writeapi": "ಬರಹ API à²¯ à²¬à²³à²\95à³\86",
        "right-delete": "ಪುಟಗಳನ್ನು ಅಳಿಸಿ",
        "right-bigdelete": "ಜಾಸ್ತಿ ಇತಿಹಾಸವಿರುವ ಪುಟಗಳನ್ನು ಅಳಿಸಿ",
        "right-deleterevision": "ಪುಟದ ಕೆಲ ಆವೃತ್ತಿಗಳನ್ನು ಅಳಿಸಿ ಹಾಗು ಉಳಿಸಿ",
        "rcshowhidemine": "ನನ್ನ ಸಂಪಾದನೆಗಳನ್ನು $1",
        "rcshowhidemine-show": "ತೊರಿಸಿ",
        "rcshowhidemine-hide": "ಮರೆ ಮಾಡಿ",
-       "rclinks": "à²\95à³\8aನà³\86ಯ $2 à²¦à²¿à²¨à²\97ಳಲà³\8dಲಿ à²®à²¾à²¡à²¿à²¦ $1 à²\95à³\8aನà³\86ಯ à²¬à²¦à²²à²¾à²µà²£à³\86à²\97ಳನà³\8dನà³\81 à²¨à³\8bಡಿ",
+       "rclinks": "ಕೊನೆಯ $2 ದಿನಗಳಲ್ಲಿ ಮಾಡಿದ $1 ಬದಲಾವಣೆಗಳನ್ನು ನೋಡಿ",
        "diff": "ವ್ಯತ್ಯಾಸ",
        "hist": "ಇತಿಹಾಸ",
        "hide": "ಅಡಗಿಸು",
        "undelete-show-file-submit": "ಹೌದು",
        "namespace": "ಹೆಸರಿನ ಬಗೆ:",
        "invert": "ಆಯ್ಕೆಯನ್ನು ತಿರುಗಿಸು",
+       "tooltip-invert": "ಆಯ್ದ ಹೆಸರಿನ ಜಾಗದಲ್ಲಿ ಬದಲಾವಣೆಗಳನ್ನು ಮರೆಮಾಡಲು ಈ ಪೆಟ್ಟಿಗೆಯನ್ನು ಪರಿಶೀಲಿಸಿ (ಮತ್ತು ಪರಿಶೀಲಿಸಿದ ವೇಳೆ ಸಂಬಂಧಿತ ನೇಮ್ಸ್ಪೇಸ್)",
+       "namespace_association": "ಅಸೋಸಿಯೇಟೆಡ್ ನೇಮ್ಸ್ಪೇಸ್",
+       "tooltip-namespace_association": "ಆಯ್ಕೆ ಮಾಡಲಾದ ಹೆಸರಿನೊಂದಿಗೆ ಸಂಬಂಧಿಸಿದ ಚರ್ಚೆ ಅಥವಾ ವಿಷಯ ನಾಮಪದವನ್ನು ಸೇರಿಸಲು ಈ ಪೆಟ್ಟಿಗೆಯನ್ನು ಪರಿಶೀಲಿಸಿ",
        "blanknamespace": "(ಮುಖ್ಯ)",
        "contributions": "{{GENDER:$1|User}} ಕಾಣಿಕೆಗಳು",
        "contributions-title": "$1 ಸದಸ್ಯರ ಕಾಣಿಕೆಗಳು",
        "tooltip-feed-atom": "ಈ ಪುಟಕ್ಕೆ Atom ಫೀಡು",
        "tooltip-t-contributions": "{{GENDER:$1|ಈ ಸದಸ್ಯರ}} ಕಾಣಿಕೆಗಳ ಪಟ್ಟಿ",
        "tooltip-t-emailuser": "ಈ ಸದಸ್ಯರಿಗೆ ಇ-ಅಂಚೆಯನ್ನು ಕಳುಹಿಸು",
-       "tooltip-t-upload": "ಕಡತ ಸೇರಿಸಿ",
+       "tooltip-t-upload": "ಕಡತಗಳನ್ನು ಸೇರಿಸಿ",
        "tooltip-t-specialpages": "ಎಲ್ಲಾ ವಿಶೇಷ ಪುಟಗಳ ಪಟ್ಟಿ",
        "tooltip-t-print": "ಈ ಪುಟದ ಮುದ್ರಣ ಮಾಡಬಹುದಾದಂತ ಆವೃತ್ತಿ",
        "tooltip-t-permalink": "ಪುಟದ ಈ ಆವೃತ್ತಿಗೆ ಶಾಶ್ವತ ಕೊಂಡಿ",
index f9338d2..b612872 100644 (file)
        "rcfilters-filter-minor-description": "기여자가 사소한 기여로 표시한 편집.",
        "rcfilters-filter-major-label": "사소하지 않은 편집",
        "rcfilters-filter-major-description": "사소한 편집으로 표시되지 않은 편집.",
+       "rcfilters-filtergroup-watchlist": "주시 중인 문서",
+       "rcfilters-filter-watchlist-watched-label": "주시문서 목록에서",
+       "rcfilters-filter-watchlist-watched-description": "주시문서 목록의 문서의 변경사항입니다.",
+       "rcfilters-filter-watchlist-watchednew-label": "새로운 주시문서 목록 변경사항",
+       "rcfilters-filter-watchlist-notwatched-label": "주시문서 목록에서가 아닌",
+       "rcfilters-filter-watchlist-notwatched-description": "주시 중인 문서의 변경사항을 제외한 모든 사항입니다.",
        "rcfilters-filtergroup-changetype": "차이 종류",
        "rcfilters-filter-pageedits-label": "문서 편집",
        "rcfilters-filter-pageedits-description": "위키 내용, 토론, 분류 설명에 대한 편집....",
        "rcfilters-hideminor-conflicts-typeofchange-global": "특정한 유형의 변경사항을 \"사소한 편집\"으로 지정할 수 없기 때문에 \"사소한 편집\" 필터는 하나 이상의 변경사항 유형 필터와 충돌합니다. 충돌되는 필터들은 위의 사용 중인 필터 영역에 표시됩니다.",
        "rcfilters-hideminor-conflicts-typeofchange": "특정한 종류의 변경사항은 \"사소한 편집\"으로 지정할 수 없으므로 이 필터는 다음 유형의 변경사항 필터와 충돌합니다: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "이 유형의 변경사항 필터는 \"사소한 편집\" 필터와 충돌합니다. 특정한 종류의 변경사항은 \"사소한 편집\"으로 지정할 수 없습니다.",
+       "rcfilters-filtergroup-lastRevision": "마지막 판",
+       "rcfilters-filter-lastrevision-description": "문서의 최근 변경사항입니다.",
        "rcnotefrom": "아래는 <strong>$3, $4</strong>부터 시작하는 {{PLURAL:$5|바뀜이 있습니다}}. (최대 <strong>$1</strong>개가 표시됨)",
        "rclistfromreset": "날짜 선택 초기화",
        "rclistfrom": "$3 $2부터 시작하는 새로 바뀐 문서 보기",
index 75a85d3..291b46d 100644 (file)
        "preview": "Forhåndsvisning",
        "showpreview": "Forhåndsvisning",
        "showdiff": "Vis endringer",
-       "blankarticle": "<strong>Advarsel:</strong> Siden du er i ferd med å opprette er tom.\nHvis du trykker \"$1\" en gang til, vil siden opprettes uten innhold.",
+       "blankarticle": "<strong>Advarsel:</strong> Siden du er i ferd med å opprette er tom.\nHvis du trykker «$1» en gang til, vil siden opprettes uten innhold.",
        "anoneditwarning": "<strong>Advarsel:</strong> Du er ikke innlogget. IP-adressen din vil bli vist offentlig om du redigerer. Hvis du <strong>[$1 logger inn]</strong> eller <strong>[$2 oppretter en konto]</strong> vil redigeringene dine tilskrives brukernavnet ditt, og du vil få flere andre fordeler.",
        "anonpreviewwarning": "<em>Du er ikke logget inn. Ved lagring vil IP-adressen din lagres i sidens redigeringshistorikk.</em>",
        "missingsummary": "'''Påminnelse:''' Du har ikke lagt inn en redigeringsforklaring.\nVelger du ''Lagre siden'' en gang til blir endringene lagret uten forklaring.",
        "rcfilters-filter-minor-description": "Redigeringer merket som mindre av brukeren.",
        "rcfilters-filter-major-label": "Ikke-mindre endringer",
        "rcfilters-filter-major-description": "Redigeringer som ikke er merket som mindre.",
+       "rcfilters-filtergroup-watchlist": "Overvåkede sider",
+       "rcfilters-filter-watchlist-watched-label": "På overvåkningslisten",
+       "rcfilters-filter-watchlist-watched-description": "Endringer til sider på overvåkningslista di.",
+       "rcfilters-filter-watchlist-watchednew-label": "Nye endringer på overvåkningslista",
+       "rcfilters-filter-watchlist-watchednew-description": "Endringer i overvåkede sider du ikke har besøkt siden endringen(e) ble gjort.",
+       "rcfilters-filter-watchlist-notwatched-label": "Ikke på overvåkningslista.",
+       "rcfilters-filter-watchlist-notwatched-description": "Alt utenom endringer på sider på overvåkningslista di.",
        "rcfilters-filtergroup-changetype": "Type endring",
        "rcfilters-filter-pageedits-label": "Sideredigeringer",
        "rcfilters-filter-pageedits-description": "Redigeringer til wikiinnhold, diskusjoner, kategoribeskrivelser ...",
index a2f1aea..2d339bb 100644 (file)
        "missingsummary": "'''Nòta:''' a l'ha butà gnun resumé dla modìfica. Se a sgnaca «$1» n'àutra vira, soa modìfica a resterà salvà sensa resumé.",
        "selfredirect": "<strong>Atension:</strong> A l'é an camin ch'a ridiression-a sa pàgina a chila-midema.\nMiraco a l'ha spessificà ël bërsaj sbalià për la ridiression, opura a l'é an camin ch'a modìfica la pàgina sbalià.\nS'a sgnaca torna ansima a «$1», la ridiression a sarà creà istess.",
        "missingcommenttext": "Për piasì, che a buta un coment sì-sota.",
-       "missingcommentheader": "'''Ch'a arcòrda:''' A l'ha pa dàit ëd soget o d'intestassion për cost coment.\nSe a sgnaca torna «$1», soa modìfica a sarà salvà sensa gnun-a intestassion.",
+       "missingcommentheader": "'''Ch'a ten-a da ment:''' A l'ha pa dàit ëd soget o d'intestassion për cost coment.\nSe a sgnaca torna «$1», soa modìfica a sarà salvà sensa gnun-a intestassion.",
        "summary-preview": "Preuva dël resumé:",
        "subject-preview": "Preuva dl'oget/intestassion:",
        "previewerrortext": "A l'é rivaje n'eror durant ël tentativ ëd previsualisassion ëd soe modìfiche.",
index 2783bda..2f34b3a 100644 (file)
        "confirmable-no": "Нет",
        "thisisdeleted": "Просмотреть или восстановить $1?",
        "viewdeleted": "Просмотреть $1?",
-       "restorelink": "{{PLURAL:$1|1=$1 удалённую правку|$1 удалённые правки|$1 удалённых правок|1=удалённую правку}}",
+       "restorelink": "{{PLURAL:$1|$1 удалённую правку|$1 удалённые правки|$1 удалённых правок|1=удалённую правку}}",
        "feedlinks": "В виде:",
        "feed-invalid": "Неправильный тип канала для подписки.",
        "feed-unavailable": "Ленты синдикации недоступны",
index 666d46b..0a8b4e2 100644 (file)
        "botpasswords-label-delete": "ڊاهيو",
        "botpasswords-label-resetpassword": "ڳجھولفظ ٻيھر مقرر ڪريو",
        "botpasswords-label-grants-column": "منظور",
+       "botpasswords-bad-appid": "بوٽ نانءُ \"$1\" قابلِڪار ناھي.",
        "resetpass_forbidden": "ڳجھالفظ بدلائي نٿا سگھجن",
        "resetpass_forbidden-reason": "ڳجھالفظ بدلائي نٿا سگھجن:$1",
        "resetpass-no-info": "هيءُ صفحو پڙهڻ لاءِ داخل ٿيڻ ضروري آهي.",
        "recentchanges-legend-heading": "<strong>ڪنجي:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (پڻ ڏسو [[Special:NewPages|نون صفحن جي فھرست]])",
        "recentchanges-submit": "ڏيکاريو",
+       "rcfilters-activefilters": "سرگرم ڇاڻيون",
+       "rcfilters-empty-filter": "ڪي بہ سرگرم ڇاڻيون ناھن. سڀ ڀاڱيداريون ڏيکاريل آھن.",
+       "rcfilters-filterlist-title": "ڇاڻيون",
        "rcfilters-filterlist-whatsthis": "هي ڇا آهي؟",
        "rcfilters-highlightbutton-title": "نتيجن کي نمايان (هاءِ لائيٽ) ڪيو",
        "rcfilters-highlightmenu-title": "رنگ چونڊيو",
+       "rcfilters-filter-bots-label": "بوٽ",
+       "rcfilters-filter-humans-label": "انسان (بوٽ نہ)",
+       "rcfilters-filter-humans-description": "انساني ايڊيٽرن پاران ڪيل ترميمون.",
+       "rcfilters-filter-pageedits-label": "صفحي ترميمون",
        "rcnotefrom": "هيٺ {{PLURAL:$5|تبديلي آهي|تبديليون آهن}} کان <strong>$3, $4</strong> (تائين <strong>$1</strong> ) ڏيکاريل آهن.",
        "rclistfrom": "$2، $3 کان شروع ٿيندڙ نيون تبديليون ڏيکاريو",
        "rcshowhideminor": "$1 معمولي ترميمون",
        "tags-title": "ٽيگس",
        "tags-tag": "ٽيگ نانءُ",
        "tags-source-header": "ذريعو",
+       "tags-active-header": "سرگرم؟",
        "tags-active-yes": "ها",
        "tags-active-no": "نہ",
        "tags-edit": "سنواريو",
index 7432feb..4e99575 100644 (file)
        "rcfilters-filter-registered-description": "Éditor asup log",
        "rcfilters-filter-unregistered-label": "Teu kadaptar",
        "rcfilters-filter-unregistered-description": "Éditor nu teu asup log.",
+       "rcfilters-filtergroup-authorship": "Kontribusi kapangarangan",
        "rcfilters-filter-editsbyself-label": "Éditan meunang anjeun",
        "rcfilters-filter-editsbyself-description": "Kontribusi anjeun.",
        "rcfilters-filter-editsbyother-label": "Éditan ku batur",
index b4584ab..ebde407 100644 (file)
        "editingsection": "Redigerar $1 (avsnitt)",
        "editingcomment": "Redigerar $1 (nytt avsnitt)",
        "editconflict": "Redigeringskonflikt: $1",
-       "explainconflict": "Någon har ändrat den här sidan efter att du började att redigera den.\nDen översta textrutan innehåller den nuvarande sparade versionen av texten.\nDin ändrade version visas i den nedre rutan.\nOm du vill spara dina ändringar så måste du infoga dem i den övre texten.\n'''Endast''' texten i den översta textrutan kommer att sparas när du trycker på \"$1\".",
+       "explainconflict": "Någon har ändrat den här sidan efter att du började att redigera den.\nDen översta textrutan innehåller den nuvarande sparade versionen av texten.\nDin ändrade version visas i den nedre rutan.\nOm du vill spara dina ändringar så måste du infoga dem i den övre texten.\n<strong>Endast</strong> texten i den översta textrutan kommer att sparas när du trycker på \"$1\".",
        "yourtext": "Din text",
        "storedversion": "Den sparade versionen",
        "nonunicodebrowser": "'''VARNING: Din webbläsare saknar stöd för unicode. För att du ska kunna redigera sidor utan problem, så visas icke-ASCII-tecken som hexadecimala koder i redigeringsrutan.'''",
        "rcfilters-filter-unregistered-label": "Oregistrerade",
        "rcfilters-filter-unregistered-description": "Redigerare som inte är inloggade.",
        "rcfilters-filter-unregistered-conflicts-user-experience-level": "Detta filter är i konflikt med följande {{PLURAL:$2|upplevelsefilter}}, som endast {{PLURAL:$2|hittar}} registrerade användare: $1",
-       "rcfilters-filtergroup-authorship": "Redigera författarskap",
-       "rcfilters-filter-editsbyself-label": "Dina egna redigeringar",
-       "rcfilters-filter-editsbyself-description": "Redigeringar av dig.",
-       "rcfilters-filter-editsbyother-label": "Redigeringar av andra",
-       "rcfilters-filter-editsbyother-description": "Redigeringar som har skapats av andra användare (inte dig).",
+       "rcfilters-filtergroup-authorship": "Författarskap av bidrag",
+       "rcfilters-filter-editsbyself-label": "Redigeringar av dig",
+       "rcfilters-filter-editsbyself-description": "Dina egna bidrag.",
+       "rcfilters-filter-editsbyother-label": "Ändringar av andra",
+       "rcfilters-filter-editsbyother-description": "Alla ändringar förutom dina egna.",
        "rcfilters-filtergroup-userExpLevel": "Erfarenhetsnivå (endast för registrerade användare)",
        "rcfilters-filtergroup-user-experience-level-conflicts-unregistered": "Upplevelsefilter hittar endast registrerade användare, så detta filter är i konflikt med filtret \"Oregistrerade\".",
        "rcfilters-filtergroup-user-experience-level-conflicts-unregistered-global": "Filtret \"Oregistrerade\" är i konflikt med en eller flera upplevelsefilter, som endast hittar registrerade användare. Filtren som är i konflikt är markerade i området med aktiva filter ovan.",
        "rcfilters-filter-minor-description": "Redigeringar som är märkta som mindre.",
        "rcfilters-filter-major-label": "Icke-mindre redigeringar",
        "rcfilters-filter-major-description": "Redigeringar som inte är märkta som mindre.",
+       "rcfilters-filtergroup-watchlist": "Bevakade sidor",
+       "rcfilters-filter-watchlist-watched-label": "I bevakningslistan",
+       "rcfilters-filter-watchlist-watched-description": "Ändringar i sidor på din bevakningslista.",
+       "rcfilters-filter-watchlist-watchednew-label": "Nya ändringar i bevakningslistan",
+       "rcfilters-filter-watchlist-watchednew-description": "Ändringar i bevakade sidor som du inte har besökt sedan ändringarna ägde rum.",
+       "rcfilters-filter-watchlist-notwatched-label": "Inte i bevakningslistan",
+       "rcfilters-filter-watchlist-notwatched-description": "Allting förutom ändringar i sidor på din bevakningslista.",
        "rcfilters-filtergroup-changetype": "Typ av ändring",
        "rcfilters-filter-pageedits-label": "Sidredigeringar",
        "rcfilters-filter-pageedits-description": "Redigeringar till wikiinnehåll, diskussioner, kategoribeskrivningar...",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filtret \"Mindre redigering\" är i konflikt med en eller flera ändringstypfilter, eftersom vissa ändringstyper inte kan betecknas som \"mindre\". Filtren som är i konflikt är markerade i området med aktiva filter ovan.",
        "rcfilters-hideminor-conflicts-typeofchange": "Vissa ändringstyper kan inte betecknas som \"mindre\", så detta filter är i konflikt med följande ändringstypfilter: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Detta ändringstypfilter är i konflikt med filtret \"Mindre ändringar\". Vissa ändringstyper kan inte betecknas som \"mindre\".",
+       "rcfilters-filtergroup-lastRevision": "Senaste version",
+       "rcfilters-filter-lastrevision-label": "Senaste version",
+       "rcfilters-filter-lastrevision-description": "Den senaste ändringen av en sida.",
+       "rcfilters-filter-previousrevision-label": "Tidigare versioner",
+       "rcfilters-filter-previousrevision-description": "Alla ändringar som inte är den senaste ändringen av en sida.",
        "rcnotefrom": "Nedan visas {{PLURAL:$5|ändringen|ändringar}} sedan <strong>$3, $4</strong> (upp till <strong>$1</strong> ändringar visas).",
        "rclistfromreset": "Återställ datumval",
        "rclistfrom": "Visa nya ändringar från och med $2 $3",
        "enotif_body_intro_moved": "{{SITENAME}}sidan $1 flyttades den $PAGEEDITDATE av {{gender:$2|$2}}, se $3 för den aktuella versionen.",
        "enotif_body_intro_restored": "{{SITENAME}}sidan $1 återställdes den $PAGEEDITDATE av {{gender:$2|$2}}, se $3 för den aktuella versionen.",
        "enotif_body_intro_changed": "{{SITENAME}}sidan $1 ändrades den $PAGEEDITDATE av {{gender:$2|$2}}, se $3 för den aktuella versionen.",
-       "enotif_lastvisited": "På $1 återfinner du alla ändringar sedan ditt senaste besök.",
-       "enotif_lastdiff": "Se denna ändring på $1",
+       "enotif_lastvisited": "För alla ändringar sedan ditt senaste besök, se $1",
+       "enotif_lastdiff": "För att se denna ändring, se $1",
        "enotif_anon_editor": "anonym användare $1",
        "enotif_body": "Hej $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nAngiven sammanfattning av redigeringen: $PAGESUMMARY $PAGEMINOREDIT\n\nKontakta användaren:\ne-post: $PAGEEDITOR_EMAIL\nwiki: $PAGEEDITOR_WIKI\n\nSåvida du inte besöker sidan, kommer du inte att få flera meddelanden om aktivitet på sidan när du är inloggad. Du kan också ta bort flaggan för meddelanden om ändringar på alla sidor i din bevakningslista.\n\nHälsningar från {{SITENAME}}s meddelandesystem\n\n--\nFör att ändra inställningarna för dina uppdateringar via e-post, besök\n{{canonicalurl:{{#special:Preferences}}}}\n\nFör att ändra inställningarna i din bevakningslista, besök\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nFör att radera sidan från din bevakningslista, besök\n$UNWATCHURL\n\nFeedback och ytterligare hjälp:\n$HELPPAGE",
        "created": "skapad",
        "sp-contributions-uploads": "uppladdningar",
        "sp-contributions-logs": "loggar",
        "sp-contributions-talk": "diskussion",
-       "sp-contributions-userrights": "hantering av användarrättigheter",
+       "sp-contributions-userrights": "hantering av {{GENDER:$1|användarrättigheter}}",
        "sp-contributions-blocked-notice": "Användaren är blockerad.\nDen senaste posten i blockeringsloggen visas nedan som referens:",
        "sp-contributions-blocked-notice-anon": "Denna IP-adress är för närvarande blockerad.\nDen senaste posten i blockeringsloggen visas nedan som referens:",
        "sp-contributions-search": "Sök efter användarbidrag",
        "tooltip-pt-mycontris": "Lista över {{GENDER:|dina}} bidrag",
        "tooltip-pt-anoncontribs": "En lista över redigeringar från denna IP-adress",
        "tooltip-pt-login": "Du uppmuntras att logga in, men det är inget krav",
+       "tooltip-pt-login-private": "Du måste logga in på denna wiki",
        "tooltip-pt-logout": "Logga ut",
        "tooltip-pt-createaccount": "Du uppmuntras att skapa ett konto och logga in, men det är inte obligatoriskt",
        "tooltip-ca-talk": "Diskussion om innehållssidan",
        "anonymous": "{{PLURAL:$1|Anonym användare|Anonyma användare}} på {{SITENAME}}",
        "siteuser": "användaren $1 på {{SITENAME}}",
        "anonuser": "{{SITENAME}} anonym användare $1",
-       "lastmodifiedatby": "Den här sidan ändrades senast kl. $2 den $1 av $3.",
+       "lastmodifiedatby": "Den här sidan redigerades senast kl. $2 den $1 av $3.",
        "othercontribs": "Baserad på arbete av $1.",
        "others": "andra",
        "siteusers": "{{SITENAME}}-{{PLURAL:$2|{{GENDER:$1|användaren}}|användarna}} $1",
        "confirmrecreate": "Användaren [[User:$1|$1]] ([[User talk:$1|diskussion]]) raderade den här sidan efter att du började redigera den med motiveringen:\n: <em>$2</em>\nBekräfta att du verkligen vill återskapa sidan.",
        "confirmrecreate-noreason": "Användare [[User:$1|$1]] ([[User talk:$1|diskussion]]) {{GENDER:$1|raderade}} den här sidan efter att du började redigera. Bekräfta att du verkligen vill återskapa sidan.",
        "recreate": "Återskapa",
+       "confirm-purge-title": "Rensa cachen för denna sida",
        "confirm_purge_button": "OK",
        "confirm-purge-top": "Rensa denna sidas cache?",
        "confirm-purge-bottom": "Rensning av en sida tömmer cachen och tvingar fram den senaste versionen.",
index cde6674..759183e 100644 (file)
        "metadata-help": "此文件中包含有额外的信息。这些信息可能是由数码相机或扫描仪在创建或数字化过程中所添加的。如果文件自初始状态已受到修改,一些详细说明可能无法反映修改后的文件。",
        "metadata-expand": "显示详细资料",
        "metadata-collapse": "隐藏详细资料",
-       "metadata-fields": "在本信息中所列出的 EXIF 元数据域将包含在图片显示页面,当元数据表损坏时只显示以下信息。\n其他的元数据默认为隐藏。\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+       "metadata-fields": "在本信息中所列出的 EXIF 元数据域将包含在图片显示页面,当元数据表损坏时只显示以下信息。其他的元数据默认为隐藏。\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
        "exif-imagewidth": "宽度",
        "exif-imagelength": "高度",
        "exif-bitspersample": "每像素字节数",
index eb717e8..287a40c 100644 (file)
@@ -59,7 +59,7 @@ unset( $lines );
 
 $lines = explode( "\n", shell_exec( 'git log --format="%aN"' ) );
 foreach ( $lines as $line ) {
-       if ( empty( $line ) )  {
+       if ( empty( $line ) ) {
                continue;
        }
        if ( substr( $line, 0, 5 ) === '[BOT]' ) {
index 55f36a3..ee42b07 100644 (file)
@@ -9,7 +9,7 @@
   "devDependencies": {
     "deepmerge": "1.3.2",
     "eslint": "3.12.2",
-    "eslint-config-wikimedia": "0.3.0",
+    "eslint-config-wikimedia": "0.4.0",
     "grunt": "1.0.1",
     "grunt-banana-checker": "0.6.0",
     "grunt-contrib-copy": "1.0.0",
index 15d0a39..143e46c 100644 (file)
                                                .revisions[ 0 ].diff.body;
                                        $wikiDiff.find( 'table.diff tbody' ).html( diffHtml );
                                        mw.hook( 'wikipage.diff' ).fire( $wikiDiff.find( 'table.diff' ) );
-                               } catch ( e ) {
+                               } catch ( err ) {
                                        // "result.blah is undefined" error, ignore
-                                       mw.log.warn( e );
+                                       mw.log.warn( err );
                                }
                                $wikiDiff.show();
                        } );
index ca7c4e6..63e13fd 100644 (file)
        /**
         * Get the parameter representation from this group
         *
+        * @param {Object} [filterRepresentation] An object defining the state
+        *  of the filters in this group, keyed by their name and current selected
+        *  state value.
         * @return {Object} Parameter representation
         */
-       mw.rcfilters.dm.FilterGroup.prototype.getParamRepresentation = function () {
-               var i, values,
+       mw.rcfilters.dm.FilterGroup.prototype.getParamRepresentation = function ( filterRepresentation ) {
+               var values,
+                       areAnySelected = false,
+                       buildFromCurrentState = !filterRepresentation,
                        result = {},
-                       filterItems = this.getItems();
+                       filterParamNames = {};
+
+               filterRepresentation = filterRepresentation || {};
+
+               // Create or complete the filterRepresentation definition
+               this.getItems().forEach( function ( item ) {
+                       // Map filter names to their parameter names
+                       filterParamNames[ item.getName() ] = item.getParamName();
+
+                       if ( buildFromCurrentState ) {
+                               // This means we have not been given a filter representation
+                               // so we are building one based on current state
+                               filterRepresentation[ item.getName() ] = item.isSelected();
+                       } else if ( !filterRepresentation[ item.getName() ] ) {
+                               // We are given a filter representation, but we have to make
+                               // sure that we fill in the missing filters if there are any
+                               // we will assume they are all falsey
+                               filterRepresentation[ item.getName() ] = false;
+                       }
 
+                       if ( filterRepresentation[ item.getName() ] ) {
+                               areAnySelected = true;
+                       }
+               } );
+
+               // Build result
                if ( this.getType() === 'send_unselected_if_any' ) {
                        // First, check if any of the items are selected at all.
                        // If none is selected, we're treating it as if they are
                        // all false
 
                        // Go over the items and define the correct values
-                       for ( i = 0; i < filterItems.length; i++ ) {
-                               result[ filterItems[ i ].getParamName() ] = this.areAnySelected() ?
-                                       Number( !filterItems[ i ].isSelected() ) : 0;
-                       }
-
+                       $.each( filterRepresentation, function ( name, value ) {
+                               result[ filterParamNames[ name ] ] = areAnySelected ?
+                                       Number( !value ) : 0;
+                       } );
                } else if ( this.getType() === 'string_options' ) {
                        values = [];
-                       for ( i = 0; i < filterItems.length; i++ ) {
-                               if ( filterItems[ i ].isSelected() ) {
-                                       values.push( filterItems[ i ].getParamName() );
+
+                       $.each( filterRepresentation, function ( name, value ) {
+                               // Collect values
+                               if ( value ) {
+                                       values.push( filterParamNames[ name ] );
                                }
-                       }
+                       } );
 
-                       result[ this.getName() ] = ( values.length === filterItems.length ) ?
+                       result[ this.getName() ] = ( values.length === Object.keys( filterRepresentation ).length ) ?
                                'all' : values.join( this.getSeparator() );
                }
 
index 69210be..aa261d3 100644 (file)
         * Analyze the groups and their filters and output an object representing
         * the state of the parameters they represent.
         *
-        * @param {Object} [filterGroups] An object defining the filter groups to
-        *  translate to parameters. Its structure must follow that of this.groups
-        *  see #getFilterGroups
+        * @param {Object} [filterDefinition] An object defining the filter values,
+        *  keyed by filter names.
         * @return {Object} Parameter state object
         */
-       mw.rcfilters.dm.FiltersViewModel.prototype.getParametersFromFilters = function ( filterGroups ) {
-               var result = {},
-                       groupItems = filterGroups || this.getFilterGroups();
+       mw.rcfilters.dm.FiltersViewModel.prototype.getParametersFromFilters = function ( filterDefinition ) {
+               var groupItemDefinition,
+                       result = {},
+                       groupItems = this.getFilterGroups();
+
+               if ( filterDefinition ) {
+                       groupItemDefinition = {};
+                       // Filter definition is "flat", but in effect
+                       // each group needs to tell us its result based
+                       // on the values in it. We need to split this list
+                       // back into groupings so we can "feed" it to the
+                       // loop below, and we need to expand it so it includes
+                       // all filters (set to false)
+                       this.getItems().forEach( function ( filterItem ) {
+                               groupItemDefinition[ filterItem.getGroupName() ] = groupItemDefinition[ filterItem.getGroupName() ] || {};
+                               groupItemDefinition[ filterItem.getGroupName() ][ filterItem.getName() ] = !!filterDefinition[ filterItem.getName() ];
+                       } );
+               }
 
                $.each( groupItems, function ( group, model ) {
-                       $.extend( result, model.getParamRepresentation() );
+                       $.extend(
+                               result,
+                               model.getParamRepresentation(
+                                       groupItemDefinition ?
+                                               groupItemDefinition[ group ] : null
+                               )
+                       );
                } );
 
                return result;
         * @param {string[]} valueArray Array of values
         * @return {string[]} Array of valid values
         */
-       mw.rcfilters.dm.FiltersViewModel.prototype.sanitizeStringOptionGroup = function( groupName, valueArray ) {
+       mw.rcfilters.dm.FiltersViewModel.prototype.sanitizeStringOptionGroup = function ( groupName, valueArray ) {
                var result = [],
                        validNames = this.getGroupFilters( groupName ).map( function ( filterItem ) {
                                return filterItem.getParamName();
index f3eef7c..f53850a 100644 (file)
 
                Util.fetchModuleInfo( this.apiModule )
                        .done( function ( pi ) {
-                               var prefix, i, j, descriptionContainer, widget, $widgetLabel, widgetField, helpField, tmp, flag, count,
+                               var prefix, i, j, descriptionContainer, widget, widgetField, helpField, tmp, flag, count,
                                        items = [],
                                        deprecatedItems = [],
                                        buttons = [],
                                                        }
                                                );
 
-                                               $widgetLabel = $( '<span>' );
                                                widgetField = new OO.ui.FieldLayout(
                                                        widget,
                                                        {
                                                                align: 'left',
                                                                classes: [ 'mw-apisandbox-widget-field' ],
-                                                               label: prefix + pi.parameters[ i ].name,
-                                                               $label: $widgetLabel
+                                                               label: prefix + pi.parameters[ i ].name
                                                        }
                                                );
 
-                                               // FieldLayout only does click for InputElement
-                                               // widgets. So supply our own click handler.
-                                               $widgetLabel.on( 'click', widgetLabelOnClick.bind( widgetField ) );
+                                               // We need our own click handler on the widget label to
+                                               // turn off the disablement.
+                                               widgetField.$label.on( 'click', widgetLabelOnClick.bind( widgetField ) );
 
                                                // Don't grey out the label when the field is disabled,
                                                // it makes it too hard to read and our "disabled"
index 7e42886..f3d1fea 100644 (file)
@@ -66,7 +66,7 @@
                        return;
                }
 
-               results.sort( function( a, b ) {
+               results.sort( function ( a, b ) {
                        return a.index - b.index;
                } );
 
index 70d7cb5..d7464b9 100644 (file)
@@ -85,7 +85,7 @@
         *
         * @return {Array} usernames
         */
-       mw.widgets.UsersMultiselectWidget.prototype.getSelectedUsernames = function() {
+       mw.widgets.UsersMultiselectWidget.prototype.getSelectedUsernames = function () {
                return this.getItemsData();
        };
 
@@ -94,7 +94,7 @@
         *
         * @private
         */
-       mw.widgets.UsersMultiselectWidget.prototype.updateMenuItems = function() {
+       mw.widgets.UsersMultiselectWidget.prototype.updateMenuItems = function () {
                var inputValue = this.$input.val();
 
                if ( inputValue === this.inputValue ) {
                                // character to uppercase so that "fo" may yield "Foo".
                                auprefix: inputValue[ 0 ].toUpperCase() + inputValue.slice( 1 ),
                                aulimit: this.limit
-                       } ).done( function( response ) {
+                       } ).done( function ( response ) {
                                var suggestions = response.query.allusers,
                                        selected = this.getSelectedUsernames();
 
                                                        label: user.name
                                                } );
                                        }
-                               } ).filter( function( item ) {
+                               } ).filter( function ( item ) {
                                        return item !== undefined;
                                } );
 
         *
         * @private
         */
-       mw.widgets.UsersMultiselectWidget.prototype.updateHiddenInput = function() {
+       mw.widgets.UsersMultiselectWidget.prototype.updateHiddenInput = function () {
                if ( 'hiddenInput' in this ) {
                        this.hiddenInput.val( this.getSelectedUsernames().join( '\n' ) );
                }
index e3a8f7b..ee3bac2 100644 (file)
@@ -98,6 +98,7 @@
                         */
                        trigger: function () {
                                // use confirm to show the message to the user (if options.text() is true)
+                               // eslint-disable-next-line no-alert
                                if ( options.test() && !confirm( message ) ) {
                                        // the user want to keep the actual page
                                        return false;
index 638fba7..9332773 100644 (file)
                                // Use Function.prototype#call to force an exception on Firefox,
                                // which doesn't define console#table but doesn't complain if you
                                // try to invoke it.
+                               // eslint-disable-next-line no-useless-call
                                console.table.call( console, data );
                                return;
                        } catch ( e ) {}
diff --git a/tests/phpunit/data/media/adobergb.jpg b/tests/phpunit/data/media/adobergb.jpg
new file mode 100644 (file)
index 0000000..470c2d6
Binary files /dev/null and b/tests/phpunit/data/media/adobergb.jpg differ
diff --git a/tests/phpunit/data/media/missingprofile.jpg b/tests/phpunit/data/media/missingprofile.jpg
new file mode 100644 (file)
index 0000000..4085f0a
Binary files /dev/null and b/tests/phpunit/data/media/missingprofile.jpg differ
index b965dc4..f10ced0 100644 (file)
Binary files a/tests/phpunit/data/media/srgb.jpg and b/tests/phpunit/data/media/srgb.jpg differ
index 12a8e09..63b687e 100644 (file)
Binary files a/tests/phpunit/data/media/tinyrgb.jpg and b/tests/phpunit/data/media/tinyrgb.jpg differ
index 5546de8..0015453 100644 (file)
@@ -23,7 +23,6 @@ class ChangesListFilterTest extends MediaWikiTestCase {
                                'filters' => [],
                        ]
                );
-
        }
 
        // @codingStandardsIgnoreStart
index 97e9b26..f61569a 100644 (file)
@@ -91,7 +91,6 @@ class FakeDatabaseMysqlBase extends DatabaseMysqlBase {
        }
 
        protected function mysqlRealEscapeString( $s ) {
-
        }
 
        function insertId() {
index d7ad1d1..2c199bc 100644 (file)
@@ -13,8 +13,7 @@ class DeferredUpdatesTest extends MediaWikiTestCase {
                $post = DeferredUpdates::POSTSEND;
                $all = DeferredUpdates::ALL;
 
-               $update = $this->getMockBuilder( 'DeferrableUpdate' )
-                             ->getMock();
+               $update = $this->getMock( DeferrableUpdate::class );
                $update->expects( $this->never() )
                        ->method( 'doUpdate' );
 
index 4754b04..1d62a78 100644 (file)
@@ -60,20 +60,37 @@ class InterwikiLookupAdapterTest extends MediaWikiTestCase {
        }
 
        public function testGetAllPrefixes() {
+               $foo = [
+                       'iw_prefix' => 'foo',
+                       'iw_url' => '',
+                       'iw_api' => '',
+                       'iw_wikiid' => 'foobar',
+                       'iw_local' => false,
+                       'iw_trans' => false,
+               ];
+               $enwt = [
+                       'iw_prefix' => 'enwt',
+                       'iw_url' => 'https://en.wiktionary.org/wiki/$1',
+                       'iw_api' => 'https://en.wiktionary.org/w/api.php',
+                       'iw_wikiid' => 'enwiktionary',
+                       'iw_local' => true,
+                       'iw_trans' => false,
+               ];
+
                $this->assertEquals(
-                       [ 'foo', 'enwt' ],
+                       [ $foo, $enwt ],
                        $this->interwikiLookup->getAllPrefixes(),
                        'getAllPrefixes()'
                );
 
                $this->assertEquals(
-                       [ 'foo' ],
+                       [ $foo ],
                        $this->interwikiLookup->getAllPrefixes( false ),
                        'get external prefixes'
                );
 
                $this->assertEquals(
-                       [ 'enwt' ],
+                       [ $enwt ],
                        $this->interwikiLookup->getAllPrefixes( true ),
                        'get local prefixes'
                );
index 9d12b10..cfc2d91 100644 (file)
@@ -10,7 +10,6 @@ class DnsSrvDiscovererTest extends PHPUnit_Framework_TestCase {
                $record = $discoverer->pickServer( $params );
 
                $this->assertEquals( $expected, $record );
-
        }
 
        public static function provideRecords() {
index 47ed67b..3dd7e4c 100644 (file)
@@ -142,61 +142,4 @@ class ExifBitmapTest extends MediaWikiMediaTestCase {
                $res = $this->handler->convertMetadataVersion( $metadata, 1 );
                $this->assertEquals( $expected, $res );
        }
-
-       /**
-        * @dataProvider provideSwappingICCProfile
-        * @covers ExifBitmapHandler::swapICCProfile
-        */
-       public function testSwappingICCProfile(
-               $sourceFilename, $controlFilename, $newProfileFilename, $oldProfileName
-       ) {
-               global $wgExiftool;
-
-               if ( !$wgExiftool || !is_file( $wgExiftool ) ) {
-                       $this->markTestSkipped( "Exiftool not installed, cannot test ICC profile swapping" );
-               }
-
-               $this->setMwGlobals( 'wgUseTinyRGBForJPGThumbnails', true );
-
-               $sourceFilepath = $this->filePath . $sourceFilename;
-               $controlFilepath = $this->filePath . $controlFilename;
-               $profileFilepath = $this->filePath . $newProfileFilename;
-               $filepath = $this->getNewTempFile();
-
-               copy( $sourceFilepath, $filepath );
-
-               $file = $this->dataFile( $sourceFilename, 'image/jpeg' );
-               $this->handler->swapICCProfile( $filepath, $oldProfileName, $profileFilepath );
-
-               $this->assertEquals(
-                       sha1( file_get_contents( $filepath ) ),
-                       sha1( file_get_contents( $controlFilepath ) )
-               );
-       }
-
-       public function provideSwappingICCProfile() {
-               return [
-                       // File with sRGB should end up with TinyRGB
-                       [
-                               'srgb.jpg',
-                               'tinyrgb.jpg',
-                               'tinyrgb.icc',
-                               'IEC 61966-2.1 Default RGB colour space - sRGB'
-                       ],
-                       // File with TinyRGB should be left unchanged
-                       [
-                               'tinyrgb.jpg',
-                               'tinyrgb.jpg',
-                               'tinyrgb.icc',
-                               'IEC 61966-2.1 Default RGB colour space - sRGB'
-                       ],
-                       // File with no profile should be left unchanged
-                       [
-                               'test.jpg',
-                               'test.jpg',
-                               'tinyrgb.icc',
-                               'IEC 61966-2.1 Default RGB colour space - sRGB'
-                       ]
-               ];
-       }
 }
index 05aed4a..b0f40ef 100644 (file)
@@ -51,4 +51,73 @@ class JpegTest extends MediaWikiMediaTestCase {
 
                $this->assertEquals( $res, $expected );
        }
+
+       /**
+        * @dataProvider provideSwappingICCProfile
+        * @covers ExifBitmapHandler::swapICCProfile
+        */
+       public function testSwappingICCProfile(
+               $sourceFilename, $controlFilename, $newProfileFilename, $oldProfileName
+       ) {
+               global $wgExiftool;
+
+               if ( !$wgExiftool || !is_file( $wgExiftool ) ) {
+                       $this->markTestSkipped( "Exiftool not installed, cannot test ICC profile swapping" );
+               }
+
+               $this->setMwGlobals( 'wgUseTinyRGBForJPGThumbnails', true );
+
+               $sourceFilepath = $this->filePath . $sourceFilename;
+               $controlFilepath = $this->filePath . $controlFilename;
+               $profileFilepath = $this->filePath . $newProfileFilename;
+               $filepath = $this->getNewTempFile();
+
+               copy( $sourceFilepath, $filepath );
+
+               $file = $this->dataFile( $sourceFilename, 'image/jpeg' );
+               $this->handler->swapICCProfile(
+                       $filepath,
+                       [ 'sRGB', '-' ],
+                       [ $oldProfileName ],
+                       $profileFilepath
+               );
+
+               $this->assertEquals(
+                       sha1( file_get_contents( $filepath ) ),
+                       sha1( file_get_contents( $controlFilepath ) )
+               );
+       }
+
+       public function provideSwappingICCProfile() {
+               return [
+                       // File with sRGB should end up with TinyRGB
+                       [
+                               'srgb.jpg',
+                               'tinyrgb.jpg',
+                               'tinyrgb.icc',
+                               'sRGB IEC61966-2.1'
+                       ],
+                       // File with TinyRGB should be left unchanged
+                       [
+                               'tinyrgb.jpg',
+                               'tinyrgb.jpg',
+                               'tinyrgb.icc',
+                               'sRGB IEC61966-2.1'
+                       ],
+                       // File without profile should end up with TinyRGB
+                       [
+                               'missingprofile.jpg',
+                               'tinyrgb.jpg',
+                               'tinyrgb.icc',
+                               'sRGB IEC61966-2.1'
+                       ],
+                       // Non-sRGB file should be left untouched
+                       [
+                               'adobergb.jpg',
+                               'adobergb.jpg',
+                               'tinyrgb.icc',
+                               'sRGB IEC61966-2.1'
+                       ]
+               ];
+       }
 }
index 4cf4071..78eec6a 100644 (file)
@@ -323,7 +323,6 @@ class ResourceLoaderWikiModuleTest extends ResourceLoaderTestCase {
                        $expected,
                        $module->getContent( $titleText )
                );
-
        }
 
        /**
index 6b12229..bb7508c 100644 (file)
@@ -51,7 +51,6 @@ class SearchIndexFieldTest extends MediaWikiTestCase {
                        }
                );
                $this->assertEquals( "test", $field1->merge( $field2 ) );
-
        }
 
 }
index 03e341a..b101857 100644 (file)
@@ -28,6 +28,20 @@ abstract class AbstractChangesListSpecialPageTestCase extends MediaWikiTestCase
                $wgGroupPermissions['patrollers'] = [
                        'patrol' => true,
                ];
+
+               // Deprecated
+               $this->setTemporaryHook(
+                       'ChangesListSpecialPageFilters',
+                       null
+               );
+
+               # setup the ChangesListSpecialPage (or subclass) object
+               $this->changesListSpecialPage = $this->getPage();
+               $context = $this->changesListSpecialPage->getContext();
+               $context = new DerivativeContext( $context );
+               $context->setUser( $this->getTestUser( [ 'patrollers' ] )->getUser() );
+               $this->changesListSpecialPage->setContext( $context );
+               $this->changesListSpecialPage->registerFilters();
        }
 
        protected function tearDown() {
@@ -44,13 +58,6 @@ abstract class AbstractChangesListSpecialPageTestCase extends MediaWikiTestCase
         * @dataProvider provideParseParameters
         */
        public function testParseParameters( $params, $expected ) {
-               $context = $this->changesListSpecialPage->getContext();
-               $context = new DerivativeContext( $context );
-               $context->setUser( $this->getTestUser( [ 'patrollers' ] )->getUser() );
-               $this->changesListSpecialPage->setContext( $context );
-
-               $this->changesListSpecialPage->registerFilters();
-
                $opts = new FormOptions();
                foreach ( $expected as $key => $value ) {
                        // Register it as null so sets aren't rejected.
@@ -73,4 +80,65 @@ abstract class AbstractChangesListSpecialPageTestCase extends MediaWikiTestCase
                        /** named= */ true
                );
        }
+
+       /**
+        * @dataProvider validateOptionsProvider
+        */
+       public function testValidateOptions( $optionsToSet, $expectedRedirect, $expectedRedirectOptions ) {
+               $redirectQuery = [];
+               $redirected = false;
+               $output = $this->getMockBuilder( OutputPage::class )
+                       ->disableProxyingToOriginalMethods()
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $output->method( 'redirect' )->willReturnCallback(
+                       function ( $url ) use ( &$redirectQuery, &$redirected ) {
+                               $urlParts = wfParseUrl( $url );
+                               $query = isset( $urlParts[ 'query' ] ) ? $urlParts[ 'query' ] : '';
+                               parse_str( $query, $redirectQuery );
+                               $redirected = true;
+                       }
+               );
+               $ctx = new RequestContext();
+
+               // Give users patrol permissions so we can test that.
+               $user = $this->getTestSysop()->getUser();
+               $ctx->setUser( $user );
+
+               // Disable this hook or it could break changeType
+               // depending on which other extensions are running.
+               $this->setTemporaryHook(
+                       'ChangesListSpecialPageStructuredFilters',
+                       null
+               );
+
+               $ctx->setOutput( $output );
+               $clsp = $this->changesListSpecialPage;
+               $clsp->setContext( $ctx );
+               $opts = $clsp->getDefaultOptions();
+
+               foreach ( $optionsToSet as $option => $value ) {
+                       $opts->setValue( $option, $value );
+               }
+
+               $clsp->validateOptions( $opts );
+
+               $this->assertEquals( $expectedRedirect, $redirected, 'redirection' );
+
+               if ( $expectedRedirect ) {
+                       if ( count( $expectedRedirectOptions ) > 0 ) {
+                               $expectedRedirectOptions += [
+                                       'title' => $clsp->getPageTitle()->getPrefixedText(),
+                               ];
+                       }
+
+                       $this->assertArrayEquals(
+                               $expectedRedirectOptions,
+                               $redirectQuery,
+                               /* $ordered= */ false,
+                               /* $named= */ true,
+                               'redirection query'
+                       );
+               }
+       }
 }
index 6028573..c8c65dc 100644 (file)
@@ -15,23 +15,26 @@ use Wikimedia\TestingAccessWrapper;
  * @covers ChangesListSpecialPage
  */
 class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase {
-       protected function setUp() {
-               parent::setUp();
-
-               # setup the rc object
-               $this->changesListSpecialPage = $this->getPage();
-       }
-
        protected function getPage() {
-               return TestingAccessWrapper::newFromObject(
-                       $this->getMockForAbstractClass(
-                               'ChangesListSpecialPage',
+               $mock = $this->getMockBuilder( ChangesListSpecialPage::class )
+                       ->setConstructorArgs(
                                [
                                        'ChangesListSpecialPage',
                                        ''
                                ]
                        )
+                       ->setMethods( [ 'getPageTitle' ] )
+                       ->getMockForAbstractClass();
+
+               $mock->method( 'getPageTitle' )->willReturn(
+                       Title::makeTitle( NS_SPECIAL, 'ChangesListSpecialPage' )
                );
+
+               $mock = TestingAccessWrapper::newFromObject(
+                       $mock
+               );
+
+               return $mock;
        }
 
        /** helper to test SpecialRecentchanges::buildMainQueryConds() */
@@ -48,6 +51,7 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                }
 
                $this->changesListSpecialPage->setContext( $context );
+               $this->changesListSpecialPage->filterGroups = [];
                $formOptions = $this->changesListSpecialPage->setup( null );
 
                #  Filter out rc_timestamp conditions which depends on the test runtime
@@ -230,22 +234,6 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                );
        }
 
-       public function testRcHidemyselfHidebyothersFilter() {
-               $user = $this->getTestUser()->getUser();
-               $this->assertConditions(
-                       [ # expected
-                               "rc_user_text != '{$user->getName()}'",
-                               "rc_user_text = '{$user->getName()}'",
-                       ],
-                       [
-                               'hidemyself' => 1,
-                               'hidebyothers' => 1,
-                       ],
-                       "rc conditions: hidemyself=1 hidebyothers=1 (logged in)",
-                       $user
-               );
-       }
-
        public function testRcHidepageedits() {
                $this->assertConditions(
                        [ # expected
@@ -372,22 +360,6 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                );
        }
 
-       public function testRcHidepatrolledHideunpatrolledFilter() {
-               $user = $this->getTestSysop()->getUser();
-               $this->assertConditions(
-                       [ # expected
-                               "rc_patrolled = 0",
-                               "rc_patrolled = 1",
-                       ],
-                       [
-                               'hidepatrolled' => 1,
-                               'hideunpatrolled' => 1,
-                       ],
-                       "rc conditions: hidepatrolled=1 hideunpatrolled=1",
-                       $user
-               );
-       }
-
        public function testHideCategorization() {
                $this->assertConditions(
                        [
@@ -576,6 +548,8 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
        }
 
        public function testGetStructuredFilterJsData() {
+               $this->changesListSpecialPage->filterGroups = [];
+
                $definition = [
                        [
                                'name' => 'gub-group',
@@ -893,4 +867,47 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                        $this->changesListSpecialPage->areFiltersInConflict()
                );
        }
+
+       public function validateOptionsProvider() {
+               return [
+                       [
+                               [ 'hideanons' => 1, 'hideliu' => 1, 'hidebots' => 1 ],
+                               true,
+                               [ 'hideliu' => 1, 'hidebots' => 1, ],
+                       ],
+
+                       [
+                               [ 'hideanons' => 1, 'hideliu' => 1, 'hidebots' => 0 ],
+                               true,
+                               [ 'hidebots' => 0, 'hidehumans' => 1 ],
+                       ],
+
+                       [
+                               [ 'hidemyself' => 1, 'hidebyothers' => 1 ],
+                               true,
+                               [],
+                       ],
+                       [
+                               [ 'hidebots' => 1, 'hidehumans' => 1 ],
+                               true,
+                               [],
+                       ],
+                       [
+                               [ 'hidepatrolled' => 1, 'hideunpatrolled' => 1 ],
+                               true,
+                               [],
+                       ],
+                       [
+                               [ 'hideminor' => 1, 'hidemajor' => 1 ],
+                               true,
+                               [],
+                       ],
+                       [
+                               // changeType
+                               [ 'hidepageedits' => 1, 'hidenewpages' => 1, 'hidecategorization' => 1, 'hidelog' => 1, ],
+                               true,
+                               [],
+                       ],
+               ];
+       }
 }
index e9c7d4b..8f3f585 100644 (file)
@@ -10,15 +10,15 @@ use Wikimedia\TestingAccessWrapper;
  * @covers SpecialRecentChanges
  */
 class SpecialRecentchangesTest extends AbstractChangesListSpecialPageTestCase {
-       protected function setUp() {
-               parent::setUp();
-
-               # setup the CLSP object
-               $this->changesListSpecialPage = TestingAccessWrapper::newFromObject(
+       protected function getPage() {
+               return TestingAccessWrapper::newFromObject(
                        new SpecialRecentchanges
                );
        }
 
+       // Below providers should only be for features specific to
+       // RecentChanges.  Otherwise, it should go in ChangesListSpecialPageTest
+
        public function provideParseParameters() {
                return [
                        [ 'limit=123', [ 'limit' => '123' ] ],
@@ -32,4 +32,15 @@ class SpecialRecentchangesTest extends AbstractChangesListSpecialPageTestCase {
                        [ 'tagfilter=foo', [ 'tagfilter' => 'foo' ] ],
                ];
        }
+
+       public function validateOptionsProvider() {
+               return [
+                       [
+                               // hidebots=1 is default for Special:RecentChanges
+                               [ 'hideanons' => 1, 'hideliu' => 1 ],
+                               true,
+                               [ 'hideliu' => 1 ],
+                       ],
+               ];
+       }
 }
index 7f9f25f..b0490ec 100644 (file)
@@ -43,7 +43,6 @@ class SpecialWatchlistTest extends SpecialPageTestBase {
                                'watchlistreloadautomatically' => 0,
                        ]
                );
-
        }
 
        /**
index 27d3825..8071d6e 100644 (file)
                                hidefilter6: 0,
                                group3: ''
                        },
-                       'One filters in one "send_unselected_if_any" group returns the other parameters truthy.'
+                       'Two filters in one "send_unselected_if_any" group returns the other parameters truthy.'
                );
 
                // Select 3 filters
 
        } );
 
+       QUnit.test( 'getParametersFromFilters (custom object)', function ( assert ) {
+               var originalState,
+                       model = new mw.rcfilters.dm.FiltersViewModel(),
+                       definition = [ {
+                               name: 'group1',
+                               title: 'Group 1',
+                               type: 'send_unselected_if_any',
+                               filters: [
+                                       { name: 'hidefilter1', label: 'Hide filter 1', description: '' },
+                                       { name: 'hidefilter2', label: 'Hide filter 2', description: '' },
+                                       { name: 'hidefilter3', label: 'Hide filter 3', description: '' }
+                               ]
+                       }, {
+                               name: 'group2',
+                               title: 'Group 2',
+                               type: 'send_unselected_if_any',
+                               filters: [
+                                       { name: 'hidefilter4', label: 'Hide filter 4', description: '' },
+                                       { name: 'hidefilter5', label: 'Hide filter 5', description: '' },
+                                       { name: 'hidefilter6', label: 'Hide filter 6', description: '' }
+                               ]
+                       }, {
+                               name: 'group3',
+                               title: 'Group 3',
+                               type: 'string_options',
+                               separator: ',',
+                               filters: [
+                                       { name: 'filter7', label: 'Hide filter 7', description: '' },
+                                       { name: 'filter8', label: 'Hide filter 8', description: '' },
+                                       { name: 'filter9', label: 'Hide filter 9', description: '' }
+                               ]
+                       } ],
+                       cases = [
+                               {
+                                       // This is mocking the cases above, both
+                                       // - 'Two filters in one "send_unselected_if_any" group returns the other parameters truthy.'
+                                       // - 'Two filters selected in "string_option" group returns those filters in the value.'
+                                       input: {
+                                               group1__hidefilter1: true,
+                                               group1__hidefilter2: true,
+                                               group1__hidefilter3: false,
+                                               group2__hidefilter4: false,
+                                               group2__hidefilter5: false,
+                                               group2__hidefilter6: false,
+                                               group3__filter7: true,
+                                               group3__filter8: true,
+                                               group3__filter9: false
+                                       },
+                                       expected: {
+                                               // Group 1 (two selected, the others are true)
+                                               hidefilter1: 0,
+                                               hidefilter2: 0,
+                                               hidefilter3: 1,
+                                               // Group 2 (nothing is selected, all false)
+                                               hidefilter4: 0,
+                                               hidefilter5: 0,
+                                               hidefilter6: 0,
+                                               group3: 'filter7,filter8'
+                                       },
+                                       msg: 'Given an explicit (complete) filter state object, the result is the same as if the object given represented the model state.'
+                               },
+                               {
+                                       // This is mocking case above
+                                       // - 'One filters in one "send_unselected_if_any" group returns the other parameters truthy.'
+                                       input: {
+                                               group1__hidefilter1: 1
+                                       },
+                                       expected: {
+                                               // Group 1 (one selected, the others are true)
+                                               hidefilter1: 0,
+                                               hidefilter2: 1,
+                                               hidefilter3: 1,
+                                               // Group 2 (nothing is selected, all false)
+                                               hidefilter4: 0,
+                                               hidefilter5: 0,
+                                               hidefilter6: 0,
+                                               group3: ''
+                                       },
+                                       msg: 'Given an explicit (incomplete) filter state object, the result is the same as if the object give represented the model state.'
+                               }
+                       ];
+
+               model.initializeFilters( definition );
+               // Store original state
+               originalState = model.getSelectedState();
+
+               // Test each case
+               cases.forEach( function ( test ) {
+                       assert.deepEqual(
+                               model.getParametersFromFilters( test.input ),
+                               test.expected,
+                               test.msg
+                       );
+               } );
+
+               // After doing the above tests, make sure the actual state
+               // of the filter stayed the same
+               assert.deepEqual(
+                       model.getSelectedState(),
+                       originalState,
+                       'Running the method with external definition to parse does not actually change the state of the model'
+               );
+       } );
+
        QUnit.test( 'getFiltersFromParameters', function ( assert ) {
                var definition = [ {
                                name: 'group1',
index 7a0de81..06ea9bc 100644 (file)
                function isCssImportApplied() {
                        // Trigger reflow, repaint, redraw, whatever (cross-browser)
                        $element.css( 'height' );
+                       // eslint-disable-next-line no-unused-expressions
                        el.innerHTML;
                        el.className = el.className;
+                       // eslint-disable-next-line no-unused-expressions
                        document.documentElement.clientHeight;
 
                        return $element.css( prop ) === val;
index b2d0bdd..d64ada9 100644 (file)
@@ -5,6 +5,9 @@
                "mocha": true,
                "node": true
        },
+       "parserOptions": {
+               "ecmaVersion": 6
+       },
        "globals": {
                "browser": false
        }