Merge "Add new public method `addFields()` to HTMLForm"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 27 Jun 2019 14:36:57 +0000 (14:36 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 27 Jun 2019 14:36:57 +0000 (14:36 +0000)
76 files changed:
RELEASE-NOTES-1.34
autoload.php
includes/DefaultSettings.php
includes/Linker.php
includes/OutputPage.php
includes/Rest/Handler.php
includes/Rest/ResponseFactory.php
includes/Rest/Router.php
includes/api/ApiQueryLanguageinfo.php
includes/api/i18n/es.json
includes/filerepo/file/LocalFile.php
includes/installer/i18n/ia.json
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderClientHtml.php
includes/resourceloader/ResourceLoaderContext.php
includes/resourceloader/ResourceLoaderFileModule.php
includes/resourceloader/ResourceLoaderModule.php
includes/resourceloader/ResourceLoaderStartUpModule.php
includes/search/SearchDatabase.php
includes/search/SearchEngineFactory.php
includes/search/SearchMssql.php
includes/search/SearchMySQL.php
includes/search/SearchOracle.php
includes/search/SearchPostgres.php
includes/search/SearchSqlite.php
includes/session/SessionManager.php
includes/session/SessionManagerInterface.php
includes/specialpage/SpecialPageFactory.php
includes/specials/SpecialEmailUser.php
includes/specials/SpecialMute.php [new file with mode: 0644]
includes/specials/SpecialVersion.php
includes/specials/helpers/LoginHelper.php
languages/i18n/ar.json
languages/i18n/be-tarask.json
languages/i18n/da.json
languages/i18n/diq.json
languages/i18n/el.json
languages/i18n/en.json
languages/i18n/eo.json
languages/i18n/es.json
languages/i18n/exif/ml.json
languages/i18n/fa.json
languages/i18n/fy.json
languages/i18n/gcr.json
languages/i18n/ht.json
languages/i18n/hu.json
languages/i18n/ia.json
languages/i18n/it.json
languages/i18n/ko.json
languages/i18n/lb.json
languages/i18n/lrc.json
languages/i18n/mk.json
languages/i18n/nl.json
languages/i18n/nqo.json
languages/i18n/pl.json
languages/i18n/pt-br.json
languages/i18n/qqq.json
languages/i18n/roa-tara.json
languages/i18n/ru.json
languages/i18n/sh.json
languages/i18n/tr.json
languages/messages/MessagesEn.php
maintenance/update.php
resources/Resources.php
resources/src/mediawiki.special.mute.js [new file with mode: 0644]
resources/src/mediawiki.special.pageLanguage.js
resources/src/startup/mediawiki.js
tests/phpunit/includes/OutputPageTest.php
tests/phpunit/includes/Rest/ResponseFactoryTest.php
tests/phpunit/includes/deferred/SearchUpdateTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
tests/phpunit/includes/search/SearchEngineTest.php
tests/phpunit/includes/session/SessionManagerTest.php
tests/phpunit/includes/specials/SpecialMuteTest.php [new file with mode: 0644]
tests/phpunit/structure/ResourcesTest.php

index 0755609..549f7e8 100644 (file)
@@ -33,6 +33,9 @@ For notes on 1.33.x and older releases, see HISTORY.
   the code as the request identificator. Otherwise, the sent header will be
   ignored and the request ID will either be taken from Apache's mod_unique
   module or will be generated by Mediawiki itself (depending on the set-up).
+* $wgEnableSpecialMute (T218265) - This configuration controls whether
+  Special:Mute is available and whether to include a link to it on emails
+  originating from Special:Email.
 
 ==== Changed configuration ====
 * $wgUseCdn, $wgCdnServers, $wgCdnServersNoPurge, and $wgCdnMaxAge – These four
@@ -57,7 +60,8 @@ For notes on 1.33.x and older releases, see HISTORY.
   wikidiff2.moved_paragraph_detection_cutoff.
 
 === New user-facing features in 1.34 ===
-* …
+* Special:Mute has been added as a quick way for users to block unwanted emails
+  from other users originating from Special:EmailUser.
 
 === New developer features in 1.34 ===
 * Language::formatTimePeriod now supports the new 'avoidhours' option to output
index 698dbf2..0b93f49 100644 (file)
@@ -1388,6 +1388,7 @@ $wgAutoloadLocalClasses = [
        'SpecialLockdb' => __DIR__ . '/includes/specials/SpecialLockdb.php',
        'SpecialLog' => __DIR__ . '/includes/specials/SpecialLog.php',
        'SpecialMergeHistory' => __DIR__ . '/includes/specials/SpecialMergeHistory.php',
+       'SpecialMute' => __DIR__ . '/includes/specials/SpecialMute.php',
        'SpecialMyLanguage' => __DIR__ . '/includes/specials/SpecialMyLanguage.php',
        'SpecialMycontributions' => __DIR__ . '/includes/specials/redirects/SpecialMycontributions.php',
        'SpecialMypage' => __DIR__ . '/includes/specials/redirects/SpecialMypage.php',
index 2075432..10155f6 100644 (file)
@@ -1689,6 +1689,16 @@ $wgEnableEmail = true;
  */
 $wgEnableUserEmail = true;
 
+/**
+ * Set to true to enable the Special Mute page. This allows users
+ * to mute unwanted communications from other users, and is linked
+ * to from emails originating from Special:Email.
+ *
+ * @since 1.34
+ * @deprecated 1.34
+ */
+$wgEnableSpecialMute = false;
+
 /**
  * Set to true to enable user-to-user e-mail blacklist.
  *
index 1980154..01f695a 100644 (file)
@@ -688,8 +688,8 @@ class Linker {
                        $label = $title->getPrefixedText();
                }
                $encLabel = htmlspecialchars( $label );
-               $file = MediaWikiServices::getInstance()->getRepoGroup()->findFile( $title );
-               $currentExists = $time ? ( $file != false ) : false;
+               $currentExists = $time
+                       && MediaWikiServices::getInstance()->getRepoGroup()->findFile( $title ) !== false;
 
                if ( ( $wgUploadMissingFileUrl || $wgUploadNavigationUrl || $wgEnableUploads )
                        && !$currentExists
index b8cbff1..4ccb0d4 100644 (file)
@@ -2278,7 +2278,7 @@ class OutputPage extends ContextSource {
        }
 
        /**
-        * T23672: Add Accept-Language to Vary and Key headers if there's no 'variant' parameter in GET.
+        * T23672: Add Accept-Language to Vary header if there's no 'variant' parameter in GET.
         *
         * For example:
         *   /w/index.php?title=Main_page will vary based on Accept-Language; but
index 472e1cc..cee403f 100644 (file)
@@ -3,6 +3,9 @@
 namespace MediaWiki\Rest;
 
 abstract class Handler {
+       /** @var Router */
+       private $router;
+
        /** @var RequestInterface */
        private $request;
 
@@ -14,15 +17,25 @@ abstract class Handler {
 
        /**
         * Initialise with dependencies from the Router. This is called after construction.
+        * @internal
         */
-       public function init( RequestInterface $request, array $config,
+       public function init( Router $router, RequestInterface $request, array $config,
                ResponseFactory $responseFactory
        ) {
+               $this->router = $router;
                $this->request = $request;
                $this->config = $config;
                $this->responseFactory = $responseFactory;
        }
 
+       /**
+        * Get the Router. The return type declaration causes it to raise
+        * a fatal error if init() has not yet been called.
+        */
+       protected function getRouter(): Router {
+               return $this->router;
+       }
+
        /**
         * Get the current request. The return type declaration causes it to raise
         * a fatal error if init() has not yet been called.
index 7ccb612..d18cdb5 100644 (file)
@@ -78,7 +78,7 @@ class ResponseFactory {
         * the new URL in the future. 301 redirects tend to get cached and are hard to undo.
         * Client behavior for methods other than GET/HEAD is not well-defined and this type
         * of response should be avoided in such cases.
-        * @param string $target Redirect URL (can be relative)
+        * @param string $target Redirect target (an absolute URL)
         * @return Response
         */
        public function createPermanentRedirect( $target ) {
@@ -87,12 +87,28 @@ class ResponseFactory {
                return $response;
        }
 
+       /**
+        * Creates a temporary (302) redirect.
+        * HTTP 302 was underspecified and has been superseded by 303 (when the redirected request
+        * should be a GET, regardless of what the current request is) and 307 (when the method should
+        * not be changed), but might still be needed for HTTP 1.0 clients or to match legacy behavior.
+        * @param string $target Redirect target (an absolute URL)
+        * @return Response
+        * @see self::createTemporaryRedirect()
+        * @see self::createSeeOther()
+        */
+       public function createLegacyTemporaryRedirect( $target ) {
+               $response = $this->createRedirectBase( $target );
+               $response->setStatus( 302 );
+               return $response;
+       }
+
        /**
         * Creates a temporary (307) redirect.
         * This indicates that the operation the client was trying to perform can temporarily
         * be achieved by using a different URL. Clients will preserve the request method when
         * retrying the request with the new URL.
-        * @param string $target Redirect URL (can be relative)
+        * @param string $target Redirect target (an absolute URL)
         * @return Response
         */
        public function createTemporaryRedirect( $target ) {
@@ -106,7 +122,7 @@ class ResponseFactory {
         * This indicates that the target resource might be of interest to the client, without
         * necessarily implying that it is the same resource. The client will always use GET
         * (or HEAD) when following the redirection. Useful for GET-after-POST.
-        * @param string $target Redirect URL (can be relative)
+        * @param string $target Redirect target (an absolute URL)
         * @return Response
         */
        public function createSeeOther( $target ) {
index 39bee89..279c15e 100644 (file)
@@ -237,8 +237,9 @@ class Router {
                $spec = $match['userData'];
                $objectFactorySpec = array_intersect_key( $spec,
                        [ 'factory' => true, 'class' => true, 'args' => true ] );
+               /** @var $handler Handler (annotation for PHPStorm) */
                $handler = ObjectFactory::getObjectFromSpec( $objectFactorySpec );
-               $handler->init( $request, $spec, $this->responseFactory );
+               $handler->init( $this, $request, $spec, $this->responseFactory );
 
                try {
                        return $this->executeHandler( $handler );
index 72b59b0..1c2d490 100644 (file)
@@ -233,7 +233,7 @@ class ApiQueryLanguageinfo extends ApiQueryBase {
                return [
                        "$pathUrl"
                                => "apihelp-$pathMsg-example-simple",
-                       "$pathUrl&{$prefix}prop=autonym|name&lang=de"
+                       "$pathUrl&{$prefix}prop=autonym|name&uselang=de"
                                => "apihelp-$pathMsg-example-autonym-name-de",
                        "$pathUrl&{$prefix}prop=fallbacks|variants&{$prefix}code=oc"
                                => "apihelp-$pathMsg-example-fallbacks-variants-oc",
index af345d5..6473c35 100644 (file)
        "apihelp-query+languageinfo-summary": "Devolver información sobre los idiomas disponibles.",
        "apihelp-query+languageinfo-paramvalue-prop-code": "El código lingüístico (es específico de MediaWiki, pero existen coincidencias con otras normas.)",
        "apihelp-query+languageinfo-paramvalue-prop-dir": "La dirección de escritura del idioma (bien <code>ltr</code> o bien <code>rtl</code>).",
+       "apihelp-query+languageinfo-example-simple": "Obtener los códigos lingüísticos de todos los idiomas admitidos.",
        "apihelp-query+languageinfo-example-autonym-name-de": "Obtener los endónimos y los nombres alemanes de todos los idiomas compatibles.",
        "apihelp-query+languageinfo-example-fallbacks-variants-oc": "Obtener los idiomas de reserva y las variantes del occitano.",
        "apihelp-query+languageinfo-example-bcp47-dir": "Obtener el código lingüístico BCP-47 y la dirección de todos los idiomas compatibles.",
        "api-help-param-deprecated": "En desuso.",
        "api-help-param-required": "Este parámetro es obligatorio.",
        "api-help-datatypes-header": "Tipos de datos",
-       "api-help-datatypes": "Las entradas en MediaWiki deberían estar en UTF-8 según la norma NFC. MediaWiki puede tratar de convertir otros formatos, pero esto puede provocar errores en algunas operaciones (tales como las [[Special:ApiHelp/edit|ediciones]] con controles MD5).\n\nAlgunos tipos de parámetros en las solicitudes de API requieren de una explicación más detallada:\n;boolean\n:Los parámetros booleanos trabajo como cajas de verificación de HTML: si el parámetro está definido, independientemente de su valor, se considera verdadero. Para un valor falso, se debe omitir el parámetro  por completo.\n;marca de tiempo\n:Las marcas de tiempo se pueden definir en varios formatos. Se recomienda seguir la norma ISO 8601 de fecha y hora. Todas las horas están en UTC, ignorándose cualquier indicación de zona horaria.\n:* Fecha y hora en ISO 8601, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (los signos de puntuación y la <kbd>Z</kbd> son opcionales)\n:* Fecha y hora en ISO 8601 con fracciones de segundo (que se omiten), <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>.<var>00001</var>Z</kbd> (los guiones, los dos puntos y la <kbd>Z</kbd> son opcionales)\n:* Formato MediaWiki, <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* Formato genérico de número, <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (la zona horaria opcional, sea <kbd>GMT</kbd>, <kbd>+<var>##</var></kbd> o <kbd>-<var>##</var></kbd> se omite)\n:* Formato EXIF, <kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:*Formato RFC 2822 (la zona horaria es opcional), <kbd><var>lun</var>, <var>15</var> <var>ene</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Formato RFC 850 (la zona horaria es opcional), <kbd><var>lunes</var>, <var>15</var>-<var>ene</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Formato ctime de C, <kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* Número de segundos desde 1970-01-01T00:00:00Z en forma de número entero de entre 1 y 13 cifras (sin <kbd>0</kbd>)\n:* La cadena <kbd>now</kbd>\n\n;separador alternativo de valores múltiples\n:Los parámetros que toman valores múltiples se envían normalmente utilizando la barra vertical para separar los valores, p. ej., <kbd>param=valor1|valor2</kbd> o <kbd>param=valor1%7Cvalor2</kbd>. Si un valor tiene que contener el carácter de barra vertical, utiliza U+001F (separador de unidades) como separador ''y'' prefija el valor con, p. ej. <kbd>param=%1Fvalor1%1Fvalor2</kbd>.",
+       "api-help-datatypes": "El formato de entrada de MediaWiki debe ser UTF-8 normalizado por NFC. MediaWiki puede intentar convertir otros formatos, pero ello podría causar que algunas operaciones, como las [[Special:ApiHelp/edit|ediciones]] con comprobaciones MD5, fallen.\n\nAlgunos tipos de parámetros para las solicitudes de API requieren una explicación más a fondo:\n;boolean\n:Los parámetros booleanos funcionan como las casillas de verificación en HTML: si se especifica el parámetro, sin importar su valor, se considera verdadero. Para un valor falso, omítase el parámetro completamente.\n;timestamp\n:Los cronomarcadores pueden especificarse en varios formatos; para obtener detalles, consúltense [[mw:Special:MyLanguage/Timestamp|los formatos de entrada de la biblioteca Timestamp documentados en mediawiki.org]]. Se recomienda el formato ISO 8601: <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd>. Además, es posible utilizar la cadena <kbd>now</kbd> para especificar la fecha y la hora actuales.\n;separador alternativo para valores múltiples\n:Normalmente, los parámetros que reciben varios valores se envían con estos separados por una pleca; p. ej., <kbd>parámetro=valor1|valor2</kbd> o <kbd>parámetro=valor1%7Cvalor2</kbd>. Si un valor debe contener una pleca, utilícese U+001F (separador de unidades) como el separador ''y'' prefíjese el valor con U+001F; p. ej., <kbd>parámetro=%1Fvalor1%1Fvalor2</kbd>.",
        "api-help-param-type-limit": "Tipo: entero o <kbd>max</kbd>",
        "api-help-param-type-integer": "Tipo: {{PLURAL:$1|1=entero|2=lista de enteros}}",
        "api-help-param-type-boolean": "Tipo: booleano/lógico ([[Special:ApiHelp/main#main/datatypes|detalles]])",
index 1e1bde3..d7d6bf7 100644 (file)
@@ -1906,7 +1906,7 @@ class LocalFile extends File {
         * @return Status
         */
        function move( $target ) {
-               $localRepo = MediaWikiServices::getInstance()->getRepoGroup();
+               $localRepo = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo();
                if ( $this->getRepo()->getReadOnlyReason() !== false ) {
                        return $this->readOnlyFatalStatus();
                }
@@ -1923,8 +1923,8 @@ class LocalFile extends File {
                wfDebugLog( 'imagemove', "Finished moving {$this->name}" );
 
                // Purge the source and target files...
-               $oldTitleFile = $localRepo->findFile( $this->title );
-               $newTitleFile = $localRepo->findFile( $target );
+               $oldTitleFile = $localRepo->newFile( $this->title );
+               $newTitleFile = $localRepo->newFile( $target );
                // To avoid slow purges in the transaction, move them outside...
                DeferredUpdates::addUpdate(
                        new AutoCommitUpdate(
index 67f769f..2b85baa 100644 (file)
@@ -51,8 +51,8 @@
        "config-env-bad": "Le ambiente ha essite verificate.\nTu non pote installar MediaWiki.",
        "config-env-php": "PHP $1 es installate.",
        "config-env-hhvm": "HHVM $1 es installate.",
-       "config-unicode-using-intl": "Le [https://pecl.php.net/intl extension PECL intl] es usate pro le normalisation Unicode.",
-       "config-unicode-pure-php-warning": "'''Aviso''': Le [https://pecl.php.net/intl extension PECL intl] non es disponibile pro exequer le normalisation Unicode; le systema recurre al implementation lente in PHP pur.\nSi tu sito ha un alte volumine de traffico, tu deberea informar te un poco super le [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalisation Unicode].",
+       "config-unicode-using-intl": "Le [https://php.net/manual/en/book.intl.php extension PHP intl] es usate pro le normalisation Unicode.",
+       "config-unicode-pure-php-warning": "'''Aviso''': Le [https://php.net/manual/en/book.intl.php extension PHP intl] non es disponibile pro exequer le normalisation Unicode; le systema recurre al implementation lente in PHP pur.\nSi tu sito ha un alte volumine de traffico, tu deberea informar te super le [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalisation Unicode].",
        "config-unicode-update-warning": "'''Aviso''': Le version installate del bibliotheca inveloppante pro normalisation Unicode usa un version ancian del bibliotheca del [http://site.icu-project.org/ projecto ICU].\nTu deberea [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations actualisar lo] si le uso de Unicode importa a te.",
        "config-no-db": "Non poteva trovar un driver appropriate pro le base de datos! Es necessari installar un driver de base de datos pro PHP.\nLe sequente {{PLURAL:$2|typo|typos}} de base de datos es supportate: $1.\n\nSi tu compilava PHP tu mesme, reconfigura lo con un cliente de base de datos activate, per exemplo, usante <code>./configure --with-mysqli</code>.\nSi tu installava PHP ex un pacchetto Debian o Ubuntu, tu debe etiam installar, per exemplo, le modulo <code>php-mysql</code>.",
        "config-outdated-sqlite": "<strong>Attention</strong>: tu ha SQLite $2, que es inferior al minime version requirite, $1. SQLite essera indisponibile.",
index 387e344..ec376e3 100644 (file)
@@ -1047,9 +1047,6 @@ MESSAGE;
                        $states[$name] = 'missing';
                }
 
-               // Generate output
-               $isRaw = false;
-
                $filter = $context->getOnly() === 'styles' ? 'minify-css' : 'minify-js';
 
                foreach ( $modules as $name => $module ) {
@@ -1128,12 +1125,11 @@ MESSAGE;
                                $states[$name] = 'error';
                                unset( $modules[$name] );
                        }
-                       $isRaw |= $module->isRaw();
                }
 
                // Update module states
-               if ( $context->shouldIncludeScripts() && !$context->getRaw() && !$isRaw ) {
-                       if ( count( $modules ) && $context->getOnly() === 'scripts' ) {
+               if ( $context->shouldIncludeScripts() && !$context->getRaw() ) {
+                       if ( $modules && $context->getOnly() === 'scripts' ) {
                                // Set the state of modules loaded as only scripts to ready as
                                // they don't have an mw.loader.implement wrapper that sets the state
                                foreach ( $modules as $name => $module ) {
@@ -1142,7 +1138,7 @@ MESSAGE;
                        }
 
                        // Set the state of modules we didn't respond to with mw.loader.implement
-                       if ( count( $states ) ) {
+                       if ( $states ) {
                                $stateScript = self::makeLoaderStateScript( $states );
                                if ( !$context->getDebug() ) {
                                        $stateScript = self::filter( 'minify-js', $stateScript );
index 7f2f85f..e324d04 100644 (file)
@@ -348,7 +348,7 @@ JAVASCRIPT;
        private static function makeContext( ResourceLoaderContext $mainContext, $group, $type,
                array $extraQuery = []
        ) {
-               // Create new ResourceLoaderContext so that $extraQuery may trigger isRaw().
+               // Create new ResourceLoaderContext so that $extraQuery is supported (eg. for 'sync=1').
                $req = new FauxRequest( array_merge( $mainContext->getRequest()->getValues(), $extraQuery ) );
                // Set 'only' if not combined
                $req->setVal( 'only', $type === ResourceLoaderModule::TYPE_COMBINED ? null : $type );
@@ -434,12 +434,6 @@ JAVASCRIPT;
                                                        );
                                                }
                                        } else {
-                                               // See if we have one or more raw modules
-                                               $isRaw = false;
-                                               foreach ( $moduleSet as $key => $module ) {
-                                                       $isRaw |= $module->isRaw();
-                                               }
-
                                                // Special handling for the user group; because users might change their stuff
                                                // on-wiki like user pages, or user preferences; we need to find the highest
                                                // timestamp of these user-changeable modules so we can ensure cache misses on change
@@ -455,9 +449,15 @@ JAVASCRIPT;
                                                // Decide whether to use 'style' or 'script' element
                                                if ( $only === ResourceLoaderModule::TYPE_STYLES ) {
                                                        $chunk = Html::linkedStyle( $url );
-                                               } elseif ( $context->getRaw() || $isRaw ) {
+                                               } elseif ( $context->getRaw() ) {
+                                                       // This request is asking for the module to be delivered standalone,
+                                                       // (aka "raw") without communicating to any mw.loader client.
+                                                       // Use cases:
+                                                       // - startup (naturally because this is what will define mw.loader)
+                                                       // - html5shiv (loads synchronously in old IE before the async startup module arrives)
+                                                       // - QUnit (needed in SpecialJavaScriptTest before async startup)
                                                        $chunk = Html::element( 'script', [
-                                                               // In SpecialJavaScriptTest, QUnit must load synchronous
+                                                               // The 'sync' option is only supported in combination with 'raw'.
                                                                'async' => !isset( $extraQuery['sync'] ),
                                                                'src' => $url
                                                        ] );
index 95a81e6..1f06ede 100644 (file)
@@ -410,4 +410,24 @@ class ResourceLoaderContext implements MessageLocalizer {
                }
                return $this->hash;
        }
+
+       /**
+        * Get the request base parameters, omitting any defaults.
+        *
+        * @internal For internal use by ResourceLoaderStartUpModule only
+        * @return array
+        */
+       public function getReqBase() {
+               $reqBase = [];
+               if ( $this->getLanguage() !== self::DEFAULT_LANG ) {
+                       $reqBase['lang'] = $this->getLanguage();
+               }
+               if ( $this->getSkin() !== self::DEFAULT_SKIN ) {
+                       $reqBase['skin'] = $this->getSkin();
+               }
+               if ( $this->getDebug() ) {
+                       $reqBase['debug'] = 'true';
+               }
+               return $reqBase;
+       }
 }
index 7093ab1..017b399 100644 (file)
@@ -140,9 +140,6 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
        /** @var bool Link to raw files in debug mode */
        protected $debugRaw = true;
 
-       /** @var bool Whether mw.loader.state() call should be omitted */
-       protected $raw = false;
-
        protected $targets = [ 'desktop' ];
 
        /** @var bool Whether CSSJanus flipping should be skipped for this module */
@@ -305,7 +302,6 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
                                        break;
                                // Single booleans
                                case 'debugRaw':
-                               case 'raw':
                                case 'noflip':
                                        $this->{$member} = (bool)$option;
                                        break;
@@ -513,13 +509,6 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
                return $contents;
        }
 
-       /**
-        * @return bool
-        */
-       public function isRaw() {
-               return $this->raw;
-       }
-
        /**
         * Disable module content versioning.
         *
@@ -620,7 +609,6 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
                        'templates',
                        'skipFunction',
                        'debugRaw',
-                       'raw',
                ] as $member ) {
                        $options[$member] = $this->{$member};
                }
@@ -1004,7 +992,6 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
                        || $this->dependencies
                        || $this->messages
                        || $this->skipFunction
-                       || $this->raw
                );
                return $canBeStylesOnly ? self::LOAD_STYLES : self::LOAD_GENERAL;
        }
index a7fee85..c376fa7 100644 (file)
@@ -335,17 +335,6 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
                return 'local';
        }
 
-       /**
-        * Whether this module's JS expects to work without the client-side ResourceLoader module.
-        * Returning true from this function will prevent mw.loader.state() call from being
-        * appended to the bottom of the script.
-        *
-        * @return bool
-        */
-       public function isRaw() {
-               return false;
-       }
-
        /**
         * Get a list of modules this module depends on.
         *
index b90b618..2959b22 100644 (file)
@@ -254,10 +254,11 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                                continue;
                        }
 
-                       if ( $module->isRaw() ) {
-                               // Don't register "raw" modules (like 'startup') client-side because depending on them
-                               // is illegal anyway and would only lead to them being loaded a second time,
-                               // causing any state to be lost.
+                       if ( $module instanceof ResourceLoaderStartUpModule ) {
+                               // Don't register 'startup' to the client because loading it lazily or depending
+                               // on it doesn't make sense, because the startup module *is* the client.
+                               // Registering would be a waste of bandwidth and memory and risks somehow causing
+                               // it to load a second time.
 
                                // ATTENTION: Because of the line below, this is not going to cause infinite recursion.
                                // Think carefully before making changes to this code!
@@ -341,13 +342,6 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                return $out;
        }
 
-       /**
-        * @return bool
-        */
-       public function isRaw() {
-               return true;
-       }
-
        /**
         * @private For internal use by SpecialJavaScriptTest
         * @since 1.32
@@ -401,6 +395,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
 
                // Perform replacements for mediawiki.js
                $mwLoaderPairs = [
+                       '$VARS.reqBase' => ResourceLoader::encodeJsonForScript( $context->getReqBase() ),
                        '$VARS.baseModules' => ResourceLoader::encodeJsonForScript( $this->getBaseModules() ),
                        '$VARS.maxQueryLength' => ResourceLoader::encodeJsonForScript(
                                $conf->get( 'ResourceLoaderMaxQueryLength' )
index 230cded..6da8f98 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\ILoadBalancer;
 
 /**
  * Base search engine base class for database-backed searches
@@ -29,16 +30,18 @@ use Wikimedia\Rdbms\IDatabase;
  * @since 1.23
  */
 abstract class SearchDatabase extends SearchEngine {
-       /**
-        * @var IDatabase Replica database from which to read results
-        */
+       /** @var ILoadBalancer */
+       protected $lb;
+       /** @var IDatabase (backwards compatibility) */
        protected $db;
 
        /**
-        * @param IDatabase|null $db The database to search from
+        * @param ILoadBalancer $lb The load balancer for the DB cluster to search on
         */
-       public function __construct( IDatabase $db = null ) {
-               $this->db = $db ?: wfGetDB( DB_REPLICA );
+       public function __construct( ILoadBalancer $lb ) {
+               $this->lb = $lb;
+               // @TODO: remove this deprecated field in 1.35
+               $this->db = $lb->getLazyConnectionRef( DB_REPLICA ); // b/c
        }
 
        /**
index ecb6f43..6a69cd4 100644 (file)
@@ -1,6 +1,8 @@
 <?php
 
 use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\ILoadBalancer;
+use MediaWiki\MediaWikiServices;
 
 /**
  * Factory class for SearchEngine.
@@ -23,31 +25,36 @@ class SearchEngineFactory {
         * @return SearchEngine
         */
        public function create( $type = null ) {
-               $dbr = null;
+               $configuredClass = $this->config->getSearchType();
+               $alternativesClasses = $this->config->getSearchTypes();
 
-               $configType = $this->config->getSearchType();
-               $alternatives = $this->config->getSearchTypes();
-
-               if ( $type && in_array( $type, $alternatives ) ) {
+               $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+               if ( $type !== null && in_array( $type, $alternativesClasses ) ) {
                        $class = $type;
-               } elseif ( $configType !== null ) {
-                       $class = $configType;
+               } elseif ( $configuredClass !== null ) {
+                       $class = $configuredClass;
                } else {
-                       $dbr = wfGetDB( DB_REPLICA );
-                       $class = self::getSearchEngineClass( $dbr );
+                       $class = self::getSearchEngineClass( $lb );
                }
 
-               $search = new $class( $dbr );
-               return $search;
+               if ( is_subclass_of( $class, SearchDatabase::class ) ) {
+                       return new $class( $lb );
+               } else {
+                       return new $class();
+               }
        }
 
        /**
-        * @param IDatabase $db
+        * @param IDatabase|ILoadBalancer $dbOrLb
         * @return string SearchEngine subclass name
         * @since 1.28
         */
-       public static function getSearchEngineClass( IDatabase $db ) {
-               switch ( $db->getType() ) {
+       public static function getSearchEngineClass( $dbOrLb ) {
+               $type = ( $dbOrLb instanceof IDatabase )
+                       ? $dbOrLb->getType()
+                       : $dbOrLb->getServerType( $dbOrLb->getWriterIndex() );
+
+               switch ( $type ) {
                        case 'sqlite':
                                return SearchSqlite::class;
                        case 'mysql':
index 0e85f9d..6a23bb3 100644 (file)
@@ -36,7 +36,9 @@ class SearchMssql extends SearchDatabase {
         * @return SqlSearchResultSet
         */
        protected function doSearchTextInDB( $term ) {
-               $resultSet = $this->db->query( $this->getQuery( $this->filter( $term ), true ) );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $resultSet = $dbr->query( $this->getQuery( $this->filter( $term ), true ) );
+
                return new SqlSearchResultSet( $resultSet, $this->searchTerms );
        }
 
@@ -47,7 +49,9 @@ class SearchMssql extends SearchDatabase {
         * @return SqlSearchResultSet
         */
        protected function doSearchTitleInDB( $term ) {
-               $resultSet = $this->db->query( $this->getQuery( $this->filter( $term ), false ) );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $resultSet = $dbr->query( $this->getQuery( $this->filter( $term ), false ) );
+
                return new SqlSearchResultSet( $resultSet, $this->searchTerms );
        }
 
@@ -72,7 +76,9 @@ class SearchMssql extends SearchDatabase {
         * @return string
         */
        private function queryLimit( $sql ) {
-               return $this->db->limitResult( $sql, $this->limit, $this->offset );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+
+               return $dbr->limitResult( $sql, $this->limit, $this->offset );
        }
 
        /**
@@ -120,8 +126,9 @@ class SearchMssql extends SearchDatabase {
         */
        private function queryMain( $filteredTerm, $fulltext ) {
                $match = $this->parseQuery( $filteredTerm, $fulltext );
-               $page = $this->db->tableName( 'page' );
-               $searchindex = $this->db->tableName( 'searchindex' );
+               $dbr = $this->lb->getMaintenanceConnectionRef( DB_REPLICA );
+               $page = $dbr->tableName( 'page' );
+               $searchindex = $dbr->tableName( 'searchindex' );
 
                return 'SELECT page_id, page_namespace, page_title, ftindex.[RANK]' .
                        "FROM $page,FREETEXTTABLE($searchindex , $match, LANGUAGE 'English') as ftindex " .
@@ -159,8 +166,10 @@ class SearchMssql extends SearchDatabase {
                        }
                }
 
-               $searchon = $this->db->addQuotes( implode( ',', $q ) );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $searchon = $dbr->addQuotes( implode( ',', $q ) );
                $field = $this->getIndexField( $fulltext );
+
                return "$field, $searchon";
        }
 
@@ -179,13 +188,14 @@ class SearchMssql extends SearchDatabase {
                // to properly decode the stream as UTF-8.  SQL doesn't support UTF8 as a data type
                // but the indexer will correctly handle it by this method.  Since all we are doing
                // is passing this data to the indexer and never retrieving it via PHP, this will save space
-               $table = $this->db->tableName( 'searchindex' );
+               $dbr = $this->lb->getMaintenanceConnectionRef( DB_MASTER );
+               $table = $dbr->tableName( 'searchindex' );
                $utf8bom = '0xEFBBBF';
                $si_title = $utf8bom . bin2hex( $title );
                $si_text = $utf8bom . bin2hex( $text );
                $sql = "DELETE FROM $table WHERE si_page = $id;";
                $sql .= "INSERT INTO $table (si_page, si_title, si_text) VALUES ($id, $si_title, $si_text)";
-               return $this->db->query( $sql, 'SearchMssql::update' );
+               return $dbr->query( $sql, 'SearchMssql::update' );
        }
 
        /**
@@ -197,13 +207,14 @@ class SearchMssql extends SearchDatabase {
         * @return bool|IResultWrapper
         */
        function updateTitle( $id, $title ) {
-               $table = $this->db->tableName( 'searchindex' );
+               $dbr = $this->lb->getMaintenanceConnectionRef( DB_MASTER );
+               $table = $dbr->tableName( 'searchindex' );
 
                // see update for why we are using the utf8bom
                $utf8bom = '0xEFBBBF';
                $si_title = $utf8bom . bin2hex( $title );
                $sql = "DELETE FROM $table WHERE si_page = $id;";
                $sql .= "INSERT INTO $table (si_page, si_title, si_text) VALUES ($id, $si_title, 0x00)";
-               return $this->db->query( $sql, 'SearchMssql::updateTitle' );
+               return $dbr->query( $sql, 'SearchMssql::updateTitle' );
        }
 }
index cae3426..4a6b93b 100644 (file)
@@ -124,7 +124,8 @@ class SearchMySQL extends SearchDatabase {
                        wfDebug( __METHOD__ . ": Can't understand search query '{$filteredText}'\n" );
                }
 
-               $searchon = $this->db->addQuotes( $searchon );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $searchon = $dbr->addQuotes( $searchon );
                $field = $this->getIndexField( $fulltext );
                return [
                        " MATCH($field) AGAINST($searchon IN BOOLEAN MODE) ",
@@ -186,14 +187,15 @@ class SearchMySQL extends SearchDatabase {
 
                $filteredTerm = $this->filter( $term );
                $query = $this->getQuery( $filteredTerm, $fulltext );
-               $resultSet = $this->db->select(
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $resultSet = $dbr->select(
                        $query['tables'], $query['fields'], $query['conds'],
                        __METHOD__, $query['options'], $query['joins']
                );
 
                $total = null;
                $query = $this->getCountQuery( $filteredTerm, $fulltext );
-               $totalResult = $this->db->select(
+               $totalResult = $dbr->select(
                        $query['tables'], $query['fields'], $query['conds'],
                        __METHOD__, $query['options'], $query['joins']
                );
@@ -224,7 +226,8 @@ class SearchMySQL extends SearchDatabase {
        protected function queryFeatures( &$query ) {
                foreach ( $this->features as $feature => $value ) {
                        if ( $feature === 'title-suffix-filter' && $value ) {
-                               $query['conds'][] = 'page_title' . $this->db->buildLike( $this->db->anyString(), $value );
+                               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+                               $query['conds'][] = 'page_title' . $dbr->buildLike( $dbr->anyString(), $value );
                        }
                }
        }
@@ -339,7 +342,7 @@ class SearchMySQL extends SearchDatabase {
         * @param string $text
         */
        function update( $id, $title, $text ) {
-               $dbw = wfGetDB( DB_MASTER );
+               $dbw = $this->lb->getConnectionRef( DB_MASTER );
                $dbw->replace( 'searchindex',
                        [ 'si_page' ],
                        [
@@ -357,13 +360,12 @@ class SearchMySQL extends SearchDatabase {
         * @param string $title
         */
        function updateTitle( $id, $title ) {
-               $dbw = wfGetDB( DB_MASTER );
-
+               $dbw = $this->lb->getConnectionRef( DB_MASTER );
                $dbw->update( 'searchindex',
                        [ 'si_title' => $this->normalizeText( $title ) ],
                        [ 'si_page' => $id ],
-                       __METHOD__,
-                       [ $dbw->lowPriorityOption() ] );
+                       __METHOD__
+               );
        }
 
        /**
@@ -374,8 +376,7 @@ class SearchMySQL extends SearchDatabase {
         * @param string $title Title of page that was deleted
         */
        function delete( $id, $title ) {
-               $dbw = wfGetDB( DB_MASTER );
-
+               $dbw = $this->lb->getConnectionRef( DB_MASTER );
                $dbw->delete( 'searchindex', [ 'si_page' => $id ], __METHOD__ );
        }
 
@@ -441,7 +442,7 @@ class SearchMySQL extends SearchDatabase {
                if ( is_null( self::$mMinSearchLength ) ) {
                        $sql = "SHOW GLOBAL VARIABLES LIKE 'ft\\_min\\_word\\_len'";
 
-                       $dbr = wfGetDB( DB_REPLICA );
+                       $dbr = $this->lb->getConnectionRef( DB_REPLICA );
                        $result = $dbr->query( $sql, __METHOD__ );
                        $row = $result->fetchObject();
                        $result->free();
index 6b2b403..a5d351b 100644 (file)
@@ -71,7 +71,8 @@ class SearchOracle extends SearchDatabase {
                        return new SqlSearchResultSet( false, '' );
                }
 
-               $resultSet = $this->db->query( $this->getQuery( $this->filter( $term ), true ) );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $resultSet = $dbr->query( $this->getQuery( $this->filter( $term ), true ) );
                return new SqlSearchResultSet( $resultSet, $this->searchTerms );
        }
 
@@ -86,7 +87,8 @@ class SearchOracle extends SearchDatabase {
                        return new SqlSearchResultSet( false, '' );
                }
 
-               $resultSet = $this->db->query( $this->getQuery( $this->filter( $term ), false ) );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $resultSet = $dbr->query( $this->getQuery( $this->filter( $term ), false ) );
                return new SqlSearchResultSet( $resultSet, $this->searchTerms );
        }
 
@@ -101,7 +103,8 @@ class SearchOracle extends SearchDatabase {
                if ( $this->namespaces === [] ) {
                        $namespaces = '0';
                } else {
-                       $namespaces = $this->db->makeList( $this->namespaces );
+                       $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+                       $namespaces = $dbr->makeList( $this->namespaces );
                }
                return 'AND page_namespace IN (' . $namespaces . ')';
        }
@@ -114,7 +117,9 @@ class SearchOracle extends SearchDatabase {
         * @return string
         */
        private function queryLimit( $sql ) {
-               return $this->db->limitResult( $sql, $this->limit, $this->offset );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+
+               return $dbr->limitResult( $sql, $this->limit, $this->offset );
        }
 
        /**
@@ -160,8 +165,11 @@ class SearchOracle extends SearchDatabase {
         */
        function queryMain( $filteredTerm, $fulltext ) {
                $match = $this->parseQuery( $filteredTerm, $fulltext );
-               $page = $this->db->tableName( 'page' );
-               $searchindex = $this->db->tableName( 'searchindex' );
+
+               $dbr = $this->lb->getMaintenanceConnectionRef( DB_REPLICA );
+               $page = $dbr->tableName( 'page' );
+               $searchindex = $dbr->tableName( 'searchindex' );
+
                return 'SELECT page_id, page_namespace, page_title ' .
                        "FROM $page,$searchindex " .
                        'WHERE page_id=si_page AND ' . $match;
@@ -208,8 +216,10 @@ class SearchOracle extends SearchDatabase {
                        }
                }
 
-               $searchon = $this->db->addQuotes( ltrim( $searchon, ' &' ) );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $searchon = $dbr->addQuotes( ltrim( $searchon, ' &' ) );
                $field = $this->getIndexField( $fulltext );
+
                return " CONTAINS($field, $searchon, 1) > 0 ";
        }
 
@@ -230,7 +240,7 @@ class SearchOracle extends SearchDatabase {
         * @param string $text
         */
        function update( $id, $title, $text ) {
-               $dbw = wfGetDB( DB_MASTER );
+               $dbw = $this->lb->getConnection( DB_MASTER );
                $dbw->replace( 'searchindex',
                        [ 'si_page' ],
                        [
@@ -258,8 +268,7 @@ class SearchOracle extends SearchDatabase {
         * @param string $title
         */
        function updateTitle( $id, $title ) {
-               $dbw = wfGetDB( DB_MASTER );
-
+               $dbw = $this->lb->getConnectionRef( DB_MASTER );
                $dbw->update( 'searchindex',
                        [ 'si_title' => $title ],
                        [ 'si_page' => $id ],
index 74ee552..63634cb 100644 (file)
@@ -42,7 +42,8 @@ class SearchPostgres extends SearchDatabase {
        protected function doSearchTitleInDB( $term ) {
                $q = $this->searchQuery( $term, 'titlevector', 'page_title' );
                $olderror = error_reporting( E_ERROR );
-               $resultSet = $this->db->query( $q, 'SearchPostgres', true );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $resultSet = $dbr->query( $q, 'SearchPostgres', true );
                error_reporting( $olderror );
                return new SqlSearchResultSet( $resultSet, $this->searchTerms );
        }
@@ -50,7 +51,8 @@ class SearchPostgres extends SearchDatabase {
        protected function doSearchTextInDB( $term ) {
                $q = $this->searchQuery( $term, 'textvector', 'old_text' );
                $olderror = error_reporting( E_ERROR );
-               $resultSet = $this->db->query( $q, 'SearchPostgres', true );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $resultSet = $dbr->query( $q, 'SearchPostgres', true );
                error_reporting( $olderror );
                return new SqlSearchResultSet( $resultSet, $this->searchTerms );
        }
@@ -111,7 +113,8 @@ class SearchPostgres extends SearchDatabase {
                $searchstring = preg_replace( '/^[\'"](.*)[\'"]$/', "$1", $searchstring );
 
                # # Quote the whole thing
-               $searchstring = $this->db->addQuotes( $searchstring );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $searchstring = $dbr->addQuotes( $searchstring );
 
                wfDebug( "parseQuery returned: $searchstring \n" );
 
@@ -131,7 +134,8 @@ class SearchPostgres extends SearchDatabase {
 
                # # We need a separate query here so gin does not complain about empty searches
                $sql = "SELECT to_tsquery($searchstring)";
-               $res = $this->db->query( $sql );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $res = $dbr->query( $sql );
                if ( !$res ) {
                        # # TODO: Better output (example to catch: one 'two)
                        die( "Sorry, that was not a valid search string. Please go back and try again" );
@@ -172,14 +176,14 @@ class SearchPostgres extends SearchDatabase {
                        if ( count( $this->namespaces ) < 1 ) {
                                $query .= ' AND page_namespace = 0';
                        } else {
-                               $namespaces = $this->db->makeList( $this->namespaces );
+                               $namespaces = $dbr->makeList( $this->namespaces );
                                $query .= " AND page_namespace IN ($namespaces)";
                        }
                }
 
                $query .= " ORDER BY score DESC, page_id DESC";
 
-               $query .= $this->db->limitResult( '', $this->limit, $this->offset );
+               $query .= $dbr->limitResult( '', $this->limit, $this->offset );
 
                wfDebug( "searchQuery returned: $query \n" );
 
@@ -201,12 +205,14 @@ class SearchPostgres extends SearchDatabase {
                        " AND s.slot_role_id = " . $slotRoleStore->getId( SlotRecord::MAIN ) . " " .
                        " AND c.content_id = s.slot_content_id " .
                        " ORDER BY old_rev_text_id DESC OFFSET 1)";
-               $this->db->query( $sql );
+
+               $dbw = $this->lb->getConnectionRef( DB_MASTER );
+               $dbw->query( $sql );
+
                return true;
        }
 
        function updateTitle( $id, $title ) {
                return true;
        }
-
 }
index c304797..3646b27 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\DatabaseSqlite;
 
 /**
  * Search engine hook for SQLite
@@ -33,7 +34,10 @@ class SearchSqlite extends SearchDatabase {
         * @return bool
         */
        function fulltextSearchSupported() {
-               return $this->db->checkForEnabledSearch();
+               /** @var DatabaseSqlite $dbr */
+               $dbr = $this->lb->getConnection( DB_REPLICA );
+
+               return $dbr->checkForEnabledSearch();
        }
 
        /**
@@ -120,8 +124,10 @@ class SearchSqlite extends SearchDatabase {
                        wfDebug( __METHOD__ . ": Can't understand search query '{$filteredText}'\n" );
                }
 
-               $searchon = $this->db->addQuotes( $searchon );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $searchon = $dbr->addQuotes( $searchon );
                $field = $this->getIndexField( $fulltext );
+
                return " $field MATCH $searchon ";
        }
 
@@ -178,10 +184,11 @@ class SearchSqlite extends SearchDatabase {
 
                $filteredTerm =
                        $this->filter( MediaWikiServices::getInstance()->getContentLanguage()->lc( $term ) );
-               $resultSet = $this->db->query( $this->getQuery( $filteredTerm, $fulltext ) );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+               $resultSet = $dbr->query( $this->getQuery( $filteredTerm, $fulltext ) );
 
                $total = null;
-               $totalResult = $this->db->query( $this->getCountQuery( $filteredTerm, $fulltext ) );
+               $totalResult = $dbr->query( $this->getCountQuery( $filteredTerm, $fulltext ) );
                $row = $totalResult->fetchObject();
                if ( $row ) {
                        $total = intval( $row->c );
@@ -202,7 +209,8 @@ class SearchSqlite extends SearchDatabase {
                if ( $this->namespaces === [] ) {
                        $namespaces = '0';
                } else {
-                       $namespaces = $this->db->makeList( $this->namespaces );
+                       $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+                       $namespaces = $dbr->makeList( $this->namespaces );
                }
                return 'AND page_namespace IN (' . $namespaces . ')';
        }
@@ -213,7 +221,9 @@ class SearchSqlite extends SearchDatabase {
         * @return string
         */
        private function limitResult( $sql ) {
-               return $this->db->limitResult( $sql, $this->limit, $this->offset );
+               $dbr = $this->lb->getConnectionRef( DB_REPLICA );
+
+               return $dbr->limitResult( $sql, $this->limit, $this->offset );
        }
 
        /**
@@ -248,8 +258,9 @@ class SearchSqlite extends SearchDatabase {
         */
        private function queryMain( $filteredTerm, $fulltext ) {
                $match = $this->parseQuery( $filteredTerm, $fulltext );
-               $page = $this->db->tableName( 'page' );
-               $searchindex = $this->db->tableName( 'searchindex' );
+               $dbr = $this->lb->getMaintenanceConnectionRef( DB_REPLICA );
+               $page = $dbr->tableName( 'page' );
+               $searchindex = $dbr->tableName( 'searchindex' );
                return "SELECT $searchindex.rowid, page_namespace, page_title " .
                        "FROM $page,$searchindex " .
                        "WHERE page_id=$searchindex.rowid AND $match";
@@ -257,8 +268,9 @@ class SearchSqlite extends SearchDatabase {
 
        private function getCountQuery( $filteredTerm, $fulltext ) {
                $match = $this->parseQuery( $filteredTerm, $fulltext );
-               $page = $this->db->tableName( 'page' );
-               $searchindex = $this->db->tableName( 'searchindex' );
+               $dbr = $this->lb->getMaintenanceConnectionRef( DB_REPLICA );
+               $page = $dbr->tableName( 'page' );
+               $searchindex = $dbr->tableName( 'searchindex' );
                return "SELECT COUNT(*) AS c " .
                        "FROM $page,$searchindex " .
                        "WHERE page_id=$searchindex.rowid AND $match " .
@@ -279,10 +291,8 @@ class SearchSqlite extends SearchDatabase {
                }
                // @todo find a method to do it in a single request,
                // couldn't do it so far due to typelessness of FTS3 tables.
-               $dbw = wfGetDB( DB_MASTER );
-
+               $dbw = $this->lb->getConnectionRef( DB_MASTER );
                $dbw->delete( 'searchindex', [ 'rowid' => $id ], __METHOD__ );
-
                $dbw->insert( 'searchindex',
                        [
                                'rowid' => $id,
@@ -302,8 +312,8 @@ class SearchSqlite extends SearchDatabase {
                if ( !$this->fulltextSearchSupported() ) {
                        return;
                }
-               $dbw = wfGetDB( DB_MASTER );
 
+               $dbw = $this->lb->getConnectionRef( DB_MASTER );
                $dbw->update( 'searchindex',
                        [ 'si_title' => $title ],
                        [ 'rowid' => $id ],
index 98c0499..3810565 100644 (file)
@@ -329,12 +329,9 @@ final class SessionManager implements SessionManagerInterface {
                        $headers = [];
                        foreach ( $this->getProviders() as $provider ) {
                                foreach ( $provider->getVaryHeaders() as $header => $options ) {
-                                       if ( !isset( $headers[$header] ) ) {
-                                               $headers[$header] = [];
-                                       }
-                                       if ( is_array( $options ) ) {
-                                               $headers[$header] = array_unique( array_merge( $headers[$header], $options ) );
-                                       }
+                                       # Note that the $options value returned has been deprecated
+                                       # and is ignored.
+                                       $headers[$header] = null;
                                }
                        }
                        $this->varyHeaders = $headers;
index c6990fe..7c05cfc 100644 (file)
@@ -96,6 +96,9 @@ interface SessionManagerInterface extends LoggerAwareInterface {
         * }
         * @endcode
         *
+        * Note that the $options argument to OutputPage::addVaryHeader() has
+        * been deprecated and should always be null.
+        *
         * @return array
         */
        public function getVaryHeaders();
index 9a793c3..40172ab 100644 (file)
@@ -232,6 +232,7 @@ class SpecialPageFactory {
                'EmailAuthentication',
                'EnableEmail',
                'EnableJavaScriptTest',
+               'EnableSpecialMute',
                'PageLanguageUseDB',
                'SpecialPages',
        ];
@@ -282,9 +283,14 @@ class SpecialPageFactory {
                                $this->list['JavaScriptTest'] = \SpecialJavaScriptTest::class;
                        }
 
+                       if ( $this->options->get( 'EnableSpecialMute' ) ) {
+                               $this->list['Mute'] = \SpecialMute::class;
+                       }
+
                        if ( $this->options->get( 'PageLanguageUseDB' ) ) {
                                $this->list['PageLanguage'] = \SpecialPageLanguage::class;
                        }
+
                        if ( $this->options->get( 'ContentHandlerUseDB' ) ) {
                                $this->list['ChangeContentModel'] = \SpecialChangeContentModel::class;
                        }
index e1606b2..122fa9b 100644 (file)
@@ -375,6 +375,15 @@ class SpecialEmailUser extends UnlistedSpecialPage {
                $text .= $context->msg( 'emailuserfooter',
                        $from->name, $to->name )->inContentLanguage()->text();
 
+               if ( $config->get( 'EnableSpecialMute' ) ) {
+                       $specialMutePage = SpecialPage::getTitleFor( 'Mute', $context->getUser()->getName() );
+                       $text .= "\n" . $context->msg(
+                               'specialmute-email-footer',
+                               $specialMutePage->getCanonicalURL(),
+                               $context->getUser()->getName()
+                       );
+               }
+
                // Check and increment the rate limits
                if ( $context->getUser()->pingLimiter( 'emailuser' ) ) {
                        throw new ThrottledError();
diff --git a/includes/specials/SpecialMute.php b/includes/specials/SpecialMute.php
new file mode 100644 (file)
index 0000000..4f34785
--- /dev/null
@@ -0,0 +1,213 @@
+<?php
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+use MediaWiki\Preferences\MultiUsernameFilter;
+
+/**
+ * A special page that allows users to modify their notification
+ * preferences
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialMute extends FormSpecialPage {
+
+       /** @var User */
+       private $target;
+
+       /** @var int */
+       private $targetCentralId;
+
+       /** @var bool */
+       private $enableUserEmailBlacklist;
+
+       /** @var bool */
+       private $enableUserEmail;
+
+       /** @var CentralIdLookup */
+       private $centralIdLookup;
+
+       public function __construct() {
+               // TODO: inject all these dependencies once T222388 is resolved
+               $config = RequestContext::getMain()->getConfig();
+               $this->enableUserEmailBlacklist = $config->get( 'EnableUserEmailBlacklist' );
+               $this->enableUserEmail = $config->get( 'EnableUserEmail' );
+
+               $this->centralIdLookup = CentralIdLookup::factory();
+
+               parent::__construct( 'Mute', '', false );
+       }
+
+       /**
+        * Entry point for special pages
+        *
+        * @param string $par
+        */
+       public function execute( $par ) {
+               $this->requireLogin( 'specialmute-login-required' );
+               $this->loadTarget( $par );
+
+               parent::execute( $par );
+
+               $out = $this->getOutput();
+               $out->addModules( 'mediawiki.special.pageLanguage' );
+       }
+
+       /**
+        * @inheritDoc
+        */
+       public function requiresUnblock() {
+               return false;
+       }
+
+       /**
+        * @inheritDoc
+        */
+       protected function getDisplayFormat() {
+               return 'ooui';
+       }
+
+       /**
+        * @inheritDoc
+        */
+       public function onSuccess() {
+               $out = $this->getOutput();
+               $out->addWikiMsg( 'specialmute-success' );
+       }
+
+       /**
+        * @param array $data
+        * @param HTMLForm|null $form
+        * @return bool
+        */
+       public function onSubmit( array $data, HTMLForm $form = null ) {
+               if ( !empty( $data['MuteEmail'] ) ) {
+                       $this->muteEmailsFromTarget();
+               } else {
+                       $this->unmuteEmailsFromTarget();
+               }
+
+               return true;
+       }
+
+       /**
+        * @inheritDoc
+        */
+       public function getDescription() {
+               return $this->msg( 'specialmute' )->text();
+       }
+
+       /**
+        * Un-mute emails from target
+        */
+       private function unmuteEmailsFromTarget() {
+               $blacklist = $this->getBlacklist();
+
+               $key = array_search( $this->targetCentralId, $blacklist );
+               if ( $key !== false ) {
+                       unset( $blacklist[$key] );
+                       $blacklist = implode( "\n", $blacklist );
+
+                       $user = $this->getUser();
+                       $user->setOption( 'email-blacklist', $blacklist );
+                       $user->saveSettings();
+               }
+       }
+
+       /**
+        * Mute emails from target
+        */
+       private function muteEmailsFromTarget() {
+               // avoid duplicates just in case
+               if ( !$this->isTargetBlacklisted() ) {
+                       $blacklist = $this->getBlacklist();
+
+                       $blacklist[] = $this->targetCentralId;
+                       $blacklist = implode( "\n", $blacklist );
+
+                       $user = $this->getUser();
+                       $user->setOption( 'email-blacklist', $blacklist );
+                       $user->saveSettings();
+               }
+       }
+
+       /**
+        * @inheritDoc
+        */
+       protected function alterForm( HTMLForm $form ) {
+               $form->setId( 'mw-specialmute-form' );
+               $form->setHeaderText( $this->msg( 'specialmute-header', $this->target )->parse() );
+               $form->setSubmitTextMsg( 'specialmute-submit' );
+               $form->setSubmitID( 'save' );
+       }
+
+       /**
+        * @inheritDoc
+        */
+       protected function getFormFields() {
+               if ( !$this->enableUserEmailBlacklist || !$this->enableUserEmail ) {
+                       throw new ErrorPageError( 'specialmute', 'specialmute-error-email-blacklist-disabled' );
+               }
+
+               if ( !$this->getUser()->getEmailAuthenticationTimestamp() ) {
+                       throw new ErrorPageError( 'specialmute', 'specialmute-error-email-preferences' );
+               }
+
+               $fields['MuteEmail'] = [
+                       'type' => 'check',
+                       'label-message' => 'specialmute-label-mute-email',
+                       'default' => $this->isTargetBlacklisted(),
+               ];
+
+               return $fields;
+       }
+
+       /**
+        * @param string $username
+        */
+       private function loadTarget( $username ) {
+               $target = User::newFromName( $username );
+               if ( !$target || !$target->getId() ) {
+                       throw new ErrorPageError( 'specialmute', 'specialmute-error-invalid-user' );
+               } else {
+                       $this->target = $target;
+                       $this->targetCentralId = $this->centralIdLookup->centralIdFromLocalUser( $target );
+               }
+       }
+
+       /**
+        * @return bool
+        */
+       private function isTargetBlacklisted() {
+               $blacklist = $this->getBlacklist();
+               return in_array( $this->targetCentralId, $blacklist );
+       }
+
+       /**
+        * @return array
+        */
+       private function getBlacklist() {
+               $blacklist = $this->getUser()->getOption( 'email-blacklist' );
+               if ( !$blacklist ) {
+                       return [];
+               }
+
+               return MultiUsernameFilter::splitIds( $blacklist );
+       }
+}
index 5456ce7..ec34db8 100644 (file)
@@ -219,23 +219,26 @@ class SpecialVersion extends SpecialPage {
        }
 
        /**
-        * Returns wiki text showing the third party software versions (apache, php, mysql).
+        * @since 1.34
         *
-        * @return string
+        * @return array
         */
-       public static function softwareInformation() {
+       public static function getSoftwareInformation() {
                $dbr = wfGetDB( DB_REPLICA );
 
                // Put the software in an array of form 'name' => 'version'. All messages should
                // be loaded here, so feel free to use wfMessage in the 'name'. Raw HTML or
                // wikimarkup can be used.
-               $software = [];
-               $software['[https://www.mediawiki.org/ MediaWiki]'] = self::getVersionLinked();
+               $software = [
+                       '[https://www.mediawiki.org/ MediaWiki]' => self::getVersionLinked()
+               ];
+
                if ( wfIsHHVM() ) {
                        $software['[https://hhvm.com/ HHVM]'] = HHVM_VERSION . " (" . PHP_SAPI . ")";
                } else {
                        $software['[https://php.net/ PHP]'] = PHP_VERSION . " (" . PHP_SAPI . ")";
                }
+
                $software[$dbr->getSoftwareLink()] = $dbr->getServerInfo();
 
                if ( defined( 'INTL_ICU_VERSION' ) ) {
@@ -245,18 +248,27 @@ class SpecialVersion extends SpecialPage {
                // Allow a hook to add/remove items.
                Hooks::run( 'SoftwareInfo', [ &$software ] );
 
+               return $software;
+       }
+
+       /**
+        * Returns HTML showing the third party software versions (apache, php, mysql).
+        *
+        * @return string HTML table
+        */
+       public static function softwareInformation() {
                $out = Xml::element(
                                'h2',
                                [ 'id' => 'mw-version-software' ],
                                wfMessage( 'version-software' )->text()
                        ) .
-                               Xml::openElement( 'table', [ 'class' => 'wikitable plainlinks', 'id' => 'sv-software' ] ) .
-                               "<tr>
-                                       <th>" . wfMessage( 'version-software-product' )->text() . "</th>
-                                       <th>" . wfMessage( 'version-software-version' )->text() . "</th>
-                               </tr>\n";
+                       Xml::openElement( 'table', [ 'class' => 'wikitable plainlinks', 'id' => 'sv-software' ] ) .
+                       "<tr>
+                               <th>" . wfMessage( 'version-software-product' )->text() . "</th>
+                               <th>" . wfMessage( 'version-software-version' )->text() . "</th>
+                       </tr>\n";
 
-               foreach ( $software as $name => $version ) {
+               foreach ( self::getSoftwareInformation() as $name => $version ) {
                        $out .= "<tr>
                                        <td>" . $name . "</td>
                                        <td dir=\"ltr\">" . $version . "</td>
index 6c9bea5..f66eccf 100644 (file)
@@ -25,6 +25,7 @@ class LoginHelper extends ContextSource {
                'resetpass-no-info',
                'confirmemail_needlogin',
                'prefsnologintext2',
+               'specialmute-login-required',
        ];
 
        /**
index 189c3a2..30b511d 100644 (file)
        "restrictionsfield-help": "عنوان أيبي أو نطاق CIDR واحد لكل سطر. لتفعيل كل شيء، استخدم:\n<pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "خطأ: $1",
        "edit-error-long": "الأخطاء:\n\n$1",
+       "specialmute": "كتم الصوت",
+       "specialmute-success": "تم تحديث تفضيلات كتم الصوت بنجاح، شاهد كل المستخدمين الصامتين في [[Special:Preferences]].",
+       "specialmute-submit": "تأكيد",
+       "specialmute-label-mute-email": "كتم رسائل البريد الإلكتروني من هذا المستخدم",
+       "specialmute-header": "يُرجَى تحديد تفضيلات كتم الصوت لـ{{BIDI:[[User:$1]]}}.",
+       "specialmute-error-invalid-user": "لا يمكن العثور على اسم المستخدم المطلوب.",
+       "specialmute-error-email-blacklist-disabled": "لم يتم تمكين كتم المستخدمين من إرسال رسائل البريد الإلكتروني إليك.",
+       "specialmute-error-email-preferences": "يجب تأكيد عنوان بريدك الإلكتروني قبل أن تتمكن من كتم صوت المستخدم، يمكنك القيام بذلك من [[Special:Preferences]].",
+       "specialmute-email-footer": "[$1 إدارة تفضيلات البريد الإلكتروني لـ{{BIDI:$2}}.]",
+       "specialmute-login-required": "يُرجَى تسجيل الدخول لتغيير تفضيلات الصمت الخاصة بك.",
        "revid": "المراجعة $1",
        "pageid": "معرف الصفحة $1",
        "interfaceadmin-info": "$1\n\nتم فصل صلاحيات تحرير ملفات CSS/JS/JSON على مستوى الموقع مؤخرً من صلاحية  <code>editinterface</code>، إذا لم تفهم سبب حصولك على هذا الخطأ، فراجع  [[mw:MediaWiki_1.32/interface-admin]].",
index c347ae2..312da36 100644 (file)
        "restrictionsfield-help": "Адзін IP-адрас ці CIDR-дыяпазон на радок. Каб дазволіць усё, ужывайце:<pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "Памылка: $1",
        "edit-error-long": "Памылкі:\n\n$1",
+       "specialmute": "Заглушаныя ўдзельнікі",
        "revid": "вэрсія $1",
        "pageid": "Ідэнтыфікатар старонкі $1",
        "interfaceadmin-info": "$1\n\nДазволы на рэдагаваньне агульнасайтавых CSS/JS/JSON-файлаў былі нядаўна вылучаныя з права <code>editinterface</code>. Калі вы не разумееце, чаму атрымліваеце гэтую памылку, глядзіце [[mw:MediaWiki_1.32/interface-admin]].",
index 169cda8..e7ae281 100644 (file)
        "credentialsform-account": "Kontonavn:",
        "edit-error-short": "Fejl: $1",
        "edit-error-long": "Fejl:\n\n$1",
+       "specialmute-submit": "Bekræft",
        "revid": "version $1",
        "pageid": "side id: $1",
        "gotointerwiki": "Forlader {{SITENAME}}",
index 17e2516..2c1eb37 100644 (file)
        "undo-summary": "[[Special:Contributions/$2|$2]]i ([[User talk:$2|werênayış]]) vurnayışê $1i peyser gırewt",
        "undo-summary-username-hidden": "Rewizyona veri $1'i hewada",
        "cantcreateaccount-text": "Hesabvıraştışê na IP adrese ('''$1''') terefê [[User:$3|$3]] kılit biyo.\n\nSebebo ke terefê $3 ra diyao ''$2''",
-       "viewpagelogs": "Qeydanê na pele bımocne",
+       "viewpagelogs": "Qandê ena pela roceka bıvinê",
        "nohistory": "Verorê vurnayışanê na perer çıni yo.",
        "currentrev": "Çımraviyarnayışo rocane",
        "currentrev-asof": "$1 ra tepiya weziyeta pela",
        "last": "verên",
        "page_first": "verên",
        "page_last": "peyên",
-       "histlegend": "Ferqê weçinayıÅ\9fi: Qutiya versiyonan qandé  têversanayıÅ\9f iÅ\9faret ke u dest be ''enter''i ya zi gocega cêrêne rone.<br />\nCetwel: <strong>({{int:ferq}})</strong> = ferqê versiyonê peyêni, <strong>({{int:peyên}})</strong> = ferqê versiyonê verêni, <strong>{{int:q}}</strong> = vırnayışo werdiyo.",
-       "history-fieldset-title": "Çımraviyarnayışan parzûn ke",
+       "histlegend": "Ferqê weçinayıÅ\9fi: Qutiya versiyonan qandê têversanayıÅ\9f iÅ\9faret kerê u dest be ''enter''i ya zi gocega cêrêne rone.<br />\nCetwel: <strong>({{int:ferq}})</strong> = ferqê versiyonê peyêni, <strong>({{int:peyên}})</strong> = ferqê versiyonê verêni, <strong>{{int:q}}</strong> = vırnayışo werdiyo.",
+       "history-fieldset-title": "Revizyona parzun kerê",
        "history-show-deleted": "Tenya çımraviyarnayışanê esterıteyan bımocne",
        "histfirst": "Verênêr",
        "histlast": "Peyênêr",
        "cantrollback": "karbero peyin têna paşt dayo, no semedi ra vuriyayiş tepiya nêgeriyeni.",
        "alreadyrolled": "[[User:$2|$2]] ([[User talk:$2|Talk]]{{int:pipe-separator}} hetê [[Special:Contributions/$2|{{int:contribslink}}]]) ra perrê ıney[[:$1]] de vırnayış biyo u no vırnayiş tepeya nêgêriyeno;\nyewna ten perre de vırnayiş kerdo u perre tepiya nêgeriyeno.\n\noyo ke vırnayışo peyên kerdo: [[User:$3|$3]] ([[User talk:$3|Talk]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "Xulasay vurnayışi: <em>$1</em> bi",
-       "revertpage": "Hetê [[Special:Contributions/$2|$2]] ([[User talk:$2|Mesac]]) ra vurnayiş biyo u ney vurnayişi tepiya geriyayo u no [[User:$1|$1]] kes o ke cuwa ver revizyon kerdo revizyonê no kesi tepiya anciyayo.",
+       "revertpage": "Terefê [[Special:Contributions/$2|$2]] ([[User talk:$2|Mesac]]) ra vurnayışê [[User:$1|$1]] peyser gêriyayo.",
        "revertpage-nouser": "No keso ke vuriyayiş kerdo vuriyayişé{{GENDER:$1|[[User:$1|$1]]}} ker o",
-       "rollback-success": "Terefê {{GENDER:$3|$1}}i ra vuriyayışi peyser gêriyayi; peyser geyriya be revizyonê {{GENDER:$4|$2}}i.",
+       "rollback-success": "Terefê {{GENDER:$3|$1}}i ra vuriyayış peyser gêriya; revizyonê {{GENDER:$4|$2}} peyser ard.",
        "sessionfailure-title": "Seans xeripiya",
        "sessionfailure": "cıkewtışê hesabê şıma de yew problem aseno;\nno kar semedê dızdiyê hesabi ibtal biyo.\nkerem kerê \"tepiya\" şiyerê u pel o ke şıma tera ameyî u o pel newe ra bar kerê , newe ra tesel/cereb kerê.",
        "changecontentmodel": "Modelê zerrekê pele bıvurne",
index ffcdf09..e0ae02b 100644 (file)
        "deletionlog": "Καταγραφές διαγραφών",
        "log-name-create": "Αρχείο καταγραφών δημιουργίας σελίδων",
        "log-description-create": "Παρακάτω υπάρχει ένας κατάλογος των πιο πρόσφατων δημιουργιών σελίδας.",
-       "logentry-create-create": "$1 δημιούργησε τη σελίδα $3",
+       "logentry-create-create": "{{GENDER:$2|Ο|Η}} $1 δημιούργησε τη σελίδα $3",
        "reverted": "Επαναφορά σε προηγούμενη αναθεώρηση",
        "deletecomment": "Λόγος:",
        "deleteotherreason": "Άλλος/πρόσθετος λόγος:",
index 425cf2b..244b281 100644 (file)
        "restrictionsfield-help": "One IP address or CIDR range per line. To enable everything, use:<pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "Error: $1",
        "edit-error-long": "Errors:\n\n$1",
+       "specialmute": "Mute",
+       "specialmute-success": "Your mute preferences have been successfully updated. See all muted users in [[Special:Preferences]].",
+       "specialmute-submit": "Confirm",
+       "specialmute-label-mute-email": "Mute emails from this user",
+       "specialmute-header": "Please select your mute preferences for {{BIDI:[[User:$1]]}}.",
+       "specialmute-error-invalid-user": "The username requested could not be found.",
+       "specialmute-error-email-blacklist-disabled": "Muting users from sending you emails is not enabled.",
+       "specialmute-error-email-preferences": "You must confirm your email address before you can mute a user. You may do so from [[Special:Preferences]].",
+       "specialmute-email-footer": "[$1 Manage email preferences for {{BIDI:$2}}.]",
+       "specialmute-login-required": "Please log in to change your mute preferences.",
        "revid": "revision $1",
        "pageid": "page ID $1",
        "interfaceadmin-info": "$1\n\nPermissions for editing of sitewide CSS/JS/JSON files were recently separated from the <code>editinterface</code> right. If you do not understand why you are getting this error, see [[mw:MediaWiki_1.32/interface-admin]].",
index 597dca2..ec385bd 100644 (file)
        "restrictionsfield-help": "Unu IP-adreso aŭ CIDR-intervalo per linio. Por permesigi ĉion, uzu:<pre>0.0.0.0/0</code>\n<code>::/0</pre>",
        "edit-error-short": "Eraro: $1",
        "edit-error-long": "Eraroj:\n\n$1",
+       "specialmute": "Silentigi",
+       "specialmute-submit": "Konfirmi",
+       "specialmute-label-mute-email": "Kaŝi retmesaĝojn el ĉi tiu uzanto",
+       "specialmute-error-invalid-user": "La petita uzantnomo ne troviĝis.",
+       "specialmute-email-footer": "[$1 Administri preferojn pri retpoŝto por {{BIDI:$2}}.]",
        "revid": "revizio $1",
        "pageid": "Identigilo de paĝo $1",
        "interfaceadmin-info": "$1\n\nPermesoj pri redaktado de tut-retejaj CSS/JavaScript/JSON-dosieroj estis lastatempe disigitaj for de la rajto <code>editinterface</code>. Se vi ne komprenas kial vi ricevis ĉi tiun eraron, vidu la paĝon [[mw:MediaWiki_1.32/interface-admin]].",
index 34a3ec0..234c7d9 100644 (file)
        "history": "Historial",
        "history_short": "Historial",
        "history_small": "historial",
-       "updatedmarker": "actualizado desde mi última visita",
+       "updatedmarker": "actualizado desde tu última visita",
        "printableversion": "Versión para imprimir",
        "permalink": "Enlace permanente",
        "print": "Imprimir",
        "restrictionsfield-help": "Una dirección IP o intervalo de CIDR por renglón. Para activarlo todo, utiliza <pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "Error: $1",
        "edit-error-long": "Errores:\n\n$1",
+       "specialmute": "Silenciar",
+       "specialmute-submit": "Confirmar",
+       "specialmute-error-invalid-user": "No se encontró el nombre de usuario solicitado.",
        "revid": "revisión $1",
        "pageid": "ID de página $1",
        "interfaceadmin-info": "$1\n\nLos permisos para editar los archivos con formato CSS, JS y JSON en todo el sitio han sido recientemente separados del permiso <code>editinterface</code>. Si no comprendes por qué recibes este error, por favor lee [[mw:MediaWiki_1.32/interface-admin]].",
index 4e35fab..26398ed 100644 (file)
@@ -31,7 +31,7 @@
        "exif-make": "ഛായാഗ്രാഹി നിർമ്മാതാവ്",
        "exif-model": "ഛായാഗ്രാഹി മോഡൽ",
        "exif-software": "ഉപയോഗിച്ച സോഫ്റ്റ്‌വെയർ",
-       "exif-artist": "ഛായാഗ്രാഹക",
+       "exif-artist": "ഛായാഗ്രാഹക(ൻ)",
        "exif-copyright": "പകർപ്പവകാശ ഉടമ",
        "exif-exifversion": "എക്സിഫ് (Exif) പതിപ്പ്",
        "exif-flashpixversion": "പിന്തുണയുള്ള ഫ്ലാഷ്‌‌പിക്സ് പതിപ്പ്",
index 58edc36..f0b6aea 100644 (file)
        "history": "تاریخچهٔ صفحه",
        "history_short": "تاریخچه",
        "history_small": "تاریخچه",
-       "updatedmarker": "به‌روزشده از آخرین باری که سرزده‌ام",
+       "updatedmarker": "به‌روزشده از آخرین باری که سرزده‌اید",
        "printableversion": "نسخهٔ قابل چاپ",
        "permalink": "پیوند پایدار",
        "print": "چاپ",
        "autoblockedtext": "دسترسی نشانی آی‌پی شما قطع شده‌است، زیرا این نشانی آی‌پی توسط کاربر دیگری استفاده شده که دسترسی او توسط $1 قطع شده‌است.\nدلیل ارائه‌شده چنین است:\n\n:''$2''\n\n* شروع قطع دسترسی: $8\n* پایان قطع دسترسی: $6\n* کاربری هدف قطع دسترسی: $7\n\nشما می‌توانید با $1 یا [[{{MediaWiki:Grouppage-sysop}}|مدیری]] دیگر تماس بگیرید و در این باره صحبت کنید.\nتوجه کنید که شما نمی‌توانید از قابلیت «{{int:emailuser}}» استفاده کنید مگر آنکه نشانی ایمیل معتبری در [[Special:Preferences|ترجیحات کاربری]] خودتان ثبت کرده باشید و نیز باید امکان استفاده از این قابلیت برای شما قطع نشده باشد.\nنشانی آی‌پی فعلی شما $3 و شمارهٔ قطع دسترسی شما $5 است.\nلطفاً تمامی جزئیات فوق را در کلیهٔ درخواست‌هایی که در این باره مطرح می‌کنید ذکر کنید.",
        "systemblockedtext": "نام کاربری یا نشانی آی‌پی شما خودکار توسط مدیاویکی مسدود شده‌است.\nدلیل ارائه‌شده:\n\n:<em>$2</em>\n\n* آغاز بلاک: $8\n* پایان بلاک: $6\n* قطع دسترسی‌شده مورد نظر: $7\n\nنشانی آی‌پی کنونی شما $3 است.\nخواهشمند است تمام جزئیات بالا را در هر پرس‌وجویی که انجام می‌دهید قرار دهید.",
        "blockednoreason": "دلیلی مشخص نشده‌است",
+       "blockedtext-composite": "<strong>نام کاربری یا نشانی آی‌پی شما خودکار توسط مدیاویکی مسدود شده‌است.</strong>\nدلیل ارائه‌شده:\n\n:<em>$2</em>\n\n* آغاز بلاک: $8\n* پایان بلاک: $6\n\nنشانی آی‌پی کنونی شما $3 است.\nخواهشمند است تمام جزئیات بالا را در هر پرس‌وجویی که انجام می‌دهید قرار دهید.",
+       "blockedtext-composite-reason": "حساب/آی‌پی شما به چند طریق بسته شده‌است",
        "whitelistedittext": "برای ویرایش مقاله‌ها باید $1.",
        "confirmedittext": "شما باید، پیش از ویرایش صفحات، آدرس ایمیل خود را مشخص و تأیید کنید. لطفاً از طریق [[Special:Preferences|ترجیحات کاربر]] این کار را صورت دهید.",
        "nosuchsectiontitle": "چنین بخشی پیدا نشد",
        "restrictionsfield-help": "یک نشانی آی‌پی یا بازهٔ سی‌آی‌دی‌ار در هر خط وارد کنید. برای فعال کردن همه‌چیز، این مقدار را استفاده کنید: <code>0.0.0.0/0</code><br /><code>::/0</code>",
        "edit-error-short": "خطا: $1",
        "edit-error-long": "خطاها:\n\n$1",
+       "specialmute": "بی‌صدا",
+       "specialmute-success": "تنظیمات بی‌صدا به روز شد. دیدن فهرست همهٔ کاربرانی که در [[Special:Preferences|ترجیحاتتان]] به عنوان بی‌صدا انتخاب کردید.",
+       "specialmute-submit": "تأیید",
+       "specialmute-label-mute-email": "بی‌صدا کردن ایمیل از این کاربر",
+       "specialmute-header": "لطفاً ترجیحات بی‌صدا برای {{BIDI:[[User:$1]]}} را انتخاب کنید.",
+       "specialmute-error-invalid-user": "نام کاربری درخواست شده یافت نشد.",
+       "specialmute-error-email-blacklist-disabled": "بی‌صدا کردن کاربران برای ارسال ایمیل فعال نشده‌است.",
+       "specialmute-error-email-preferences": "پیش از بی‌صدا کردن دیگر کاربران باید آدرس ایمیلیتان را تائید کنید. که از [[Special:Preferences|ترجیحاتتان]] مقدور است.",
+       "specialmute-email-footer": "[$1 مدیریت ترجیحات ایمیل برای {{BIDI:$2}}.]",
+       "specialmute-login-required": "لطفاً برای تغییر ترجیحات بی‌صدا به سامانه وارد شوید.",
        "revid": "نسخهٔ $1",
        "pageid": "شناسهٔ صفحهٔ $1",
        "interfaceadmin-info": "\n$1\n\nدسترسی‌ها برای ویرایش فایل‌های CSS/JS/JSON که اخیراً از دسترسی <code>editinterface</code> جدا شده‌اند. اگر نمی دانید که چرا این خطا رخ داده‌است [[mw:MediaWiki_1.32/interface-admin]] را مطالعه کنید.",
index f72f85c..2f62520 100644 (file)
        "rcfilters-filter-previousrevision-label": "Net de lêste ferzje",
        "rcfilters-filter-previousrevision-description": "Alle wizigings dy't net de \"lêste ferzje\" binne.",
        "rcfilters-filter-excluded": "Utsein",
+       "rcfilters-tag-prefix-namespace-inverted": "<strong>:net</strong> $1",
        "rcfilters-exclude-button-off": "Seleksje omkeare",
        "rcfilters-exclude-button-on": "Omkearde seleksje",
        "rcfilters-view-tags": "Lebele bewurkings",
        "deletecomment": "Reden:",
        "deleteotherreason": "Oare/eventuele reden:",
        "deletereasonotherlist": "Oare reden",
-       "deletereason-dropdown": "*Faak-brûkte redenen\n** Frege troch de skriuwer\n** Skeining fan auteursrjocht\n** Fandalisme",
+       "deletereason-dropdown": "* Gongbere wiskredens\n** Spam\n** Fandalisme\n** Skeining fan auteursrjochten\n** Frege troch de skriuwer\n** Misse trochferwizing",
        "rollback": "Wizigings weromdraaie",
        "rollback-confirmation-yes": "Weromdraaie",
        "rollbacklink": "weromdraaie",
index 7919e19..db8f738 100644 (file)
@@ -5,7 +5,7 @@
                        "Léon973"
                ]
        },
-       "tog-underline": "Soulignman dé lyannaj :",
+       "tog-underline": "Soulignman dyannaj :",
        "tog-hideminor": "Maské modifikasyon minò-ya annan modifikasyon résan-yan",
        "tog-hidepatrolled": "Maské modifikasyon-yan ki rouli annan modifikasyon résan-yan",
        "tog-newpageshidepatrolled": "Maské paj-ya ki rouli annan lis dé nouvèl paj",
@@ -30,7 +30,7 @@
        "tog-enotifrevealaddr": "Afiché mo adrès élègtronnik annan kourilèt di notifikasyon",
        "tog-shownumberswatching": "Afiché nonm-an di itilizatò an kour",
        "tog-oldsig": "Zòt signatir atchwèl :",
-       "tog-fancysig": "Trété signatir-a kou di wikitègs (san lyannaj otonmantik)",
+       "tog-fancysig": "Trété signatir-a kou wikitègs (san yannaj otonmantik)",
        "tog-uselivepreview": "Afiché apèrsou san roucharjé paj-a",
        "tog-forceeditsummary": "Avèrti mo lò mo pa èspésifyé di rézimen di modifikasyon",
        "tog-watchlisthideown": "Maské mo pròp modifikasyon annan lis di swivi",
        "listingcontinuesabbrev": "(swit)",
        "index-category": "Paj endèksé",
        "noindex-category": "Paj ki pa endèksé",
-       "broken-file-category": "Paj ké lyannaj di fiché brizé",
+       "broken-file-category": "Paj ké yannaj-ya di fiché ki brizé",
        "categoryviewer-pagedlinks": "($1) ($2)",
        "category-header-numerals": "$1–$2",
        "about": "Apropo",
        "tagline": "Di {{SITENAME}}",
        "help": "Lèd",
        "search": "Sasé",
-       "search-ignored-headings": " #<!-- pa modifyé sa lign --><pre>\n# Tit dé sègsyon ki ké fika ignoré pa sasé-a.\n# Chanjman-yan ki éfègtchwé isi ka pran léfè lò ki paj-a ké tit-a sa endègsé.\n# Zòt pouvé fòrsé réyendègsasyon di paj-a an éfègtchwan roun modifikasyon vid.\n# Sentags-a sa swivant-a :\n#   * Tousa ki ka swiv roun « # » jouk finisman-an di lign-an sa roun koumantèr.\n#   * Tout lign ki pa-vid sa tit ègzak-a pou ignoré, kas konprann osi.\nRéférans\nLyannaj ègstèrn\nWè osi\n #</pre><!-- pa modifyé sa lign -->",
+       "search-ignored-headings": " #<!-- pa modifyé sa lign --><pre>\n# Tit sègsyon-yan ki ké fika ignoré pa sasé-a.\n# Chanjman-yan ki éfègtchwé isi ka pran léfè lò ki paj-a ké tit-a sa endègsé.\n# Zòt pouvé fòrsé réyendègsasyon-an di paj-a an éfègtchwan roun modifikasyon ki vid.\n# Sentags-a sa swivant-a :\n#   * Tousa ki ka swiv roun « # » jouk finisman-an di lign-an sa roun koumantèr.\n#   * Tout lign ki pa-vid sa tit ègzak-a pou ignoré, kas konprann osi.\nRéférans\nYannaj èstèrn\nWè osi\n #</pre><!-- pa modifyé sa lign -->",
        "searchbutton": "Sasé",
        "go": "Konsilté",
        "searcharticle": "Kontinwé",
        "history_short": "Listorik",
        "history_small": "listorik",
        "updatedmarker": "modifyé dipi zòt dannyé vizit",
-       "printableversion": "Vèrsyon enprimab",
-       "permalink": "Lyannaj pèrmannan",
+       "printableversion": "Vèrsyon ki enprimab",
+       "permalink": "Yannaj ki pèrmannan",
        "print": "Enprimé",
        "view": "Lir",
        "view-foreign": "Wè asou $1",
        "lastmodifiedat": "Dannyé modifikasyon di sa paj té fè $1 à $2.",
        "viewcount": "Sa paj {{PLURAL:$1|0=pa té janmen konsilté|1=té konsilté roun sèl fwè|té konsilté $1 fwè}}.",
        "protectedpage": "Paj protéjé",
-       "jumpto": "Alé à",
+       "jumpto": "Alé bò :",
        "jumptonavigation": "navigasyon",
        "jumptosearch": "sasé",
        "view-pool-error": "Dézolé, sèrvò-ya sa sircharjé pou moman-an.\nTròp itilizatò ka sasé konsilté sa paj.\nSouplé, atann enpé anvan di éséyé òkò d’aksédé à sala.\n\n$1",
        "nstab-category": "Katégori",
        "mainpage-nstab": "Paj prensipal",
        "nosuchaction": "Agsyon enkonnèt",
-       "nosuchactiontext": "Lagsyon-an ki èspésifyé annan URL-a sa envalid.\nZòt pitèt mal rantré URL-a oben swivi roun lyannaj ki éronnen.\nLi pouvé égalman endiké roun annonmanli annan logisyèl-a ki itilizé pa {{SITENAME}}.",
+       "nosuchactiontext": "Lagsyon-an ki èspésifyé annan URL-a sa envalid.\nZòt pitèt mal rantré URL-a oben swivi roun yannaj ki éronnen.\nLi pouvé égalman endiké roun annonmanli annan logisyèl-a ki itilizé pa {{SITENAME}}.",
        "nosuchspecialpage": "Paj èspésyal inègzistant",
        "nospecialpagetext": "<strong>Zòt doumandé oun paj èspésyal ki pa ka ègzisté.</strong>\n\nOun lis dé paj èspésyal valid ka trouvé so kò asou [[Special:SpecialPages|{{int:specialpages}}]].",
        "error": "Lérò",
        "readonly": "Baz di data vérouyé",
        "enterlockreason": "Endiké rézon-an di vérouyaj ensi ki roun èstimasyon di so douré",
        "readonlytext": "Ajou-ya ké mizajou-ya di baz di data fika atchwèlman bloké, probabman pou pèrmèt mentnans-a di baz-a, apré sa, tout bagaj ké rantré annòrd.\n\nAdministratò sistenm-an ki vérouyé baz di data fourni lèsplikasyon-an ki ka swiv :<br /> $1",
-       "missing-article": "Baz-a di data pa trouvé tègs-a di roun paj ki li té divèt trouvé, ki entitilé « $1 » $2.\n\nJénéralman, sala ka sirvini an swivan roun lyannaj bò'd roun dif ki périmen oben bò'd listorik-a di roun paj ki siprimen.\n\nSi a pa sa ki la, zòt pitèt trouvé roun annonmanli annan progranm-an.\nSouplé, signalé li à roun [[Special:ListUsers/sysop|administratò]] é pa bliyé di endiké li URL-a di paj-a.",
+       "missing-article": "Baz-a di data pa trouvé tègs-a di roun paj ki li té divèt trouvé, ki entitilé « $1 » $2.\n\nJénéralman, sala ka sirvini an swivan roun yannaj bò'd roun dif ki périmen oben bò'd listorik-a di roun paj ki siprimen.\n\nSi a pa sa, a pitèt roun annonmanli annan progranm-an.\nSouplé, signalé li bay roun [[Special:ListUsers/sysop|administratò]] é pa bliyé di endiké li URL-a di paj-a.",
        "missingarticle-rev": "(niméro di vèrsyon : $1)",
        "missingarticle-diff": "(diff : $1, $2)",
        "readonly_lag": "Baz-a di data té otonmatikman vérouyé pannan ki sèrvò-ya ségondèr ka réyaligné yé kò asou sèrvò prensipal-a",
        "badtitletext": "Tit di paj doumandé pa valid, vid, oben mal fòrmé si a roun tit entèr-lanng oben entèr-projè.\nI ka kontni pitèt oun oben plizyò karaktèr ki pa pouvé fika itilizé annan tit-ya.",
        "title-invalid-empty": "Tit di paj doumandé sa vid oben ka kontni sèlman non-an di roun lèspas di non.",
        "title-invalid-utf8": "Tit di paj doumandé ka kontni roun sékans UTF-8 envalid.",
-       "title-invalid-interwiki": "Paj siblé-a ka kontni roun lyannaj entèrwiki ki pa pouvé fika itilizé annan tit-ya.",
+       "title-invalid-interwiki": "Paj sib-a ka kontni roun yannaj entèrwiki ki pa pouvé fika itilizé annan tit-ya.",
        "title-invalid-talk-namespace": "Tit di paj doumandé ka fè référans à roun paj di diskisyon ki pa pouvé ègzisté.",
        "title-invalid-characters": "Tit di paj doumandé ka kontni dé karaktèr ki pa valid : « $1 ».",
        "title-invalid-relative": "Tit ka kontni oun chimen roulatif. Tit-ya ki ka référansé dé paj roulativ (./, ../) pa valid pas li sa souvan itilizé pa navigatò di itilizatò-a.",
        "createacct-email-ph": "Antré zòt adrès di kourilèt",
        "createacct-another-email-ph": "Antré adrès-a di kourilèt",
        "createaccountmail": "Itilizé roun modipas aléyatwè ki tanporèr é voyé li pou adrès-a di kourilèt ki èspésifyé",
-       "createaccountmail-help": "Pouvé fika itilizé pou kréyé roun kont pou rounòt moun san konèt mo di pas-a.",
+       "createaccountmail-help": "Pouvé fika itilizé pou kréyé roun kont pou rounòt moun san konnèt modipas-a.",
        "createacct-realname": "Non réyèl (fakiltatif)",
        "createacct-reason": "Motif",
        "createacct-reason-ph": "Poukisa zòt kréyé rounòt kont",
        "login-userblocked": "{{GENDER:$1|Sa itilizatò}} bloké. Konnègsyon-an pa otorizé.",
        "wrongpassword": "Non-an di itilizatò oben modipas enkorèk.\nSouplé, éséyé òkò.",
        "wrongpasswordempty": "Zòt pa rantré pyès modipas.\nSouplé, éséyé òkò.",
-       "passwordtooshort": "Zòt mo di pas divèt kontni omwen $1 karaktèr{{PLURAL:$1|}}.",
+       "passwordtooshort": "Zòt modipas divèt kontni onmwen $1 karaktèr{{PLURAL:$1|}}.",
        "passwordtoolong": "Modipas-ya pa pouvé dépasé $1 karagtèr{{PLURAL:$1|}}.",
        "passwordtoopopular": "Modipas ki tròp kouran pa pouvé fika itilizé. Souplé, chwézi roun modipas ki pi difisil pou sonjé.",
-       "password-name-match": "Zòt mo di pas divèt fika diféran di zòt non d'itilizatò.",
+       "password-name-match": "Zòt modipas divèt fika diféran di zòt non di itilizatò.",
        "password-login-forbidden": "Litilizasyon-an di sa non d'itilizatò oben di sa modipas sa entèrdi.",
        "mailmypassword": "Réynisyalizé modipas-a",
        "passwordremindertitle": "Nouvèl modipas tanporèr pou {{SITENAME}}",
        "loginlanguagelabel": "Lanng : $1",
        "suspicious-userlogout": "Zòt doumann di konnègsyon té roufizé pas i sanblé ki li té voyé pa roun navigatò défègtché oben dipi kach-a di roun sèrvis mandatèr.",
        "createacct-another-realname-tip": "Véritab non-an sa òpsyonnèl.\nSi zòt désidé di fourni li, i ké fika itilizé pou krédité lotò-a di so travay-ya.",
-       "pt-login": "Konnègté so kò",
+       "pt-login": "Konnègté sokò",
        "pt-login-button": "Konnègté so kò",
        "pt-login-continue-button": "Kontinwé konnègsyon-an",
        "pt-createaccount": "Kréyé roun kont",
-       "pt-userlogout": "Dékonnègté so kò",
+       "pt-userlogout": "Dékonnègté sokò",
        "php-mail-error-unknown": "Lérò enkonnèt annan fongsyon-an <kod>mail()</kod> di PHP.",
        "user-mail-no-addy": "Enposib di voyé roun kourilèt san adrès di kourilèt.",
        "user-mail-no-body": "Lésè di voyé di roun kourilèt ké roun kò vid oben anòrmalman kourt.",
        "botpasswords-label-needsreset": "(Modipas-a divèt fika réynisyalizé)",
        "botpasswords-label-appid": "Non di robo :",
        "botpasswords-label-create": "Kréyé",
-       "botpasswords-label-update": "Mété à jou",
+       "botpasswords-label-update": "Fè roun mizajou",
        "botpasswords-label-cancel": "Annilé",
        "botpasswords-label-delete": "Siprimen",
        "botpasswords-label-resetpassword": "Réynisyalizé modipas-a",
        "botpasswords-insert-failed": "Échèk di ajou-a di non di robo « $1 ». Ès i té ja ajouté ?",
        "botpasswords-update-failed": "Léchèk di mizajou di non di robo « $1 ». Ès i té ja siprimen ?",
        "botpasswords-created-title": "Modipas di robo kréyé",
-       "botpasswords-created-body": "Mo di pas pou robo-a « $1 » di {{GENDER:$2|itilizatò|itilizatris}}-a « $2 » té kréyé.",
+       "botpasswords-created-body": "Modipas-a pou robo-a « $1 » di {{GENDER:$2|itilizatò|itilizatris}}-a « $2 » fika kréyé.",
        "botpasswords-updated-title": "Modipas di robo mizajou",
-       "botpasswords-updated-body": "Mo di pas pou robo-a « $1 » di {{GENDER:$2|itilizatò|itilizatris}}-a « $2 » té mizajou.",
+       "botpasswords-updated-body": "Modipas-a pou robo-a « $1 » di {{GENDER:$2|itilizatò|itilizatris}}-a « $2 » fika mizajou.",
        "botpasswords-deleted-title": "Modipas di robo siprimen",
        "botpasswords-deleted-body": "Modipas-a pou robo-a « $1 » di {{GENDER:$2|itilizatò|itilizatris}}-a « $2 » té siprimen.",
        "botpasswords-newpassword": "Nouvèl modipas-a pou konnègté so kò à<strong>$1</strong> sa <strong>$2</strong>. <em>Souplé, anréjistré li pou fè référans asou li iltèryòrman.</em><br> (Pou ansyen robo-ya ki ka nésésité ki non-an ki fourni pou konnègsyon-an ka fika menm-an ki non-an di itilizatò évantchwèl, zòt pouvé osi itilizé <strong>$3</strong> kou non di itilizatò é <strong>$4</strong> kou modipas).",
        "botpasswords-no-provider": "BotPasswordsSessionProvider pa disponnib.",
        "botpasswords-restriction-failed": "Rèstrigsyon-yan di modipas di robo ka anpéché sa konnègsyon.",
        "botpasswords-invalid-name": "Non-an d'itilizatò ki èspésifyé pa ka kontni di séparatò di modipas di robo (« $1 »).",
-       "botpasswords-not-exist": "{{GENDER:$1|Itilizatò|Itilizatris}}-a « $1 » pa gen di mo di pas di robo nonmen « $2 ».",
+       "botpasswords-not-exist": "{{GENDER:$1|Itilizatò|Itilizatris}}-a « $1 » pa gen di modipas di robo ki nonmen « $2 ».",
        "botpasswords-needs-reset": "Modipas-a di robo di non « $2 » di itilizatò-a « $1 » divèt fika réynisyalizé.",
        "resetpass_forbidden": "Modipas-ya pa pouvé fika chanjé.",
        "resetpass_forbidden-reason": "Modipas-ya pa pouvé fika chanjé : $1",
        "bold_tip": "Tègs gra",
        "italic_sample": "Tègs italik",
        "italic_tip": "Tègs italik",
-       "link_sample": "Tit di lyannaj",
-       "link_tip": "Lyannaj entèrn",
-       "extlink_sample": "http://www.example.com/ tit di lyannaj",
-       "extlink_tip": "Lyannaj ègstèrn (pa bliyé préfigs-a http://)",
+       "link_sample": "Tit di yannaj",
+       "link_tip": "Yannaj entèrn",
+       "extlink_sample": "http://www.example.com/ tit di yannaj",
+       "extlink_tip": "Yannaj èstèrn (pa bliyé préfigs-a http://)",
        "headline_sample": "Tègs di tit",
        "headline_tip": "Soutit nivo 2",
        "nowiki_sample": "Rantré tègs-a ki pa fòrmaté isi",
        "nowiki_tip": "Ignoré sentags wiki-a",
        "image_tip": "Fiché enséré",
-       "media_tip": "Lyannaj bò'd roun fiché médja",
+       "media_tip": "Yannaj bò'd roun fiché médja",
        "sig_tip": "Zòt signatir ké dat",
        "hr_tip": "Lign orizontal (pa an abizé)",
        "summary": "Rézimen :",
        "blockedtitle": "Itilizatò-a bloké.",
        "blockedtext": "<strong>Zòt kont itilizatò oben zòt adrès IP fika bloké.</strong>\n\nBlokaj té éfègtchwé pa $1.\nRézon-an ki évoké ka swiv : <em>$2</em>.\n\n* Koumansman di blokaj : $8\n* Lèspirasyon di blokaj : $6\n* Kont bloké : $7.\n\nZòt pouvé kontagté $1 oben rounòt [[{{MediaWiki:Grouppage-sysop}}|administratò]] pou diskité apropo di sa.\nZòt pouvé itilizé fongsyon-an « {{int:emailuser}} » rounso si roun adrès di kourilèt valid sa èspésifyé annan zòt [[Special:Preferences|préférans]] é rounso si sa fongsyonnalité pa fika bloké ba zòt.\nZòt adrès IP atchwèl sa $3 é zòt idantifyan di blokaj sa $5.\nSouplé, enkli tout détay-ya lasou'l annan chak rékèt ki zòt ké fè.",
        "blockednoreason": "pyès rézon bay",
-       "loginreqlink": "konnègté so kò",
+       "loginreqlink": "konnègté sokò",
        "accmailtitle": "Modipas voyé.",
        "newarticle": "(Nòv)",
-       "newarticletext": "Zòt swiv roun lyannaj bò'd roun paj ki pa ka ègzisté òkò. \nAfen di kréyé sa paj, rantré zòt tègs annan bwèt-a ki apré (zòt pouvé konsilté [$1 paj di lèd-a] pou plis di lenfòrmasyon).\nSi zòt vini{{GENDER:|}} isi pa lérò, kliké asou bouton-an <strong>Viré</strong> di zòt navigatò.",
+       "newarticletext": "Zòt swiv roun yannaj bò'd roun paj ki pa ka ègzisté òkò. \nAfen di kréyé sa paj, rantré zòt tègs annan bwèt-a ki apré (zòt pouvé konsilté [$1 paj di lèd-a] pou plis lenfòrmasyon).\nSi zòt vini{{GENDER:|}} isi pa lérò, kliké asou bouton-an <strong>Viré</strong> di zòt navigatò.",
        "anontalkpagetext": "----\n<em>Zòt asou paj-q di diskisyon di roun itilizatò annonnim ki pa òkò kréyé di kont oben ki pa ka itilizé roun</em>.\nPou sa rézon, nou divèt itilizé so adrès IP pou idantifyé li.\nOun adrès konran IP pouvé fika patajé pa plizyò itilizatò.\nSi zòt sa roun itiliza{{GENDER:|ò}} annonnim é si zòt ka kontasté ki dé koumantèr ki pa ka konsèrnen zòt, fika adrésé ba zòt, zòt pouvé [[Special:CreateAccount|kréyé roun kont]] oben [[Special:UserLogin|konnègté zòt kò]] pou évité tout konfizyon fitir ké ròt kontribitò annonnim.",
-       "noarticletext": "I pa gen atchwèlman pyès tègs asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|lansé oun sasé asou sa tit]] annan ròt paj-ya,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sasé annan lopérasyon-yan ki lyannen]\noben [{{fullurl:{{FULLPAGENAME}}|action=edit}} kréyé sa paj]</span>.",
+       "noarticletext": "I gen atchwèlman pyès tègs asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|lansé oun sasé asou sa tit]] annan ròt paj-ya,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sasé annan lopérasyon-yan ki yannen]\noben [{{fullurl:{{FULLPAGENAME}}|action=edit}} kréyé sa paj]</span>.",
        "noarticletext-nopermission": "I pa gen atchwèlman pyès tègs asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|fè roun sasé asou sa tit]] annan ròt paj-ya,\noben <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|paj={{FULLPAGENAMEE}}}} sasé annan journal-ya ki asosyé]</span>, mé zòt pa gen pèrmisyon-an di kréyé sa paj.",
        "userpage-userdoesnotexist-view": "Kont itilizatò-a « $1 » pa anréjistré.",
        "clearyourcache": "<strong>Nòt :</strong> apré zòt anréjistré zòt modifikasyon, zòt divèt fòrsé roucharjman konplè di kach di zòt navigatò pou wè chanjman-yan.\n* <strong>Firefox / Safari :</strong> mentni touch-a <em>Maj</em> (<em>Shift</em>) an klikan asou bouton-an <em>Atchwalizé</em> oben présé <em>Ctrl-F5</em> oben <em>Ctrl-R</em> (<em>⌘-R</em> asou roun Mac) \n* <strong>Google Chrome :</strong> apiyé asou <em>Ctrl-Maj-R</em> (<em>⌘-Shift-R</em> asou roun Mac) \n* <strong>Internet Explorer :</strong> mentni touch-a <em>Ctrl</em> an klikan asou bouton-an <em>Atchwalizé</em> oben présé <em>Ctrl-F5</em> \n* <strong>Opera :</strong> alé annan <em>Menu → Settings</em> (<em>Opera → Préférences</em> asou roun Mac) é answit à <em>Konfidansyalité & sékrité → Éfasé data di lésplorasyon-yan → Zimaj ké fiché an kach</em>.",
        "page_first": "pronmyé",
        "page_last": "dannyé",
        "histlegend": "Sélègsyon di diff : koché bouton radjo-ya dé vèrsyon ki à konparé é apiyé asou rantré oben asou bouton-an ki anba.<br />\nLéjann : <strong>({{int:cur}})</strong> = diférans ké dannyé vèrsyon-an, <strong>({{int:last}})</strong> = diférans ké vèrsyon présédan-an, <strong>{{int:minoreditletter}}</strong> = modifikasyon minò.",
-       "history-fieldset-title": "Sasé dé révizyon",
+       "history-fieldset-title": "Filtré vèrsyon-yan",
        "histfirst": "Pli ansyenn",
        "histlast": "Pli résan-yan",
-       "historyempty": "(vid)",
+       "historyempty": "vid",
        "history-feed-title": "Listorik dé vèrsyon",
        "history-feed-description": "Listorik dé vèrsyon pou sa paj asou wiki-a",
-       "history-feed-item-nocomment": "$1 à $2",
+       "history-feed-item-nocomment": "$1  $2",
        "rev-delundel": "afiché/maské",
        "rev-showdeleted": "afiché",
        "revdelete-show-file-submit": "Enren",
        "recentchangeslinked": "Swivi di paj-ya ki yannen",
        "recentchangeslinked-feed": "Swivi di paj-ya ki yannen",
        "recentchangeslinked-toolbox": "Swivi di paj-ya ki yannen",
-       "recentchangeslinked-title": "Swivi dé paj asosyé à « $1 »",
-       "recentchangeslinked-summary": "Rantré roun non di paj pou wè modifikasyon-yan ki fè résaman asou dé paj ki lyannen dipi oben bò'd sa paj (pou wè manm-yan di roun katégori, rantré {{ns:category}}:Non di katégori). Modifikasyon-yan dé paj di [[Special:Watchlist|zòt lis di swivi]] sa <strong>an gra</strong>.",
+       "recentchangeslinked-title": "Swivi di paj-ya ki asosyé ké « $1 »",
+       "recentchangeslinked-summary": "Rantré roun non di paj pou wè modifikasyon-yan ki fèt résaman asou paj-ya ki yannen dipi oben bò'd sa paj (pou wè manm-yan di roun katégori, rantré {{ns:category}}:Non di katégori). Modifikasyon-yan di paj-ya di [[Special:Watchlist|zòt lis di swivi]] sa <strong>an gra</strong>.",
        "recentchangeslinked-page": "Non di paj :",
-       "recentchangeslinked-to": "Afiché modifikasyon-yan dé paj ki ka konpòrté roun lyannaj bò'd paj-a ki bay plito ki lenvèrs-a",
+       "recentchangeslinked-to": "Afiché modifikasyon-yan di paj-ya ki ka konpòrté roun yannaj bò'd paj-a ki bay plito ki lenvèrs-a",
        "upload": "Enpòrté roun fiché",
        "uploadlogpage": "Journal di enpo di fiché",
        "filedesc": "Dèskripsyon",
        "sharedupload-desc-here": "Sa fiché ka provini di $1. Li pouvé fika itilizé pa ròt projè.\nSo dèskripsyon asou so [$2 paj di dèskripsyon] sa afiché anba.",
        "filepage-nofile": "Pyès fiché di sa non ka ègzisté.",
        "upload-disallowed-here": "Zòt pa pouvé ranplasé sa fiché.",
-       "randompage": "Paj an azò",
+       "randompage": "Paj  azò",
        "statistics": "Èstatistik",
        "double-redirect-fixer": "Korègtò di roudirègsyon",
        "nbytes": "$1 {{PLURAL:$1|ògtè}}",
        "contribsub2": "Pou {{GENDER:$3|$1}} ($2)",
        "nocontribs": "Pyès modifikasyon korèspondan à sa kritèr trouvé.",
        "uctop": "atchwèl",
-       "month": "À partir di mwa (é présédan) :",
-       "year": "À partir di lannen (é présédant) :",
+       "month": "Apati di mwè (ké anvan) :",
+       "year": "Apati di lannen (ké anvan) :",
        "sp-contributions-newbies": "Montré ren ki kontribisyon-yan dé nouvèl itilizatò",
        "sp-contributions-blocklog": "journal dé blokaj",
        "sp-contributions-uploads": "enpòr",
        "whatlinkshere": "Paj ki yannen",
        "whatlinkshere-title": "Paj ki ka pwenté bò'd « $1 »",
        "whatlinkshere-page": "Paj :",
-       "linkshere": "Paj-ya ki anba ka kontni roun lyannaj bò'd <strong>$2</strong> :",
-       "nolinkshere": "Pyès paj ka kontni lyannaj bò'd <strong>$2</strong>.",
+       "linkshere": "Paj-ya ki anba ka kontni roun yannaj bò'd <strong>$2</strong> :",
+       "nolinkshere": "Pyès paj yannen bò'd <strong>$2</strong>.",
        "isredirect": "paj di roudirègsyon",
        "istemplate": "enklizyon",
-       "isimage": "lyannaj bò'd fiché-a",
+       "isimage": "yannaj bò'd fiché-a",
        "whatlinkshere-prev": "{{PLURAL:$1|présédant|$1 présédant}}",
        "whatlinkshere-next": "{{PLURAL:$1|swivant|$1 swivant}}",
-       "whatlinkshere-links": "← lyannaj",
+       "whatlinkshere-links": "← yannaj",
        "whatlinkshere-hideredirs": "$1 roudirègsyon-yan",
        "whatlinkshere-hidetrans": "$1 enklizyon-yan",
-       "whatlinkshere-hidelinks": "$1 lyannaj-ya",
-       "whatlinkshere-hideimages": "$1 lyannaj-ya bò'd fiché-a",
+       "whatlinkshere-hidelinks": "$1 yannaj-ya",
+       "whatlinkshere-hideimages": "$1 yannaj-ya bò'd fiché-a",
        "whatlinkshere-filters": "Filt",
        "ipboptions": "2 lò:2 hours,1 jou:1 day,3 jou:3 days,1 simenn:1 week,2 simenn:2 weeks,1 mwa:1 month,3 mwa:3 months,6 mwa:6 months,1 lan:1 year,endéfiniman:infinite",
        "infiniteblock": "enfini",
        "tooltip-pt-watchlist": "Oun lis dé paj don zòt ka swiv modifikasyon",
        "tooltip-pt-mycontris": "Oun lis di {{GENDER:|zòt}} kontribisyon",
        "tooltip-pt-login": "Nou ka ankourajé zòt à konnègté zòt kò ; soupannan, zòt pa blijé di fè li",
-       "tooltip-pt-logout": "Dékonnègté so kò",
+       "tooltip-pt-logout": "Dékonnègté sokò",
        "tooltip-pt-createaccount": "Nou ka ankourajé zòt à kréyé roun kont itilizatò é konnègté zòt kò ; soupannan, zòt pa blijé di fè li",
        "tooltip-ca-talk": "Diskisyon o sijè di sa paj di kontni",
        "tooltip-ca-edit": "Modifyé wikikod-a",
        "tooltip-n-portal": "Apropo di projè, sa ki zòt pouvé fè, koté trouvé lenfòrmasyon-yan",
        "tooltip-n-currentevents": "Trouvé plis d'enfòrmasyon asou atchwalité an kour",
        "tooltip-n-recentchanges": "Lis dé modifikasyon résan asou wiki-a",
-       "tooltip-n-randompage": "Afiché roun paj an azò",
-       "tooltip-n-help": "Aksè à lèd",
-       "tooltip-t-whatlinkshere": "Lis dé paj ki lyannen ki ka pwenté asou sala",
-       "tooltip-t-recentchangeslinked": "Lis dé modifikasyon résan ki lyannen ké sa paj",
+       "tooltip-n-randompage": "Afiché roun paj  azò",
+       "tooltip-n-help": "Laksè bò lèd-a",
+       "tooltip-t-whatlinkshere": "Lis di paj-ya ki yannen ki ka pwenté asou sala",
+       "tooltip-t-recentchangeslinked": "Lis di modifikasyon-yan ki résan ki yannen ké sa paj",
        "tooltip-feed-atom": "Flux Atom pou sa paj",
        "tooltip-t-contributions": "Wè lis dé kontribisyon di {{GENDER:$1|sa itilizatò|sa itilizatris}}",
        "tooltip-t-emailuser": "Voyé roun kourilèt pou {{GENDER:$1|sa itilizatò}}",
        "tooltip-t-upload": "Télévèrsé dé fiché",
        "tooltip-t-specialpages": "Lis di tout paj èspésyal",
-       "tooltip-t-print": "Vèrsyon enprimab di sa paj",
+       "tooltip-t-print": "Vèrsyon ki enprimab di sa paj",
        "tooltip-t-permalink": "Adrès pèrmanant di sa vèrsyon di paj-a",
        "tooltip-ca-nstab-main": "Wè kontni di paj-a",
        "tooltip-ca-nstab-user": "Wè paj di itilizatò",
index 410918c..d41c894 100644 (file)
        "tog-watchlisthideliu": "Kache modifikasyon yo ki fèt pa itilizatè yo ki enskri nan lis swivi mwen",
        "tog-watchlisthideanons": "Kache modifikasyon anònim nan lis swivi mwen",
        "tog-watchlisthidepatrolled": "Kache modifikasyon ki siveye yo nan lis swivi mwen",
+       "tog-watchlisthidecategorization": "Kache kategorizasyon paj yo",
        "tog-ccmeonemails": "Voye yon kopi imèl mwen voye ba lòt ban mwen",
        "tog-diffonly": "Pa montre enfòmasyon yon paj ki anba chanjman yo montre nan konparezon",
        "tog-showhiddencats": "Montre kategori kache yo",
        "tog-norollbackdiff": "Pa montre chanjman yo lè mwen fè yon revokasyon",
        "tog-useeditwarning": "Avèti lè m ap kite yon paj chanjman san m pa sovgade",
        "tog-prefershttps": "Toujou sèvi ak yon koneksyon sekirize lè m ap konekte",
+       "tog-showrollbackconfirmation": "Montre yon demann konfimasyon lè gen klik sou yon lyen revokasyon",
        "underline-always": "Toujou",
        "underline-never": "Jamè",
        "underline-default": "Dekorasyon ou navigatè pa defo",
        "october-date": "$1 oktòb",
        "november-date": "$1 novanm",
        "december-date": "$1 desanm",
+       "period-am": "AM",
+       "period-pm": "PM",
        "pagecategories": "{{PLURAL:$1|Kategori|Kategori yo}}",
        "category_header": "Paj yo ki nan kategori « $1 »",
        "subcategories": "Soukategori yo",
        "newwindow": "(Ouvè nan yon lòt fenèt)",
        "cancel": "Anile",
        "moredotdotdot": "Pi plis …",
-       "morenotlisted": "Lis sa a pa konplè.",
+       "morenotlisted": "Lis sa ka pa konplè.",
        "mypage": "Paj",
        "mytalk": "Diskisyon",
        "anontalk": "Diskite",
        "returnto": "Ritounen nan paj $1.",
        "tagline": "Yon atik de {{SITENAME}}.",
        "help": "Èd",
+       "help-mediawiki": "Èd konsènan MediaWiki",
        "search": "Chache",
        "searchbutton": "Fouye",
        "go": "Ale",
        "talk": "Diskisyon",
        "views": "Afichay yo",
        "toolbox": "Bwat zouti",
+       "tool-link-userrights": "Chanje {{GENDER:$1|itilizatè}} gwoup yo",
+       "tool-link-userrights-readonly": "Gade {{GENDER:$1|itilizatè}} gwoup yo",
+       "tool-link-emailuser": "Voye yon mail bay {{GENDER:$1|itilizatè }}",
        "imagepage": "Wè paj fichye",
        "mediawikipage": "Wè paj mesaj",
        "templatepage": "Wè paj modèl",
        "ok": "OK",
        "retrievedfrom": "Rekipere depi «&nbsp;$1&nbsp;»",
        "youhavenewmessages": "Ou genyen $1 ($2).",
-       "youhavenewmessagesmanyusers": "Ou gen $2 de plizyè itilizatè $2.",
+       "youhavenewmessagesmanyusers": "Ou gen $1 de plizyè itilizatè $2.",
+       "newmessageslinkplural": "{{PLURAL:$1|yon nouvo mesaj|999=nouvo mesaj yo}}",
+       "newmessagesdifflinkplural": "Dènye {{PLURAL:$1|chanjman|999=chanjman yo}}",
        "youhavenewmessagesmulti": "Ou genyen nouvo mesaj sou $1.",
        "editsection": "modifye",
        "editold": "modifye",
        "hidetoc": "kache",
        "collapsible-collapse": "Redui",
        "collapsible-expand": "Etann",
-       "confirmable-confirm": "Eske w si?",
+       "confirmable-confirm": "Eske {{GENDER:$1|w}} si?",
        "confirmable-yes": "Wi",
        "confirmable-no": "Non",
        "thisisdeleted": "Ou vle wè oubyen restore $1 ?",
        "nospecialpagetext": "<strong>Paj espesial ou demande-a envalid.</strong>\n\nOu ka jwenn yon lis paj espesial ki valid yo la [[Special:SpecialPages|{{int:specialpages}}]].",
        "error": "Erè",
        "databaseerror": "Erè nan bazdone.",
+       "databaseerror-text": "Gen yon erè rekèt bazdone ki fèt.\nSa ka endike yon erè nan lojisyèl la",
+       "databaseerror-textcl": "Yon erè rekèt bazdone fèt.",
+       "databaseerror-query": "Rekèt: $1",
+       "databaseerror-function": "Fonksyon: $1",
+       "databaseerror-error": "Erè: $1",
        "laggedslavemode": "'''Atansyon:''' paj sa a kapab pa anrejistre modifikasyon ki fèk fèt yo.",
        "readonly": "Bazdone a fèmen toutbon.",
        "enterlockreason": "Bay yon rezon pou fème bazdone a ak yon estimasyon ki lè w ap ouvri l ankò",
index f4017f4..2d675bf 100644 (file)
        "restrictionsfield-help": "Egy IP-cím vagy CIDR-tartomány soronként. Minden engedélyezéséhez használd a következő tartományokat:\n<pre>\n0.0.0.0/0\n::/0\n</pre>",
        "edit-error-short": "Hiba: $1",
        "edit-error-long": "Hibák:\n\n$1",
+       "specialmute": "Némítás",
+       "specialmute-submit": "Megerősítés",
+       "specialmute-label-mute-email": "E-mailek némítása ettől a felhasználótól",
+       "specialmute-error-invalid-user": "A kért felhasználónév nem található.",
+       "specialmute-error-email-blacklist-disabled": "Felhasználók e-mailküldési lehetőségének némítása nincs bekapcsolva.",
+       "specialmute-error-email-preferences": "Először meg kell erősítened az e-mail-címedet, mielőtt lenémíthatnál egy felhasználót. Ezt a [[Special:Preferences]] oldalon tudod megtenni.",
+       "specialmute-email-footer": "[$1 {{BIDI:$2}} e-mail beállításainak kezelése.]",
+       "specialmute-login-required": "Kérjük, jelentkezz be a némítási beállításaid módosításához.",
        "revid": "$1 változat",
        "pageid": "$1 lapazonosító",
        "interfaceadmin-info": "$1\n\nA CSS/JS/JSON lapok szerkesztéséhez szükséges jogosultság a közelmúltban elválasztásra került a <code>editinterface</code> jogtól. Amennyiben nem érted, miért látod ezt az üzenetet, [[mw:MediaWiki_1.32/interface-admin|itt tudhatsz meg többet]].",
index 63969ab..2a92a13 100644 (file)
        "history": "Historia del pagina",
        "history_short": "Historia",
        "history_small": "historia",
-       "updatedmarker": "actualisate post mi ultime visita",
+       "updatedmarker": "actualisate post tu ultime visita",
        "printableversion": "Version pro imprimer",
        "permalink": "Ligamine permanente",
        "print": "Imprimer",
index 2948200..1dd959a 100644 (file)
        "restrictionsfield-help": "Un indirizzo IP o intervallo CIDR per linea. Per consentire tutto, utilizza:<pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "Errore: $1",
        "edit-error-long": "Errori:\n\n$1",
+       "specialmute": "Muto",
+       "specialmute-submit": "Conferma",
+       "specialmute-error-invalid-user": "Impossibile trovare il nome utente richiesto.",
        "revid": "versione $1",
        "pageid": "ID della pagina $1",
        "rawhtml-notallowed": "I tag &lt;html&gt; non possono essere utilizzati al di fuori delle normali pagine.",
index ae0377a..94249e8 100644 (file)
        "restrictionsfield-help": "줄 단위의 하나의 IP 주소 또는 CIDR 대역입니다. 모든 곳에 적용하려면, 다음을 사용하세요:<pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "오류: $1",
        "edit-error-long": "오류:\n\n$1",
+       "specialmute": "알림 미표시",
+       "specialmute-success": "알림 미표시 환경 설정이 성공적으로 업데이트되었습니다. [[Special:Preferences]]에서 알림이 표시되지 않는 모든 사용자를 확인하십시오.",
+       "specialmute-submit": "확인",
+       "specialmute-label-mute-email": "이 사용자의 이메일 알림을 표시하지 않습니다",
+       "specialmute-header": "{{BIDI:[[User:$1]]}}의 알림 미표시 환경 설정을 선택해 주십시오.",
+       "specialmute-error-invalid-user": "요청한 사용자 이름을 찾을 수 없습니다.",
+       "specialmute-error-email-blacklist-disabled": "이메일 보내기로부터 사용자 알림 미표시가 활성화되어 있지 않습니다.",
+       "specialmute-error-email-preferences": "사용자의 알림을 미표시 처리하기 전에 이메일 주소를 확인해야 합니다. [[Special:Preferences]]에서 이 작업을 할 수 있습니다.",
+       "specialmute-email-footer": "[$1 {{BIDI:$2}}의 이메일 환경 설정을 관리합니다.]",
+       "specialmute-login-required": "알림 미표시 환경 설정을 변경하려면 로그인해 주십시오.",
        "revid": "$1 판",
        "pageid": "페이지 ID $1",
        "interfaceadmin-info": "$1\n\n사이트 전체에 쓰이는 CSS/JS/JSON 파일의 편집 권한이 최근 <code>editinterface</code> 권한에서 분리되었습니다. 왜 이 오류가 발생하는지 이해가 되지 않는다면, [[mw:MediaWiki_1.32/interface-admin]]을 참고하십시오.",
index 0ae2c67..d61a2e6 100644 (file)
        "restrictionsfield-label": "Zougeloossen IP-Beräicher:",
        "edit-error-short": "Feeler: $1",
        "edit-error-long": "Feeler:\n\n$1",
+       "specialmute": "Toun aus",
+       "specialmute-submit": "Confirméieren",
+       "specialmute-error-invalid-user": "De Gefrote Benotzernumm gouf net fonnt.",
        "revid": "Versioun $1",
        "gotointerwiki": "{{SITENAME}} verloossen",
        "gotointerwiki-invalid": "De spezifizéierten Titel ass net valabel.",
index dee85ef..2a90040 100644 (file)
        "post-expand-template-inclusion-warning": "زٱنڳیار چۊئٱ د ڤٱر گرتٱ ٱندازاٛ یٱ کاْ فرٱ گٱپٱ.پاراٛیؽ د چۊئٱیا ناْ د ڤٱر نماٛیرٱ.",
        "post-expand-template-inclusion-category": "بٱلگٱیا د ڤٱر گرتٱ چۊئٱ هؽسن کاْ ٱندازٱش د هٱد اومایٱ ڤ دٱر",
        "post-expand-template-argument-warning": "زٱنڳیار اؽ بٱلگٱ د ڤٱر گرتٱ هٱدٱقٱل یاٛ چۊئٱ سی چٱک چنٱ یٱ کاْ ٱندازٱ فرٱ گٱپٱ.\nگٱپسنؽا پاک بینٱ.",
-       "post-expand-template-argument-category": "بÙ\84Ú¯Ù\87 Ø¯ Ù\88ر Ú¯Ø±ØªÙ\87 Ú\86Ù\88ئÙ\87 Ú\86Ú© Ú\86Ù\86Û\8cا Ø¯ Ø¨Û\8cÙ\86 Ø±Ø¦ØªÙ\87",
-       "parser-template-loop-warning": "حلقه چوئه دیاری کرده:[[$1]]",
-       "parser-template-recursion-depth-warning": "محدÙ\88دÛ\8cت Ù¾Û\8c Û\8cا Ù\88رئشتÙ\86 Ú\86Ù\88ئÙ\87 Ø±Ø¯ Ø¨Û\8c($1)",
-       "language-converter-depth-warning": "محدÙ\88دÛ\8cت Ù¾Û\8c Û\8cا Ø²Ù\88Ù\86 Ù\88اÙ\84رÙ\86 Ø±Ø¯ Ø¨Û\8c($1)",
-       "node-count-exceeded-category": "بÙ\84Ú¯Ù\87 Û\8cا Ú©Ù\87 Ø¯ Ø¨Û\8cشرÙ\88Ù\86Ù\87 Ø´Ù\85ارÙ\87 Ú¯Ø±Ù\88 Ù\81رÙ\87 Ù¾Ø¦Ø´Ú©Ø±Ø¯ Ú©Ø±Ø¯Ù\86Ù\87",
-       "node-count-exceeded-category-desc": "زیردسه سی بلگه یایی که د ونو اشمارنه فره پئشکرد کرده.",
-       "node-count-exceeded-warning": "بÙ\84Ú¯Ù\87 Ø¯ Ø¨Û\8cشترÙ\88Ù\86Ù\87 Ø´Ù\85ارÙ\87 Ú¯Ø±Ù\88 Ù\81رÙ\87 Ù¾Ø¦شکرد کرد",
-       "expansion-depth-exceeded-category": "بÙ\84Ú¯Ù\87 Û\8cاÛ\8cÛ\8c Ú©Ù\87 Ø¯ Ø¨Û\8cشترÙ\88Ù\86Ù\87 Ù¾Û\8c Û\8cا Ù\88Ù\88Ù\84Ù\87 Ú©Ø±Ø¯Ù\86 Ù\81رÙ\87 Ù¾Ø¦Ø´Ú©Ø±Ø¯ Ú©Ø±Ø¯Ù\86Ù\87",
-       "expansion-depth-exceeded-category-desc": "زیر دسه سی بلگه یایی که د ونو پی یا ووله بیین فره پئشکرد کرده.",
-       "expansion-depth-exceeded-warning": "بÙ\84Ú¯Ù\87 Ø¯ Ù¾Û\8c Û\8cا Ù\88Ù\88Ù\84Ù\87 Ø¨Û\8cÛ\8cÙ\86 Ù¾Ø¦شکرد کرد",
-       "parser-unstrip-loop-warning": "گردوله د فرمونه Unstrip پیدا بیه",
-       "unstrip-depth-warning": "د بیشترونه د سرچشمه رئتن د دستور Unstrip واروتر رئتیته($1)",
-       "converter-manual-rule-error": "خطا د قانون والرشتن دسی زون",
-       "undo-success": "نبوئه ویرایشت نه انجومشیو بکیت.\nلطفا ای فرخی که ها د هار نه وارسی بکیت تا یه کاریه که میهات انجوم بئیت، و اوسه آلشتیا هار نه اماییه بکیت سی یه که خمثی کردن ویرایشت نه انجوم بئیت.",
+       "post-expand-template-argument-category": "بٱÙ\84Ú¯Ù± Ø¯ Ú¤Ù±Ø± Ú¯Ø±ØªÙ± Ú\86Û\8aئٱ Ú\86Ù±Ú© Ú\86Ù\86Ù± Ø¯ Ø¨Ø§Ù\9bÙ\86 Ø±Ù±ØªÙ±",
+       "parser-template-loop-warning": "هٱلقٱ چۊئٱ دؽاری کردٱ:[[$1]]",
+       "parser-template-recursion-depth-warning": "مÙ±Ù\87دÛ\8aدÛ\8cٱت Ù¾Û\8c Û\8cا Ú¤Ø±Ú¯Ù±Ø´ØªÙ\86 Ú\86Û\8aئٱ Ø±Ù±Ø¯ Ø¨Û\8c($1)",
+       "language-converter-depth-warning": "مÙ±Ù\87دÛ\8aدÛ\8cٱت Ù¾Û\8c Û\8cا Ø²Ú¤Ù\88Ý© Ú¤Ø§Ù\84Ù\9bرÙ\86 Ø±Ù±Ø¯ Ø¨Û\8c($1)",
+       "node-count-exceeded-category": "بٱÙ\84Ú¯Ù±Û\8cا Ú©Ø§Ù\92 Ø¯ Ø¨Ø½Ø´Ø±Ù\88Ù\86Ù± Ø´Ù\85ارٱ Ú¯Ø±Û\8a Ù\81رٱ Ù¾Û\8cشکرد Ú©Ø±Ø¯Ù\86Ù±",
+       "node-count-exceeded-category-desc": "زؽردٱسٱ سی بٱلگٱیایؽ کاْ د ڤنو اْشمارنٱ فرٱ پیشکرد کردٱ.",
+       "node-count-exceeded-warning": "بٱÙ\84Ú¯Ù± Ø¯ Ø¨Ø½Ø´ØªØ±Ù\88Ù\86Ù± Ø´Ù\85ارٱ Ú¯Ø±Û\8a Ù\81رٱ Ù¾Û\8cشکرد کرد",
+       "expansion-depth-exceeded-category": "بٱÙ\84Ú¯Ù±Û\8cاÛ\8cؽ Ú©Ø§Ù\92 Ø¯ Ø¨Ø½Ø´ØªØ±Ù\88Ù\86Ù± Ù¾Û\8c Û\8cا Ú¤Ù\84Ù± Ú©Ø±Ø¯Ù\86 Ù\81رٱ Ù¾Û\8cشکرد Ú©Ø±Ø¯Ù\86Ù±",
+       "expansion-depth-exceeded-category-desc": "زؽر دٱسٱ سی بٱلگٱیایؽ کاْ د ڤنو پی یا ڤلٱ بیئن فرٱ پیشکرد کردٱ.",
+       "expansion-depth-exceeded-warning": "بٱÙ\84Ú¯Ù± Ø¯ Ù¾Û\8c Û\8cا Ú¤Ù\84Ù± Ø¨Û\8cئÙ\86 Ù¾Û\8cشکرد کرد",
+       "parser-unstrip-loop-warning": "گردۊلٱ د فرمونٱ Unstrip پاٛدا بیٱ",
+       "unstrip-depth-warning": "د بؽشترونٱ د سرچشمٱ رٱتن د دٱسدۊر Unstrip ڤارۉتر رٱتؽتٱ($1)",
+       "converter-manual-rule-error": "خٱتا د قانۊن ڤالٛرشتن دٱسی زڤوݩ",
+       "undo-success": "نمۊئٱ ڤیرایش ناْ ٱنجومشیو بٱکؽت.\nلوتفٱن اؽ فٱرخؽ کاْ ها د هار ناْ ڤارسی بٱکؽت تا یاٛ کارؽ کاْ مؽهایت ٱنجوم باٛیؽت،ۉ اۊساْ آلشتؽا هار ناْآمادٱ بٱکؽت سی یٱ کاْ خونسا کردن ڤیرایش ناْ ٱنجوم باٛیؽت.",
        "undo-failure": "سی ری ڤ ری بیئن اؽ ڤیرایش ڤا ڤیرایشؽا مؽنجایی، نمۊئٱ اؽ ڤیرایش ناْ خونسا بٱکؽت.",
-       "undo-norev": "نبوئه ای ویرایشت نه خومثی بکیت سی یه که یا وجود ناره یا پاکسا بیه.",
-       "undo-nochange": "وه نظر میا که ای ویرایشت د ایسنیا خومثی بیه.",
-       "undo-summary": "Ø®Ù\88Ù\85Ø«Û\8c Ø¨Û\8cئÙ\86 Ù\88اÙ\86ئرÛ\8c Ù\88ا $1 [[Special:Contributions/$2|$2]] ([[User talk:$2|Ú\86Ú© Ú\86Ù\86Ù\87]])",
-       "undo-summary-username-hidden": "Ø®Ù\88Ù\85Ø«Û\8c Ø¨Û\8cئÙ\86 Ù\88اÙ\86ئرÛ\8c $1 Ù\88ا Û\8cÙ\87 Ú¯Ù\84 Ú©Ø§Ø±Û\8cار Ù\82اÙ\85 Ø¨Û\8cÙ\87",
-       "cantcreateaccount-text": "حساو دروس بیه و ا ای تیرنشون آی پی(<strong>$1</strong>) وه دس ای [[کاریار:$3|$3]] قلف بیه.\n\n\nدلیل دئه بیه وا $3 ها د<em>$2</em>",
+       "undo-norev": "نمۊئٱ اؽ ڤیرایش ناْ خونسا بٱکؽت سی یٱ کاْ یا ڤوجۊد نارٱ یا پاکسا بیٱ.",
+       "undo-nochange": "ڤ نٱزٱر مؽا کاْ اؽ ڤیرایش د ایسنیا خونسی بیٱ.",
+       "undo-summary": "Ø®Ù\88Ù\86سا Ø¨Û\8cئÙ\86 Ú¤Ø§Ù\86رÛ\8c Ú¤Ø§ $1 [[Special:Contributions/$2|$2]] ([[User talk:$2|Ú\86Ù±Ú© Ú\86Ù\86Ù±]])",
+       "undo-summary-username-hidden": "Ø®Ù\88Ù\86سا Ø¨Û\8cئÙ\86 Ú¤Ø§Ù\86رÛ\8c $1 Ú¤Ø§ Û\8cاÙ\9b Ú©Ø§Ø±Û\8cار Ù\82اÛ\8cÙ\85 Ø¨Û\8cÙ±",
+       "cantcreateaccount-text": "هساو دۏرس بیٱ ڤا اؽ تیرنشوݩ آی پی(<strong>$1</strong>) ڤ دٱس اؽ [[کاریار:$3|$3]] قلف بیٱ.\n\n\nدلیل دئه بیه وا $3 ها د<em>$2</em>",
        "cantcreateaccount-range-text": "حساو دروس بیه وا تیرنشون آی پی که د پوشینه <strong>$1</strong> ، که وه ئم مینونه دار تیرنشون آی پی شما ئم هئ(<strong>$4</strong>)، وه دس [[کاریار:$3|$3]]قلف بیه.\n\nدلیل دئه بیه وا $3، \"$2\" ئه.",
-       "viewpagelogs": "ساÙ\9bÙ\84Ù\9b Ù¾Ù\87رستÙ\86Ù\88Ù\85Ù±Û\8cا Ø§Ø¨ بٱلگٱ بٱکؽت",
+       "viewpagelogs": "ساÙ\9bÙ\84Ù\9b Ù¾Ù\87رستÙ\86Ù\88Ù\85Ù±Û\8cا Ø§Ø½ بٱلگٱ بٱکؽت",
        "nohistory": "هیچ ویرگار ویرایشتی د ای بلگه نئ.",
        "currentrev": "آخرین دوواره دیئن",
        "currentrev-asof": "آخری ڤانری چی $1",
        "exbeforeblank": "مینونه حالی دمایی:\"$1\" بی",
        "delete-confirm": "پاکسا کئردئن \"$1\"",
        "delete-legend": "پاکسا کئردئن",
-       "historywarning": "<strong>هشدار:</strong> بلگه یی که شما میهایت پاکساش بکیت دش یه گل ویرگارچه واگرد $1 {{PLURAL:$1|وانئری|وانئریا}} ئه:",
+       "historywarning": "<strong>هوشدار:</strong> بٱلگاٛیؽ کاْ شما مؽهایت پاکساش بٱکؽت دش یاٛ ڤیرگارچٱ ڤاگرد $1 {{PLURAL:$1|ڤانری|ڤانریا}} ئٱ:",
        "confirmdeletetext": "شما د حال و بار پاکسا کردن یه گل بلگه یا عسگ د رسینه جا واگرد همه ویرگارچه ونیت.\nلطف بکیت ای کنشتکاری نه پشت راسکاری بکیت و یه دل بوئیت که سرانجوم ای کار نه دونیت و ای کار نه مطابق وا [[{{MediaWiki:Policy-url}}|سیاستیا]] انجوم دئیته.",
        "actioncomplete": "عملكرد كامل بيه",
        "actionfailed": "عملكرد شكست حرده",
index 961f242..eb80f11 100644 (file)
        "history": "историја",
        "history_short": "Историја",
        "history_small": "историја",
-       "updatedmarker": "подновено Ð¾Ð´ Ð¼Ð¾Ñ\98ата последна посета",
+       "updatedmarker": "подновено Ð¾Ð´ Ð²Ð°Ñ\88ата последна посета",
        "printableversion": "Верзија за печатење",
        "permalink": "Постојана врска",
        "print": "Печати",
        "restrictionsfield-help": "Една IP-адреса или CIDR-опсег по ред. За да овозможите сè, користете<br /><code>0.0.0.0/0</code><br /><code>::/0</code>",
        "edit-error-short": "Грешка: $1",
        "edit-error-long": "Грешки:\n\n$1",
+       "specialmute": "Искл. известувања",
+       "specialmute-success": "Промените се успешно направени. Погледајте ги сите исклучени корисници на [[Special:Preferences]].",
+       "specialmute-submit": "Потврди",
+       "specialmute-label-mute-email": "Исклучи е-пошта од корисников",
+       "specialmute-header": "Изберете поставки за известувања од {{BIDI:[[User:$1]]}}.",
+       "specialmute-error-invalid-user": "Не можев да го најдам корисничкото име.",
+       "specialmute-error-email-blacklist-disabled": "Исклучувањето на е-пошта од корисници не е овозможено.",
+       "specialmute-error-email-preferences": "Ќе мора да ја потврдите вашата е-пошта пред да исклучите известувања од други. Тоа се прави на страницата [[Special:Preferences]].",
+       "specialmute-email-footer": "[$1 Раководење со поставки за е-пошта од {{BIDI:$2}}.]",
+       "specialmute-login-required": "Најавете се за да ги направите промените.",
        "revid": "преработка $1",
        "pageid": "назнака на страницата $1",
        "interfaceadmin-info": "$1\n\nДозволите за уредување на CSS/JS/JSON податотеки низ цело вики неодамна се одвоени од правото <code>editinterface</code>. Ако не разбирате зошто ја добивате оваа грешка, погл. [[mw:MediaWiki_1.32/interface-admin]].",
index 40e2855..8d3c9be 100644 (file)
        "restrictionsfield-help": "Een IP-adres of CIDR bereik per lijn. Om alles toe te staan, gebruik:<pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "Fout: $1",
        "edit-error-long": "Fouten:\n\n$1",
+       "specialmute": "Negeren",
+       "specialmute-success": "Het bijwerken van uw voorkeur voor het negeren is geslaagd. Bekijk een lijst met alle genegeerde gebruikers in [[Special:Preferences|uw voorkeuren]].",
+       "specialmute-submit": "Bevestig",
+       "specialmute-label-mute-email": "Negeer e-mails van deze gebruiker",
+       "specialmute-header": "Selecteer uw voorkeur voor het negeren van {{BIDI:[[User:$1]]}}.",
+       "specialmute-error-invalid-user": "De ingevoerde gebruikersnaam kon niet worden gevonden.",
+       "specialmute-error-email-blacklist-disabled": "Het negeren van e-mails verstuurd door andere gebruikers is niet ingeschakeld.",
+       "specialmute-error-email-preferences": "U moet uw e-mailadres bevestigen voordat u een gebruiker kunt negeren. U kunt dit doen in [[Special:Preferences|uw voorkeuren]].",
+       "specialmute-email-footer": "[$1 E-mail voorkeuren beheren voor {{BIDI:$2}}.]",
+       "specialmute-login-required": "U moet aanmelden om voorkeuren voor het negeren van gebruikers in te stellen.",
        "revid": "versie $1",
        "pageid": "Pagina-ID $1",
        "interfaceadmin-info": "$1\n\nRechten voor het bewerken van wikibrede CSS/JS/JSON-bestanden zijn recentelijk gescheiden van het <code>editinterface</code> recht. Als u niet begrijpt waarom u deze foutmelding te zien krijgt, ga dan naar [[mw:MediaWiki_1.32/interface-admin]].",
index 3eb72a5..d2d6457 100644 (file)
        "right-move-categorypages": "ߦߌߟߡߊ߫ ߞߐߜߍ ߟߎ߬ ߛߋ߲߬ߓߐ߫",
        "right-movefile": "ߞߐߕߐ߮ ߟߎ߬ ߛߋ߲߬ߓߐ߫",
        "right-upload": "ߞߐߕߐ߮ ߟߎ߬ ߟߊߦߟߍ߬",
+       "right-reupload": "ߛߋ߲߬ߠߊ߬ ߞߐߕߐ߮ ߖߏ߬ߛߌ߬",
+       "right-reupload-own": "ߌ ߖߍ߬ߘߍ ߟߊ߫ ߞߐߕߐ߯ ߟߊߦߟߍ߬ߣߍ߲ ߠߎ߬ ߖߏ߰ߛߌ߬",
+       "right-upload_by_url": "ߞߐߕߐ߮ ߘߏ߫ ߟߊߦߟߍ߬ ߞߊ߬ ߓߐ߫ URL ߘߐ߫",
        "right-writeapi": "ߛߓߍߟߌ API ߟߊߓߊ߯ߙߊ߫",
        "right-delete": "ߞߐߜߍ ߟߎ߬ ߖߏ߰ߛߌ߬",
        "right-bigdelete": "ߞߐߜߍ߫ ߘߝߐ߬ ߓߟߋ߬ߓߟߋ߬ߡߊ ߟߎ߬ ߖߏ߰ߛߌ߬",
        "action-editmyuserjson": "ߌ ߖߘߍ߬ߞߊ߬ߣߌ߲߬ JSON ߞߐߕߐ߮ ߟߎ߬ ߡߊߦߟߍ߬ߡߊ߲߫",
        "action-editmyuserjs": "ߌ ߖߘߍ߬ߞߊ߬ߣߌ߲߬ JavaScript ߞߐߕߐ߮ ߟߎ߬ ߡߊߦߟߍ߬ߡߊ߲߫",
        "action-viewsuppressed": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߘߏ ߟߎ߬ ߟߊ߫ ߟߢߊ߬ߟߌ߬ ߢߡߊߘߏ߲߰ߣߍ߲ ߠߎ߬ ߦߋ߫",
+       "action-unblockself": "ߌ ߖߍ߬ߘߍ ߓߊ߬ߟߌ߬ߣߍ߲ ߓߐ߫",
+       "nchanges": "$1 {{PLURAL:$1|ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲|ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߠߎ߬}}",
+       "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ߞߊ߬ߦߌ߯ ߓߐߒߡߊߟߌ ߟߊߓߊ߲}}",
        "enhancedrc-history": "ߕߊ߬ߡߌ߲߬ߣߍ߲",
        "recentchanges": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߎߘߊ ߟߎ߬",
        "recentchanges-legend": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߎߘߊ ߟߎ߫ ߟߊ߬ߓߍ߲߬ߢߐ߰ߡߦߊ߬ߘߊ",
        "recentchanges-summary": "ߥߞߌ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߎ߲ߓߊ ߡߍ߲ ߠߎ߬ ߞߍߣߍ߲߫ ߞߐߜߍ ߣߌ߲߬ ߞߊ߲߬߸ ߏ߬ ߟߎ߫ ߣߐ߬ߣߐ߬.",
        "recentchanges-noresult": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߬ ߛߌ߫ ߓߍ߲߬ߢߐ߲߰ߦߊ߬ߣߍ߲߬ ߕߍ߫ ߛߎߡߊ߲ߡߕߊ ߢߌ߲߬ ߠߎ߫ ߡߊ߬ ߕߎ߬ߡߊ߬ ߟߊߕߍ߰ߣߍ߲ ߦߌ߬ߘߊ ߘߐ߫.",
+       "recentchanges-timeout": "ߢߌߣߌ߲ߣߌ߲ ߣߌ߲߬ ߕߎ߬ߡߊ ߓߘߊ߫ ߕߊ߬ߡߌ߲߬. ߌ ߞߊߞߊ߲߫ ߞߊ߬ ߢߊߢߌߣߌ߲߫ ߜߘߍ߫ ߟߊ߬ߓߍ߲߬ߢߐ߲߰ߡߊ ߞߍ߫.",
+       "recentchanges-network": "ߞߊ߬ ߓߍ߲߬ ߛߋߒߞߏߟߦߊ ߝߎ߬ߕߎ߲߬ߕߌ ߡߊ߬߸ ߞߐߝߟߌ߫ ߛߌ߫ ߕߍ߫ ߣߊ߬ ߛߋ߫ ߟߊ߫ ߟߊߢߎ߲߫ ߠߊ߫. ߌ ߞߊߘߊ߲߫ ߞߊ߬ ߞߐߜߍ ߣߌ߲߬ ߠߊߛߎߡߦߊ߫ ߖߊ߰ߣߌ߲߫.",
+       "recentchanges-notargetpage": "ߞߐߜߍ ߕߐ߮ ߟߊߘߏ߲߬ ߛߊ߲ߝߍ߬߸ ߦߟߍ߬ߡߊ߲ ߡߍ߲ ߦߋ߫ ߞߐߜߍ ߘߐ߫߸ ߞߵߏ߬ ߦߋ߫.",
        "recentchanges-label-newpage": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߣߌ߲߬ ߓߘߊ߫ ߘߐߜߍ߫ ߞߎߘߊ ߟߊߘߊ߲߫",
        "recentchanges-label-minor": "ߢߟߊߞߎߘߦߊ߫ ߝߕߌߣߍ߲ ߠߋ߬",
        "recentchanges-label-bot": "ߡߐ߰ߡߐ߮ ߟߋ߫ ߣߐ߬ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ ߣߌ߲߬ ߞߍ߫ ߟߊ߫",
        "rcfilters-quickfilters": "ߞߎ߲߬ߕߐ߰ ߟߊߞߎ߲߬ߘߎ߬ߣߍ߲ ߠߎ߬",
        "rcfilters-quickfilters-placeholder-title": "ߛߌ߲ߘߌߣߍ߲ ߟߊߞߎ߲߬ߘߎ߬ߣߍ߲߬ ߕߍ߫ ߡߎߣߎ߲߬",
        "rcfilters-savedqueries-defaultlabel": "ߞߎ߲߬ߕߐ߰ ߟߊߞߎ߲߬ߘߎ߬ߣߍ߲ ߠߎ߬",
+       "rcfilters-savedqueries-rename": "ߊ߬ ߕߐ߯ߟߊ߫",
+       "rcfilters-savedqueries-setdefault": "ߊ߬ ߞߍ߫ ߓߐߛߎ߲ ߘߌ߫",
+       "rcfilters-savedqueries-unsetdefault": "ߊ߬ ߓߐ߫ ߓߐߛߎ߲ ߘߐ߫",
+       "rcfilters-savedqueries-remove": "ߊ߬ ߖߏ߰ߛߌ߬",
+       "rcfilters-savedqueries-new-name-label": "ߕߐ߮",
+       "rcfilters-savedqueries-cancel-label": "ߊ߬ ߘߐߛߊ߬",
+       "rcfilters-filterlist-whatsthis": "ߣߌ߲߬ ߦߋ߫ ߓߊ߯ߙߊ߫ ߟߊ߫ ߘߌ߬؟",
+       "rcfilters-highlightbutton-title": "ߞߐߝߟߌ߫ ߡߊߦߋߙߋ߲ߣߍ߲ ߠߎ߬",
+       "rcfilters-highlightmenu-title": "ߞߐ߬ߟߐ ߘߏ߫ ߓߊߓߌ߬ߟߊ߬",
+       "rcfilters-filter-editsbyself-label": "ߡߍ߲ ߠߎ߬ ߡߊߦߟߍ߬ߡߊ߲߬ߣߍ߲߬ ߌ ߓߟߏ߫",
+       "rcfilters-filter-editsbyself-description": "ߌ ߖߘߍ߬ߞߊ߬ߣߌ߲߬ ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲.",
+       "rcfilters-filter-editsbyother-label": "ߘߏ ߟߎ߬ ߟߊ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߠߎ߬",
+       "rcfilters-filter-editsbyother-description": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߓߍ߯ ߝߴߌ ߕߊ ߟߎ߬.",
+       "rcfilters-filter-user-experience-level-registered-label": "ߕߐ߯ߛߓߍߣߍ߲",
+       "rcfilters-filter-user-experience-level-registered-description": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߊ߫ ߜߊ߲߬ߞߎ߲߬ߣߍ߲ ߠߎ߬",
+       "rcfilters-filter-user-experience-level-unregistered-label": "ߕߐ߯ߛߓߍߓߊߟߌ",
+       "rcfilters-filter-user-experience-level-unregistered-description": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߊ ߡߍ߲ ߜߊ߲߬ߞߎ߲߬ߣߍ߲߬ ߕߍ߫.",
        "rcfilters-filter-user-experience-level-learner-label": "ߞߊ߬ߙߊ߲߬ߠߊ ߟߎ߬",
+       "rcfilters-filter-bots-label": "ߓߏߕ",
+       "rcfilters-filter-bots-description": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߡߍ߲ ߠߎ߬ ߛߌ߲ߘߌߣߍ߲߫ ߞߍߒߖߘߍߦߋ߫ ߖߐ߯ߙߊ߲ ߠߎ߬ ߘߐ߫.",
+       "rcfilters-filter-humans-label": "ߡߐ߱ (ߓߏߕ  ߕߍ߫)",
+       "rcfilters-filter-humans-description": "ߡߐ߱ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߊ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ ߣߐ.",
+       "rcfilters-filter-reviewstatus-unpatrolled-label": "ߓߍ߬ߙߍ߲߬ߓߍ߬ߙߍ߲߬ߓߊߟߌ",
+       "rcfilters-filter-minor-label": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߘߋ߬ߣߍ߲ ߠߎ߬",
        "rcfilters-filtergroup-watchlist": "ߜߋ߬ߟߎ߲߬ߠߌ߲߬ ߛߙߍߘߍ ߞߐߜߍ ߟߎ߬",
        "rcfilters-filter-watchlist-watched-label": "ߜߋ߬ߟߎ߲߬ߠߌ߲߬ ߛߙߍߘߍ ߘߐ߫",
+       "rcfilters-filtergroup-changetype": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߛߎ߯ߦߊ",
+       "rcfilters-filter-pageedits-label": "ߞߐߜߐ ߡߊߦߟߍ߬ߡߊ߲߫",
+       "rcfilters-filter-pageedits-description": "ߞߐߜߍ ߛߌ߲ߘߟߌ",
+       "rcfilters-filter-newpages-label": "ߞߐߜߍ ߛߌ߲ߘߟߌ",
+       "rcfilters-filter-newpages-description": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߡߍ߲ ߠߎ߬ ߦߋ߫ ߞߐߜߍ߫ ߞߎߘߊ߫ ߟߊߘߊ߲߫ ߠߊ߫.",
+       "rcfilters-filter-categorization-label": "ߦߌߟߡߊ߫ ߡߊߦߟߍߡߊ߲",
+       "rcfilters-target-page-placeholder": "ߞߐߜߍ ߕߐ߮ ߟߊߘߏ߲߬ (ߥߟߊ߫ ߦߌߟߡߊ)",
        "rcnotefrom": "ߘߎ߰ߟߊ ߘߐ߫ {{PLURAL:$5|is the change|are the changes}} ߞߊ߬ߦߌ߯ <strong>$3, $4</strong> (up to <strong>$1</strong> shown).",
+       "rclistfromreset": "ߞߐߜߍ ߓߊߕߐߡߐ߲ߠߌ߲ ߡߊߦߟߍ߬ߡߊ߲߫",
        "rclistfrom": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߎߘߊ ߟߎ߫ ߦߌ߬ߘߊ ߘߊߡߌ߬ߣߊ߬ ߣߌ߲߭ ߡߊ߬ $2, $3",
        "rcshowhideminor": "$1 ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߘߋ߬ߣߍ߲",
        "rcshowhideminor-show": "ߊ߬ ߦߌ߬ߘߊ߬",
        "rcshowhideanons-show": "ߦߌ߬ߘߊ߬ߟߌ",
        "rcshowhideanons-hide": "ߊ߬ ߢߡߊߘߏ߲߰",
        "rcshowhidepatr": "$1 ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ߣߍ߲߫ ߞߣߐ߬ߜߍ߲߬ߣߍ߲ ߠߎ߬",
+       "rcshowhidepatr-show": "ߊ߬ ߦߌ߬ߘߊ߬",
+       "rcshowhidepatr-hide": "ߊ߬ ߢߡߊߘߏ߲߰",
        "rcshowhidemine": "ߒ ߠߊ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߣߍ߲ ߠߎ߬ $1",
        "rcshowhidemine-show": "ߊ߬ ߦߌ߬ߘߊ߬",
        "rcshowhidemine-hide": "ߊ߬ ߦߡߊߘߏ߲߰",
+       "rcshowhidecategorization": "$1 ߞߐߜߍ ߦߌߟߡߊߦߊߟߌ",
+       "rcshowhidecategorization-show": "ߊ߬ ߦߌ߬ߘߊ߬",
+       "rcshowhidecategorization-hide": "ߊ߬ ߢߡߊߘߏ߲߰",
        "rclinks": "ߕߋ߬ߟߋ $2 ߕߊ߬ߡߌ߲߬ߣߍ߲ ߣߌ߲߬ ߡߝߊ߬ߟߋ߲߬ߠߌ߲߬ ߟߊ߬ߓߊ߲ $1 ߦߌ߬ߘߊ߬",
        "diff": "ߝߘߏ߬ߢߐ߲߰ߡߊ",
        "hist": "ߞߊ߬ߞߘߐ",
        "newpageletter": "ߞ",
        "boteditletter": "ߓ",
        "rc-change-size-new": "$1 {{PLURAL:$1|ߝߌ߬ߘߊ߲|ߝߌ߬ߘߊ߲ ߠߎ߬}} ߢߟߊߞߎߘߦߊ ߞߐ߫",
+       "newsectionsummary": "/* $1 */ ߞߣߐߘߐ߫ ߞߎߘߊ߫",
+       "rc-enhanced-expand": "ߝߊߙߊ߲ߝߊ߯ߛߌ ߟߎ߬ ߦߌ߬ߘߊ߬",
+       "rc-enhanced-hide": "ߝߊߙߊ߲ߝߊ߯ߛߌ ߟߎ߬ ߢߡߊߘߏ߲߰",
        "rc-old-title": "ߊ߬ ߓߊߞߘߐ ߟߊߘߊ߲߫ ߣߍ߲߫ ߦߋ߫ ߕߊ߲߬ ߠߋ߫ \"$1\"",
        "recentchangeslinked": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߜߋ߲߬ߞߘߎ߬ߢߐ߲߰ߡߊ ߟߎ߬",
        "recentchangeslinked-toolbox": "ߢߟߊߞߎߘߦߊߟߌ߫ ߜߋ߲߬ߞߘߎ߬ߡߊ ߟߎ߬",
        "recentchangeslinked-page": "ߞߐߜߍ ߕߐ߮:",
        "recentchangeslinked-to": "ߞߐߜߍ ߛߘߌ߬ߜߋ߲ ߠߎ߬ ߦߌ߬ߘߊ߬߸ ߞߊ߬ ߞߐߜߍ ߣߌ߬ ߞߋߟߋ߲ߘߌ߫",
        "upload": "ߞߐߕߐ߮ ߟߊߦߟߍ",
+       "uploadbtn": "ߞߐߕߐ߮ ߟߊߦߟߍ߬",
        "uploadlogpage": "ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߘߏ߫ ߟߊߦߟߍ߬",
        "filename": "ߞߐߕߐ߮ ߕߐ߮",
        "filedesc": "ߟߊߘߛߏߣߍ߲",
index 6a3e2c0..6cac408 100644 (file)
        "restrictionsfield-help": "Jeden adres IP lub zakres CIDR w wierszu. Aby zaznaczyć wszystkie, użyj:<pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "Błąd: $1",
        "edit-error-long": "Błędy:\n\n$1",
+       "specialmute": "Ignoruj",
+       "specialmute-success": "Twoje preferencje ignorowania zostały pomyślnie zaktualizowane. Zobacz wszystkich ignorowanych użytkowników w [[Special:Preferences|preferencjach]].",
+       "specialmute-submit": "Potwierdź",
+       "specialmute-label-mute-email": "Ignoruj e-maile od tego użytkownika",
+       "specialmute-header": "Wybierz swoje preferencje ignorowania dla {{BIDI:[[User:$1]]}}.",
+       "specialmute-error-invalid-user": "Pożądana nazwa użytkownika nie została odnaleziona.",
+       "specialmute-error-email-blacklist-disabled": "Ignorowanie e-maili od użytkowników nie jest włączone.",
+       "specialmute-error-email-preferences": "Musisz potwierdzić swój adres e-mail zanim będziesz {{GENDER:|mógł|mogła}} ignorować użytkownika. Możesz to zrobić w [[Special:Preferences|preferencjach]].",
+       "specialmute-email-footer": "[$1 Zarządzaj preferencjami ignorowania dla {{BIDI:$2}}.]",
+       "specialmute-login-required": "Zaloguj się, aby zmienić swoje preferencje wyignorowania.",
        "revid": "wersja $1",
        "pageid": "ID strony: $1",
        "interfaceadmin-info": "$1\n\nUprawnienia do edycji plików CSS/JS/JSON całej witryny zostały wydzielone z dotychczasowego uprawnienia <code>editinterface</code>. Jeżeli nie rozumiesz, dlaczego otrzymujesz ten komunikat, przeczytaj [[mw:MediaWiki_1.32/interface-admin]].",
index bc6aaa6..175e0b4 100644 (file)
        "restrictionsfield-help": "Um endereço IP ou intervalo CIDR por linha. Para ativar tudo, use\n<pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "Erro: $1",
        "edit-error-long": "Erros:\n$1",
+       "specialmute": "Silenciar",
+       "specialmute-success": "Suas preferências de silêncio foram atualizadas com sucesso. Ver todos os usuários silenciados em [[Special:Preferences]].",
+       "specialmute-submit": "Confirmar",
+       "specialmute-label-mute-email": "Silenciar e-mails deste usuário",
+       "specialmute-header": "Por favor, selecione suas preferências de mudo para {{BIDI:[[User:$1]]}}.",
+       "specialmute-error-invalid-user": "O nome de usuário solicitado não foi encontrado.",
+       "specialmute-error-email-blacklist-disabled": "O silenciamento de usuários do envio de e-mails não está ativado.",
+       "specialmute-error-email-preferences": "Você deve confirmar seu endereço de e-mail antes de poder silenciar um usuário. Você pode fazer isso de [[Special:Preferences]].",
+       "specialmute-email-footer": "[$1 Gerenciar preferências de email para {{BIDI:$2}}.]",
+       "specialmute-login-required": "Por favor, entre para alterar suas preferências de mudo.",
        "revid": "revisão $1",
        "pageid": "ID da página $1",
        "interfaceadmin-info": "$1\n\nAs permissões para edição de arquivos CSS/JS/JSON em todo o site foram separadas recentemente do direito <code>editinterface</code>. Se você não entende porque está recebendo este erro, veja [[mw:MediaWiki_1.32/interface-admin]].",
index 507bbfd..63ff375 100644 (file)
        "restrictionsfield-help": "Placeholder text displayed in restriction fields (e.g. on Special:BotPassword).",
        "edit-error-short": "Error message. Parameters:\n* $1 - the error details\nSee also:\n* {{msg-mw|edit-error-long}}\n{{Identical|Error}}",
        "edit-error-long": "Error message. Parameters:\n* $1 - the error details\nSee also:\n* {{msg-mw|edit-error-short}}\n{{Identical|Error}}",
+       "specialmute": "The name of the special page [[Special:Mute]].",
+       "specialmute-success": "The content of [[Special:Mute]] with a successful message indicating that your mute preferences have been updated after the form has been submitted.",
+       "specialmute-submit": "Submit button on [[Special:Mute]] form.\n{{Identical|Confirm}}",
+       "specialmute-label-mute-email": "Label for the checkbox that mutes/unmutes emails from the specified user.",
+       "specialmute-header": "Used as header text on [[Special:Mute]]. Shown before the form with the muting options.\n* $1 - User selected for muting",
+       "specialmute-error-invalid-user": "Error displayed when the username cannot be found.",
+       "specialmute-error-email-blacklist-disabled": "Error displayed when email blacklist is not enabled.",
+       "specialmute-error-email-preferences": "Error displayed when the user has not confirmed their email address.",
+       "specialmute-email-footer": "Email footer linking to [[Special:Mute]] preselecting the sender to manage muting options.\n* $1 - Url linking to [[Special:Mute]].\n* $2 - The user sending the email.",
+       "specialmute-login-required": "Error displayed when a user tries to access [[Special:Mute]] before logging in.",
        "revid": "Used to format a revision ID number in text. Parameters:\n* $1 - Revision ID number.\n{{Identical|Revision}}",
        "pageid": "Used to format a page ID number in text. Parameters:\n* $1 - Page ID number.",
        "interfaceadmin-info": "Part of the error message shown when someone with the <code>editinterface</code> right but without the appropriate <code>editsite*</code> right tries to edit a sitewide CSS/JSON/JS page.",
index f6c23c6..cdf5c9c 100644 (file)
        "virus-scanfailed": "condrolle fallite (codece $1)",
        "virus-unknownscanner": "antivirus scanusciute:",
        "logouttext": "'''Tu tè scollegate.'''\n\nNote Bbuene ca certe pàggene ponne condinuà a essere viste cumme ce tu ste angore collegate, fine a quanne a cache d'u browser no se sdevache.",
+       "logging-out-notify": "Ste isse, aspitte.",
        "logout-failed": "Non ge puè assè mò: $1",
        "cannotlogoutnow-title": "Non ge puè assè mò",
        "cannotlogoutnow-text": "Non ge puè assè quanne ste ause $1.",
        "uploadstash-bad-path-unknown-type": "Tipe scanusciute \"$1\".",
        "uploadstash-bad-path-unrecognized-thumb-name": "Nome d'a miniature non acchiate.",
        "uploadstash-bad-path-bad-format": "'A chiave \"$1\" non ge ste jndr'à 'nu formate appropriate.",
+       "uploadstash-file-not-found-no-thumb": "No ge se pò avè 'a miniature.",
+       "uploadstash-file-not-found-no-local-path": "Nisciune percorse locale pa vôsce in scale.",
+       "uploadstash-file-not-found-no-object": "Non ge pozze ccrejà 'nu oggette file locale pa miniature.",
+       "uploadstash-file-not-found-no-remote-thumb": "Recupere d'a miniature schiute a male: $1\nURL = $2",
        "uploadstash-no-extension": "L'estenzione jè vacande.",
        "uploadstash-zero-length": "'U file tène lunghezze zero.",
        "invalid-chunk-offset": "distanze d'u chunk invalide",
        "blocklist-userblocks": "Scunne le blocche sus a le cunde de l'utinde",
        "blocklist-tempblocks": "Scunne le blocche temboranèe",
        "blocklist-addressblocks": "Scunne le blocche de le IP singole",
+       "blocklist-type": "Tipe:",
+       "blocklist-type-opt-all": "Tutte",
+       "blocklist-type-opt-sitewide": "Tutte 'u site",
+       "blocklist-type-opt-partial": "Parziale",
        "blocklist-rangeblocks": "Scunne le indervalle de blocche",
        "blocklist-timestamp": "Orarie de stambe",
        "blocklist-target": "Destinazione",
        "blocklink": "blocche",
        "unblocklink": "sblocche",
        "change-blocklink": "cange 'u blocche",
+       "empty-username": "(nisciune nome utende disponibbele)",
        "contribslink": "condrebbute",
        "emaillink": "manne 'n'e-mail",
        "autoblocker": "Autobloccate purcè l'indirizze IP tune ha state ausate urtemamende da \"[[User:$1|$1]]\".\n'U mutive date pu blocche de $1 ète \"$2\"",
        "block-log-flags-hiddenname": "nome de l'utende scunnute",
        "range_block_disabled": "L'abbilità de le amministrature de ccrejà blocche a indervalle jè disabbilitate.",
        "ipb_expiry_invalid": "L'orarije de scadenze non g'è valide.",
+       "ipb_expiry_old": "L'ore de scadenza jè jndr'à 'u passate.",
        "ipb_expiry_temp": "Le blocche sus a le nome de l'utinde scunnute onna essere permanende.",
        "ipb_hide_invalid": "Non ge se pò scangellà stu cunde utende; tène cchiù de troppe  {{PLURAL:$1|'nu cangiamede|$1 cangiaminde}}.",
        "ipb_already_blocked": "\"$1\" jè ggià blocchete",
        "linkaccounts-submit": "Colleghe le cunde",
        "unlinkaccounts": "Scolleghe le cunde",
        "unlinkaccounts-success": "'U cunde ha state scollegate.",
+       "specialmute": "Citte",
+       "specialmute-submit": "Conferme",
+       "specialmute-error-invalid-user": "'U nome utende rechieste non g'è state acchiate.",
        "revid": "revisione $1",
        "pageid": "ID d'a pàgene $1",
        "rawhtml-notallowed": "Le tag &lt;html&gt; non ge ponne essere ausate fore da le pàggene normale.",
        "gotointerwiki-invalid": "'U titole specificate non g'è valide.",
        "pagedata-bad-title": "Titole invalide: $1.",
        "passwordpolicies-group": "Gruppe",
-       "passwordpolicies-policies": "Politeche"
+       "passwordpolicies-policies": "Politeche",
+       "userlogout-continue": "Vue ccù isse?"
 }
index fa38c4f..7136fb7 100644 (file)
        "history": "История",
        "history_short": "История",
        "history_small": "история",
-       "updatedmarker": "обновлено Ð¿Ð¾Ñ\81ле Ð¼Ð¾его последнего посещения",
+       "updatedmarker": "обновлено Ð¿Ð¾Ñ\81ле Ð²Ð°Ñ\88его последнего посещения",
        "printableversion": "Версия для печати",
        "permalink": "Постоянная ссылка",
        "print": "Печать",
        "restrictionsfield-help": "По одному IP-адресу или CIDR-диапазону в строке. Чтобы разрешить всё, используйте:<pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "Ошибка: $1",
        "edit-error-long": "Ошибки:\n\n$1",
+       "specialmute": "Откл. уведомления",
+       "specialmute-success": "Изменения были успешно сделаны. Просмотрите всех отключённых участников на [[Special:Preferences]].",
+       "specialmute-submit": "Подтвердить",
+       "specialmute-label-mute-email": "Отключить эл. почту от этого участника",
+       "specialmute-header": "Пожалуйста, выберите настройки уведомлений от {{BIDI:[[User:$1]]}}.",
+       "specialmute-error-invalid-user": "Указанное вами имя участника не может быть найдено.",
+       "specialmute-error-email-preferences": "Вы должны подтвердить вашу электронную почту, прежде чем отключить уведомление от других. Это можно сделать на странице [[Special:Preferences]].",
+       "specialmute-email-footer": "[$1 Управление настройками эл. почты для {{BIDI:$2}}.]",
+       "specialmute-login-required": "Пожалуйста, войдите, чтобы совершить изменения.",
        "revid": "версия $1",
        "pageid": "ID страницы $1",
        "interfaceadmin-info": "$1\n\nПрава на редактирование общесайтных CSS/JS/JSON-файлов были недавно вынесены из права <code>editinterface</code>. Если вы не понимаете, почему вы наткнулись на эту ошибку, см. [[mw:MediaWiki_1.32/interface-admin]].",
index fb724c4..48fcb81 100644 (file)
        "restrictionsfield-help": "Jedna IP-adresa ili CIDR-opseg po redu. Da omogućite sve, koristite<br /><code>0.0.0.0/0</code><br /><code>::/0</code>",
        "edit-error-short": "Greška: $1",
        "edit-error-long": "Greške:\n\n$1",
+       "specialmute": "Iskl. obavještenja",
+       "specialmute-success": "Promjene su uspješno napravljene. Pogledajte sve isključene korisnike na [[Special:Preferences]].",
+       "specialmute-submit": "Potvrdi / Потврди",
+       "specialmute-label-mute-email": "Isključi e-poštu od ovog korisnika",
+       "specialmute-header": "Izaberite postavke za obavještenja od {{BIDI:[[User:$1]]}}.",
+       "specialmute-error-invalid-user": "Nisam mogao naći korisničko ime.",
+       "specialmute-error-email-blacklist-disabled": "Isključavanje e-pošte od korisnika nije omogućeno.",
+       "specialmute-error-email-preferences": "Morat ćete potvrditi svoju e-poštu prije isključivanja obavijesti od drugih. To je učinjeno na stranici [[Special:Preferences]].",
+       "specialmute-email-footer": "[$1 Upravljanje postavkama e-pošte od {{BIDI:$2}}.]",
+       "specialmute-login-required": "Molimo Vas prijavite se da biste napravili promjene.",
        "revid": "izmjena $1",
        "pageid": "ID stranice $1",
        "interfaceadmin-info": "$1\n\nDozvole za uređivanje CSS/JS/JSON datoteka preko cijelog wikija nedavno su odvojene od prava <code>editinterface</code>. Ako ne razumijete zašto ste dobili ovu grešku, pogl. [[mw:MediaWiki_1.32/interface-admin]].",
index 7158abb..6a68b4a 100644 (file)
        "history": "Sayfa geçmişi",
        "history_short": "Geçmiş",
        "history_small": "geçmiş",
-       "updatedmarker": "son ziyaretimden sonra güncellenmiş",
+       "updatedmarker": "son ziyaretinizden bu yana güncellendi",
        "printableversion": "Yazdırılabilir sürüm",
        "permalink": "Kalıcı bağlantı",
        "print": "Yazdır",
        "revision-info": "$2 tarafından oluşturulmuş $1 tarihli sürüm $7",
        "previousrevision": "← Önceki hâli",
        "nextrevision": "Sonraki hâli →",
-       "currentrevisionlink": "En güncel hâli",
+       "currentrevisionlink": "Güncel sürüm",
        "cur": "gün",
        "next": "sonraki",
        "last": "son",
        "page_first": "ilk",
        "page_last": "son",
        "histlegend": "Fark seçimi: Karşılaştırmayı istediğiniz 2 sürümün önündeki daireleri işaretleyip, \"{{int:Compareselectedversions}}\" düğmesine basın.<br />\nTanımlar: '''({{int:cur}})''' = son revizyon ile arasındaki fark, '''({{int:last}})''' = bir önceki revizyon ile arasındaki fark, '''{{int:minoreditletter}}''' = küçük değişiklik.",
-       "history-fieldset-title": "Sürümleri filtrele",
+       "history-fieldset-title": "Revizyonları filtrele",
        "history-show-deleted": "Sadece silinen sürümler",
        "histfirst": "en eski",
        "histlast": "en yeni",
        "action-ipblock-exempt": "IP engellemelerini, otomatik engellemelerini ve aralık engellemelerini atla",
        "action-unblockself": "kendi engellini kaldır",
        "action-noratelimit": "derecelendirme sınırlamalarından etkilenme",
+       "action-reupload-own": "kendisi tarafından yüklenen mevcut dosyaların üzerine yaz",
+       "action-nominornewtalk": "kullanıcı tartışma sayfalarında yaptığı küçük değişiklikler kullanıcıya yeni mesaj bildirimiyle bildirilmez",
+       "action-markbotedits": "geri döndürülen değişikliklerini bot değişiklikleri olarak işaretle",
+       "action-patrolmarks": "son değişiklikler gözleme işaretlerini gör",
+       "action-override-export-depth": "sayfaları, derinlik 5'e kadar bağlantılı sayfalarla beraber dışa aktar",
+       "action-suppressredirect": "sayfaları taşırken kaynak sayfalardan yönlendirmeler oluşturma",
        "nchanges": "$1 {{PLURAL:$1|değişiklik|değişiklik}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|son ziyaretten bu yana}}",
        "enhancedrc-history": "geçmiş",
        "rcfilters-filter-categorization-description": "Kategorilere eklenen veya kaldırılan sayfaların kayıtları.",
        "rcfilters-filter-logactions-label": "Günlüğü tutulan işlemler",
        "rcfilters-filter-logactions-description": "Hizmetli işlemleri, hesap oluşturmalar, sayfa silmeler, yüklemeler...",
-       "rcfilters-filtergroup-lastrevision": "En son sürümler",
+       "rcfilters-hideminor-conflicts-typeofchange-global": "\"Küçük değişiklikler\" filtresi, bir veya daha fazla değişiklik türü filtresiyle çakışıyor çünkü belirli değişiklik türleri \"küçük\" olarak belirlenemez. Çakışan filtreler yukarıdaki Aktif filtreler alanında işaretlenmiştir.",
+       "rcfilters-hideminor-conflicts-typeofchange": "Bazı değişiklik türleri \"küçük\" olarak belirlenemez, bu nedenle bu filtre şu değişiklik filtreleriyle çakışıyor: $1",
+       "rcfilters-typeofchange-conflicts-hideminor": "Bu değişiklik filtresi \"Küçük değişiklikler\" filtresiyle çakışıyor. Bazı değişiklik türleri \"küçük\" olarak tanımlanamaz.",
+       "rcfilters-filtergroup-lastrevision": "Güncel sürümler",
        "rcfilters-filter-lastrevision-label": "Son revizyon",
        "rcfilters-filter-lastrevision-description": "Bir sayfadaki en yeni değişiklik.",
-       "rcfilters-filter-previousrevision-label": "Son revizyon değil",
+       "rcfilters-filter-previousrevision-label": "Güncel sürüm değil",
+       "rcfilters-filter-previousrevision-description": "\"Güncel sürüm\" olmayan tüm değişiklikler",
        "rcfilters-filter-excluded": "Hariç",
+       "rcfilters-tag-prefix-namespace-inverted": "<strong>:not</strong> $1</strong>",
        "rcfilters-exclude-button-off": "Seçileni hariç tut",
        "rcfilters-exclude-button-on": "Seçilen hariç",
        "rcfilters-view-tags": "Etiketli düzenlemeler",
        "recentchangeslinked-page": "Sayfa adı:",
        "recentchangeslinked-to": "Belirtilen sayfadan verilenler yerine, sayfaya verilen bağlantıları göster.",
        "recentchanges-page-added-to-category": "[[:$1]] kategoriye eklendi",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] kategoriye eklendi,  [[Special:WhatLinksHere/$1|bu sayfa diğer sayfalara dahil edildi]]",
        "recentchanges-page-removed-from-category": "[[:$1]] kategoriden çıkarıldı",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] kategoriden kaldırıldı, [[Special:WhatLinksHere/$1|bu sayfa diğer sayfalara dahil edildi]]",
        "autochange-username": "MediaWiki otomatik değişimi",
        "upload": "Dosya yükle",
        "uploadbtn": "Dosya yükle",
        "reuploaddesc": "Yükleme formuna geri dön.",
        "upload-tryagain": "Değiştirilmiş dosya açıklamasını gönder",
+       "upload-tryagain-nostash": "Yeniden yüklenen dosyayı ve değiştirilen açıklamayı gönder",
        "uploadnologin": "Oturum açık değil",
        "uploadnologintext": "Dosya yükleyebilmek için $1manız gerekiyor.",
        "upload_directory_missing": "Yükleme dizini ($1) kayıp ve websunucusu tarafından oluşturulamıyor.",
        "file-thumbnail-no": "Bu dosyanın adı <strong>$1</strong> ile başlıyor.\nBu başka bir resim küçültülmüş sürümüne benziyor ''(thumbnail)''\nEğer sizde bu resmin tam çöznürlükteki sürümü varsa onu yükleyin, aksi takdirde lütfen dosya adını değiştirin.",
        "fileexists-forbidden": "Bu isimde bir dosya zaten var, ve üzerine yazılamıyor.\nDosyanızı yinede yüklemek istiyorsanız, lütfen geri dönüp yeni bir isim kullanın. [[File:$1|thumb|center|$1]]",
        "fileexists-shared-forbidden": "Bu isimde bir dosya ortak havuzda zaten mevcut.\nDosyanızı yinede yüklemek istiyorsanız, lütfen geri gidip yeni bir isim kullanın. [[File:$1|thumb|center|$1]]",
+       "fileexists-no-change": "Yükleme, mevcut <strong>[[:$1]]</strong> sürümünün tam bir kopyasıdır.",
+       "fileexists-duplicate-version": "Yükleme, <strong>[[:$1]]</strong> dosyasının {{PLURAL:$2|eski bir sürümünün|eski sürümlerinin}} tam bir kopyasıdır.",
        "file-exists-duplicate": "Bu dosya aşağıdaki {{PLURAL:$1|dosyanın|dosyaların}} kopyasıdır:",
        "file-deleted-duplicate": "Bu dosyanın özdeşi olan başka bir dosya ([[:$1]]) daha önceden silindi. Bu dosyayı yeniden yüklemeden önce diğer dosyanın silme kayıtlarını kontrol etmelisiniz.",
        "file-deleted-duplicate-notitle": "Bu dosyaya eş bir dosya daha önceden silinmiş, ve başlık bastırılmış.\nDosyayı tekrar yüklemeye devam etmeden önce, bastırılmış dosya verisini görme yetkisine sahip birisine durumu gözden geçirmesini istemelisiniz.",
        "uploadwarning": "Yükleme uyarısı",
        "uploadwarning-text": "Lütfen aşağıdaki dosya açıklamasını değiştirin ve tekrar deneyin.",
+       "uploadwarning-text-nostash": "Lütfen dosyayı yeniden yükleyin, aşağıdaki açıklamayı değiştirin ve tekrar deneyin.",
        "savefile": "Dosyayı kaydet",
        "uploaddisabled": "Geçici olarak şu anda bu wiki'ye herhangi bir dosya yüklenemez. Lütfen daha sonra bir daha deneyiniz.",
        "copyuploaddisabled": "URL ile yükleme devre dışı.",
        "php-uploaddisabledtext": "PHP dosyası yüklemeleri devre dışıdır. Lütfen file_uploads ayarını kontrol edin.",
        "uploadscripted": "Bu dosya bir internet tarayıcısı tarafından hatalı çevrilebilecek bir HTML veya script kodu içermektedir.",
        "upload-scripted-pi-callback": "XML-stylesheet işleme talimatları içeren bir dosyalar yüklenemez.",
+       "upload-scripted-dtd": "Standart olmayan bir DTD bildirimi içeren SVG dosyaları yüklenemiyor.",
        "uploaded-script-svg": "Yüklenen SVG dosyasında komutlanabilir (scriptable) öğe bulundu: \"$1\"",
        "uploaded-hostile-svg": "Yüklenen SVG dosyasının \"style\" öğesinde güvensiz CSS bulundu.",
        "uploaded-event-handler-on-svg": "SVG dosyalarında event-handler özniteliğini <code>$1=\"$2\"</code> şeklinde ayarlanmasına izin verilmiyor.",
        "uploaded-href-unsafe-target-svg": "Yüklenen SVG dosyasında <code>&lt;$1 $2=\"$3\"&gt;</code> güvensiz hedefine href veri: URI bulundu.",
        "uploaded-animate-svg": "\"animate\" etiketi bulundu, href'i değiştiriyor olabilir. Yüklenen SVG dosyasındaki \"from\" özniteliği kullanılıyor  <code>&lt;$1 $2=\"$3\"&gt;</code>",
+       "uploaded-setting-event-handler-svg": "Olay işleyicisi özniteliklerini ayarlama engellenir, yüklenen SVG dosyasında <code>&lt;$1 $2=\"$3\"&gt;</code> bulundu.",
+       "uploaded-setting-href-svg": "Üst ögeye \"href\" özelliğini eklemek için \"set\" etiketinin kullanılması engellenir.",
        "uploadscriptednamespace": "Bu SVG dosyası geçersiz \"<nowiki>$1</nowiki>\" alan adını içermektedir.",
        "uploadinvalidxml": "Yüklenen dosyadaki XML işlenemedi.",
        "uploadvirus": "Bu dosya virüslüdür! Detayları: $1",
        "deleteprotected": "Bu sayfayı silemezsiniz çünkü sayfa korumaya alınmış.",
        "deleting-backlinks-warning": "'''Uyarı:''' Silmek üzere olduğunuz sayfaya [[Özel:SayfayaBağlantılar/{{FULLPAGENAME}}|başka sayfalardan]] bağlantılar var veya sayfanın bazı bölümleri başka sayfalar tarafından alıntı olarak kullanılıyor.",
        "rollback": "değişiklikleri geri al",
+       "rollback-confirmation-confirm": "Lütfen onaylayın:",
+       "rollback-confirmation-yes": "Geri döndürme",
+       "rollback-confirmation-no": "İptal",
        "rollbacklink": "geri döndür",
        "rollbacklinkcount": "$1 {{PLURAL:$1|değişikliği|değişikliği}} geri döndür",
        "rollbacklinkcount-morethan": "$1 {{PLURAL:$1|değişiklikten|değişiklikten}} daha fazlasını geri döndür",
        "rollbackfailed": "geri alma işlemi başarısız",
+       "rollback-missingparam": "İstek üzerine gerekli parametreler eksik.",
        "rollback-missingrevision": "Sürüm verisi yüklenemedi.",
        "cantrollback": "Sayfaya son katkıda bulunan kullanıcı, sayfaya katkıda bulunmuş tek kişi olduğu için, değişiklikler geri alınamıyor.",
        "alreadyrolled": "[[User:$2|$2]] ([[User talk:$2|Tartışma]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) tarafından [[:$1]] sayfasında yapılmış son değişiklik geri döndürülemiyor;\nbaşka birisi sayfada değişiklik yaptı ya da sayfayı geri döndürdü.\n\nSon değişikliği yapan: [[User:$3|$3]] ([[User talk:$3|Tartışma]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "sp-contributions-blocked-notice-anon": "Bu IP adresi şu anda engellenmiş.\nSon engelleme günlüğü girdisi kaynak amacıyla aşağıda verilmiştir:",
        "sp-contributions-search": "Katkıları ara",
        "sp-contributions-username": "IP adresi veya kullanıcı adı:",
-       "sp-contributions-toponly": "Sadece son revizyon olan değişiklikleri göster",
+       "sp-contributions-toponly": "Sadece güncel sürüm olan değişiklikleri göster",
        "sp-contributions-newonly": "Yalnızca yeni sayfa oluşturan değişiklikleri görüntüle",
        "sp-contributions-hideminor": "Küçük değişiklikleri gizle",
        "sp-contributions-submit": "Ara",
index 666b28f..22313a4 100644 (file)
@@ -447,6 +447,7 @@ $specialPageAliases = [
        'Mostlinkedtemplates'       => [ 'MostTranscludedPages', 'MostLinkedTemplates', 'MostUsedTemplates' ],
        'Mostrevisions'             => [ 'MostRevisions' ],
        'Movepage'                  => [ 'MovePage' ],
+       'Mute'                      => [ 'Mute' ],
        'Mycontributions'           => [ 'MyContributions' ],
        'MyLanguage'                => [ 'MyLanguage' ],
        'Mypage'                    => [ 'MyPage' ],
index b6c7ae4..fe40536 100755 (executable)
@@ -123,6 +123,10 @@ class UpdateMediaWiki extends Maintenance {
 
                $this->output( "MediaWiki {$wgVersion} Updater\n\n" );
 
+               foreach ( SpecialVersion::getSoftwareInformation() as $name => $version ) {
+                       $this->output( "{$name}: {$version}\n" );
+               }
+
                wfWaitForSlaves();
 
                if ( !$this->hasOption( 'skip-compat-checks' ) ) {
index b90ead4..4446d0d 100644 (file)
@@ -2150,7 +2150,10 @@ return [
                ],
        ],
        'mediawiki.special.pageLanguage' => [
-               'scripts' => 'resources/src/mediawiki.special.pageLanguage.js',
+               'scripts' => [
+                       'resources/src/mediawiki.special.mute.js',
+                       'resources/src/mediawiki.special.pageLanguage.js'
+               ],
                'dependencies' => [
                        'oojs-ui-core',
                ],
@@ -2822,7 +2825,6 @@ return [
                'scripts' => [
                        'resources/lib/html5shiv/html5shiv.js'
                ],
-               'raw' => true,
        ],
 
        /* EasyDeflate */
diff --git a/resources/src/mediawiki.special.mute.js b/resources/src/mediawiki.special.mute.js
new file mode 100644 (file)
index 0000000..3d494d0
--- /dev/null
@@ -0,0 +1,23 @@
+( function () {
+       'use strict';
+
+       $( function () {
+               var $inputs = $( '#mw-specialmute-form input:checkbox' ),
+                       saveButton, $saveButton = $( '#save' );
+
+               function isFormChanged() {
+                       return $inputs.is( function () {
+                               return this.checked !== this.defaultChecked;
+                       } );
+               }
+
+               if ( $saveButton.length ) {
+                       saveButton = OO.ui.infuse( $saveButton );
+                       saveButton.setDisabled( !isFormChanged() );
+
+                       $inputs.on( 'change', function () {
+                               saveButton.setDisabled( !isFormChanged() );
+                       } );
+               }
+       } );
+}() );
index 8b70e1f..8538e95 100644 (file)
@@ -4,8 +4,10 @@
 ( function () {
        $( function () {
                // Select the 'Language select' option if user is trying to select language
-               OO.ui.infuse( $( '#mw-pl-languageselector' ) ).on( 'change', function () {
-                       OO.ui.infuse( $( '#mw-pl-options' ) ).setValue( '2' );
-               } );
+               if ( $( '#mw-pl-languageselector' ).length ) {
+                       OO.ui.infuse( $( '#mw-pl-languageselector' ) ).on( 'change', function () {
+                               OO.ui.infuse( $( '#mw-pl-options' ) ).setValue( '2' );
+                       } );
+               }
        } );
 }() );
index 4b65ed5..2976dca 100644 (file)
                                batch.sort();
 
                                // Query parameters common to all requests
-                               reqBase = {
-                                       skin: mw.config.get( 'skin' ),
-                                       lang: mw.config.get( 'wgUserLanguage' ),
-                                       debug: mw.config.get( 'debug' )
-                               };
+                               reqBase = $VARS.reqBase;
 
                                // Split module list by source and by group.
                                splits = Object.create( null );
index 5f0067d..25de1a3 100644 (file)
@@ -2250,7 +2250,6 @@ class OutputPageTest extends MediaWikiTestCase {
         * @param array[] $calls For each array, call addVaryHeader() with those arguments
         * @param string[] $cookies Array of cookie names to vary on
         * @param string $vary Text of expected Vary header (including the 'Vary: ')
-        * @param string $key Text of expected Key header (including the 'Key: ')
         */
        public function testVaryHeaders( array $calls, array $cookies, $vary ) {
                // Get rid of default Vary fields
index 6ccacda..ae71272 100644 (file)
@@ -49,6 +49,13 @@ class ResponseFactoryTest extends MediaWikiTestCase {
                $this->assertSame( 301, $response->getStatusCode() );
        }
 
+       public function testCreateLegacyTemporaryRedirect() {
+               $rf = new ResponseFactory;
+               $response = $rf->createLegacyTemporaryRedirect( 'http://www.example.com/' );
+               $this->assertSame( [ 'http://www.example.com/' ], $response->getHeader( 'Location' ) );
+               $this->assertSame( 302, $response->getStatusCode() );
+       }
+
        public function testCreateTemporaryRedirect() {
                $rf = new ResponseFactory;
                $response = $rf->createTemporaryRedirect( 'http://www.example.com/' );
index 74a5e3c..8faaeda 100644 (file)
@@ -76,9 +76,6 @@ class MockSearch extends SearchEngine {
        public static $title;
        public static $text;
 
-       public function __construct( $db ) {
-       }
-
        public function update( $id, $title, $text ) {
                self::$id = $id;
                self::$title = $title;
index 99f5e1b..bc7cb69 100644 (file)
@@ -182,23 +182,6 @@ mw.loader.register( [
         "util",
         "{blankVer}"
     ]
-] );',
-                       ] ],
-                       [ [
-                               'msg' => 'Omit raw modules from registry',
-                               'modules' => [
-                                       'test.raw' => new ResourceLoaderTestModule( [ 'isRaw' => true ] ),
-                                       'test.blank' => new ResourceLoaderTestModule(),
-                               ],
-                               'out' => '
-mw.loader.addSource( {
-    "local": "/w/load.php"
-} );
-mw.loader.register( [
-    [
-        "test.blank",
-        "{blankVer}"
-    ]
 ] );',
                        ] ],
                        [ [
index 1171ebc..544afae 100644 (file)
@@ -171,9 +171,8 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
                        'simple scripts' => [ true,
                                [ 'scripts' => 'example.js' ]
                        ],
-                       'simple scripts, raw and targets' => [ true, [
+                       'simple scripts with targets' => [ true, [
                                'scripts' => [ 'a.js', 'b.js' ],
-                               'raw' => true,
                                'targets' => [ 'desktop', 'mobile' ],
                        ] ],
                        'FileModule' => [ true,
index 0c6520e..1a0393e 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use Wikimedia\Rdbms\LoadBalancerSingle;
+
 /**
  * @group Search
  * @group Database
@@ -39,7 +41,8 @@ class SearchEngineTest extends MediaWikiLangTestCase {
                        ]
                ] );
 
-               $this->search = new $searchType( $this->db );
+               $lb = LoadBalancerSingle::newFromConnection( $this->db );
+               $this->search = new $searchType( $lb );
        }
 
        protected function tearDown() {
index b33cd24..cd0867d 100644 (file)
@@ -711,10 +711,10 @@ class SessionManagerTest extends MediaWikiTestCase {
                ] );
 
                $expect = [
-                       'Foo' => [],
-                       'Bar' => [ 'X', 'Bar1', 3 => 'Bar2' ],
-                       'Quux' => [ 'Quux' ],
-                       'Baz' => [],
+                       'Foo' => null,
+                       'Bar' => null,
+                       'Quux' => null,
+                       'Baz' => null,
                ];
 
                $this->assertEquals( $expect, $manager->getVaryHeaders() );
diff --git a/tests/phpunit/includes/specials/SpecialMuteTest.php b/tests/phpunit/includes/specials/SpecialMuteTest.php
new file mode 100644 (file)
index 0000000..e31357c
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+
+/**
+ * @group SpecialPage
+ * @covers SpecialMute
+ */
+class SpecialMuteTest extends SpecialPageTestBase {
+
+       protected function setUp() {
+               parent::setUp();
+
+               $this->setMwGlobals( [
+                       'wgEnableUserEmailBlacklist' => true
+               ] );
+       }
+
+       /**
+        * @inheritDoc
+        */
+       protected function newSpecialPage() {
+               return new SpecialMute();
+       }
+
+       /**
+        * @covers SpecialMute::execute
+        * @expectedExceptionMessage username requested could not be found
+        * @expectedException ErrorPageError
+        */
+       public function testInvalidTarget() {
+               $user = $this->getTestUser()->getUser();
+               $this->executeSpecialPage(
+                       'InvalidUser', null, 'qqx', $user
+               );
+       }
+
+       /**
+        * @covers SpecialMute::execute
+        * @expectedExceptionMessage Muting users from sending you emails is not enabled
+        * @expectedException ErrorPageError
+        */
+       public function testEmailBlacklistNotEnabled() {
+               $this->setMwGlobals( [
+                       'wgEnableUserEmailBlacklist' => false
+               ] );
+
+               $user = $this->getTestUser()->getUser();
+               $this->executeSpecialPage(
+                       $user->getName(), null, 'qqx', $user
+               );
+       }
+
+       /**
+        * @covers SpecialMute::execute
+        * @expectedException UserNotLoggedIn
+        */
+       public function testUserNotLoggedIn() {
+               $this->executeSpecialPage( 'TestUser' );
+       }
+
+       /**
+        * @covers SpecialMute::execute
+        */
+       public function testMuteAddsUserToEmailBlacklist() {
+               $this->setMwGlobals( [
+                       'wgCentralIdLookupProvider' => 'local',
+               ] );
+
+               $targetUser = $this->getTestUser()->getUser();
+
+               $loggedInUser = $this->getMutableTestUser()->getUser();
+               $loggedInUser->setOption( 'email-blacklist', "999" );
+               $loggedInUser->confirmEmail();
+               $loggedInUser->saveSettings();
+
+               $fauxRequest = new FauxRequest( [ 'wpMuteEmail' => 1 ], true );
+               list( $html, ) = $this->executeSpecialPage(
+                       $targetUser->getName(), $fauxRequest, 'qqx', $loggedInUser
+               );
+
+               $this->assertContains( 'specialmute-success', $html );
+               $this->assertEquals(
+                       "999\n" . $targetUser->getId(),
+                       $loggedInUser->getOption( 'email-blacklist' )
+               );
+       }
+
+       /**
+        * @covers SpecialMute::execute
+        */
+       public function testUnmuteRemovesUserFromEmailBlacklist() {
+               $this->setMwGlobals( [
+                       'wgCentralIdLookupProvider' => 'local',
+               ] );
+
+               $targetUser = $this->getTestUser()->getUser();
+
+               $loggedInUser = $this->getMutableTestUser()->getUser();
+               $loggedInUser->setOption( 'email-blacklist', "999\n" . $targetUser->getId() );
+               $loggedInUser->confirmEmail();
+               $loggedInUser->saveSettings();
+
+               $fauxRequest = new FauxRequest( [ 'wpMuteEmail' => false ], true );
+               list( $html, ) = $this->executeSpecialPage(
+                       $targetUser->getName(), $fauxRequest, 'qqx', $loggedInUser
+               );
+
+               $this->assertContains( 'specialmute-success', $html );
+               $this->assertEquals( "999", $loggedInUser->getOption( 'email-blacklist' ) );
+       }
+}
index 78e5763..a762884 100644 (file)
@@ -45,9 +45,9 @@ class ResourcesTest extends MediaWikiTestCase {
        }
 
        /**
-        * Verify that nothing explicitly depends on raw modules (such as "query").
+        * Verify that nothing depends on "startup".
         *
-        * Depending on them is unsupported as they are not registered client-side by the startup module.
+        * Depending on it is unsupported as it cannot be loaded by the client.
         *
         * @todo Modules can dynamically choose dependencies based on context. This method does not
         * test such dependencies. The same goes for testMissingDependencies() and
@@ -58,7 +58,7 @@ class ResourcesTest extends MediaWikiTestCase {
 
                $illegalDeps = [];
                foreach ( $data['modules'] as $moduleName => $module ) {
-                       if ( $module->isRaw() ) {
+                       if ( $module instanceof ResourceLoaderStartUpModule ) {
                                $illegalDeps[] = $moduleName;
                        }
                }