Merge "resourceloader: Remove only=messages"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 14 May 2015 18:10:10 +0000 (18:10 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 14 May 2015 18:10:10 +0000 (18:10 +0000)
27 files changed:
includes/api/ApiOptions.php
includes/api/i18n/es.json
includes/api/i18n/zh-hans.json
includes/filebackend/SwiftFileBackend.php
includes/filerepo/LocalRepo.php
includes/filerepo/file/LocalFile.php
includes/libs/objectcache/WANObjectCache.php
includes/registration/ExtensionProcessor.php
includes/registration/Processor.php
includes/specials/SpecialContributions.php
includes/specials/SpecialDeletedContributions.php
languages/i18n/an.json
languages/i18n/be-tarask.json
languages/i18n/ce.json
languages/i18n/es.json
languages/i18n/fr.json
languages/i18n/ko.json
languages/i18n/la.json
languages/i18n/pl.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/ru.json
tests/phpunit/includes/libs/ArrayUtilsTest.php
tests/phpunit/includes/objectcache/WANObjectCacheTest.php
tests/phpunit/includes/registration/ExtensionProcessorTest.php
tests/phpunit/includes/site/CachingSiteStoreTest.php
tests/phpunit/includes/site/SiteImporterTest.php

index 8ef0629..436f22a 100644 (file)
@@ -75,11 +75,17 @@ class ApiOptions extends ApiBase {
                $prefs = Preferences::getPreferences( $user, $this->getContext() );
                $prefsKinds = $user->getOptionKinds( $this->getContext(), $changes );
 
+               $htmlForm = null;
                foreach ( $changes as $key => $value ) {
                        switch ( $prefsKinds[$key] ) {
                                case 'registered':
                                        // Regular option.
+                                       if ( $htmlForm === null ) {
+                                               // We need a dummy HTMLForm for the validate callback...
+                                               $htmlForm = new HTMLForm( array(), $this );
+                                       }
                                        $field = HTMLForm::loadInputFromParameters( $key, $prefs[$key] );
+                                       $field->mParent = $htmlForm;
                                        $validation = $field->validate( $value, $user->getOptions() );
                                        break;
                                case 'registered-multiselect':
index 5705c48..b29f32d 100644 (file)
        "apihelp-options-example-reset": "Restablecer todas las preferencias",
        "apihelp-paraminfo-description": "Obtener información acerca de los módulos de la API.",
        "apihelp-paraminfo-param-helpformat": "Formato de las cadenas de ayuda.",
+       "apihelp-parse-paramvalue-prop-modules": "Da los módulos ResourceLoader utilizados en la página.",
        "apihelp-patrol-example-rcid": "Patrullar un cambio reciente",
        "apihelp-patrol-example-revid": "Patrullar una revisión",
        "apihelp-protect-param-reason": "Motivo de la (des)protección.",
index 1b3564b..ff265cd 100644 (file)
        "apihelp-parse-param-pageid": "解析此页的内容。覆盖<var>$1page</var>。",
        "apihelp-parse-param-redirects": "如果<var>$1page</var>或<var>$1pageid</var>被设置为一个重定向,则解析它。",
        "apihelp-parse-param-oldid": "解析该修订版本的内容。覆盖<var>$1page</var>和<var>$1pageid</var>。",
+       "apihelp-parse-paramvalue-prop-categorieshtml": "提供HTML版本分类。",
        "apihelp-parse-paramvalue-prop-modules": "提供在页面中使用的ResourceLoader模块。",
        "apihelp-parse-param-pst": "在解析输入前,对输入做一次保存前变换处理。仅当使用文本时有效。",
        "apihelp-parse-param-effectivelanglinks": "包含由扩展提供的语言链接(用于与<kbd>$1prop=langlinks</kbd>一起使用)。",
index 5f406c9..d6d7e9e 100644 (file)
@@ -235,16 +235,16 @@ class SwiftFileBackend extends FileBackendStore {
                        'body' => $params['content']
                ) );
 
-               $be = $this;
+               $that = $this;
                $method = __METHOD__;
-               $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) {
+               $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
                        list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
                        if ( $rcode === 201 ) {
                                // good
                        } elseif ( $rcode === 412 ) {
                                $status->fatal( 'backend-fail-contenttype', $params['dst'] );
                        } else {
-                               $be->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+                               $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
                        }
                };
 
@@ -298,16 +298,16 @@ class SwiftFileBackend extends FileBackendStore {
                        'body' => $handle // resource
                ) );
 
-               $be = $this;
+               $that = $this;
                $method = __METHOD__;
-               $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) {
+               $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
                        list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
                        if ( $rcode === 201 ) {
                                // good
                        } elseif ( $rcode === 412 ) {
                                $status->fatal( 'backend-fail-contenttype', $params['dst'] );
                        } else {
-                               $be->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+                               $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
                        }
                };
 
@@ -347,16 +347,16 @@ class SwiftFileBackend extends FileBackendStore {
                        ) + $this->sanitizeHdrs( $params ), // extra headers merged into object
                ) );
 
-               $be = $this;
+               $that = $this;
                $method = __METHOD__;
-               $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) {
+               $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
                        list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
                        if ( $rcode === 201 ) {
                                // good
                        } elseif ( $rcode === 404 ) {
                                $status->fatal( 'backend-fail-copy', $params['src'], $params['dst'] );
                        } else {
-                               $be->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+                               $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
                        }
                };
 
@@ -405,9 +405,9 @@ class SwiftFileBackend extends FileBackendStore {
                        );
                }
 
-               $be = $this;
+               $that = $this;
                $method = __METHOD__;
-               $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) {
+               $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
                        list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
                        if ( $request['method'] === 'PUT' && $rcode === 201 ) {
                                // good
@@ -416,7 +416,7 @@ class SwiftFileBackend extends FileBackendStore {
                        } elseif ( $rcode === 404 ) {
                                $status->fatal( 'backend-fail-move', $params['src'], $params['dst'] );
                        } else {
-                               $be->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+                               $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
                        }
                };
 
@@ -446,9 +446,9 @@ class SwiftFileBackend extends FileBackendStore {
                        'headers' => array()
                ) );
 
-               $be = $this;
+               $that = $this;
                $method = __METHOD__;
-               $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) {
+               $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
                        list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
                        if ( $rcode === 204 ) {
                                // good
@@ -457,7 +457,7 @@ class SwiftFileBackend extends FileBackendStore {
                                        $status->fatal( 'backend-fail-delete', $params['src'] );
                                }
                        } else {
-                               $be->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+                               $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
                        }
                };
 
@@ -505,16 +505,16 @@ class SwiftFileBackend extends FileBackendStore {
                        'headers' => $metaHdrs + $customHdrs
                ) );
 
-               $be = $this;
+               $that = $this;
                $method = __METHOD__;
-               $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) {
+               $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
                        list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
                        if ( $rcode === 202 ) {
                                // good
                        } elseif ( $rcode === 404 ) {
                                $status->fatal( 'backend-fail-describe', $params['src'] );
                        } else {
-                               $be->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+                               $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
                        }
                };
 
index 591d684..ef402ea 100644 (file)
@@ -275,14 +275,14 @@ class LocalRepo extends FileRepo {
                        );
                };
 
-               $repo = $this;
+               $that = $this;
                $applyMatchingFiles = function ( ResultWrapper $res, &$searchSet, &$finalFiles )
-                       use ( $repo, $fileMatchesSearch, $flags )
+                       use ( $that, $fileMatchesSearch, $flags )
                {
                        global $wgContLang;
-                       $info = $repo->getInfo();
+                       $info = $that->getInfo();
                        foreach ( $res as $row ) {
-                               $file = $repo->newFileFromRow( $row );
+                               $file = $that->newFileFromRow( $row );
                                // There must have been a search for this DB key, but this has to handle the
                                // cases were title capitalization is different on the client and repo wikis.
                                $dbKeysLook = array( str_replace( ' ', '_', $file->getName() ) );
index e26f739..fe42c2d 100644 (file)
@@ -1603,21 +1603,21 @@ class LocalFile extends File {
 
                // Hack: the lock()/unlock() pair is nested in a transaction so the locking is not
                // tied to BEGIN/COMMIT. To avoid slow purges in the transaction, move them outside.
-               $file = $this;
+               $that = $this;
                $this->getRepo()->getMasterDB()->onTransactionIdle(
-                       function () use ( $file, $archiveNames ) {
+                       function () use ( $that, $archiveNames ) {
                                global $wgUseSquid;
 
-                               $file->purgeEverything();
+                               $that->purgeEverything();
                                foreach ( $archiveNames as $archiveName ) {
-                                       $file->purgeOldThumbnails( $archiveName );
+                                       $that->purgeOldThumbnails( $archiveName );
                                }
 
                                if ( $wgUseSquid ) {
                                        // Purge the squid
                                        $purgeUrls = array();
                                        foreach ( $archiveNames as $archiveName ) {
-                                               $purgeUrls[] = $file->getArchiveUrl( $archiveName );
+                                               $purgeUrls[] = $that->getArchiveUrl( $archiveName );
                                        }
                                        SquidUpdate::purge( $purgeUrls );
                                }
index e1f64ba..8d202c7 100755 (executable)
@@ -76,6 +76,8 @@ class WANObjectCache {
 
        /** Idiom for set()/getWithSetCallback() TTL */
        const TTL_NONE = 0;
+       /** Idiom for getWithSetCallback() callbacks to avoid calling set() */
+       const TTL_UNCACHEABLE = -1;
 
        /** Cache format version number */
        const VERSION = 1;
@@ -307,10 +309,13 @@ class WANObjectCache {
        /**
         * Method to fetch/regenerate cache keys
         *
-        * On cache miss, the key will be set to the callback result.
+        * On cache miss, the key will be set to the callback result,
+        * unless the callback returns false. The arguments supplied are:
+        *     (current value or false, &$ttl)
         * The callback function returns the new value given the current
-        * value (false if not present). If false is returned, then nothing
-        * will be saved to cache.
+        * value (false if not present). Preemptive re-caching and $checkKeys
+        * can result in a non-false current value. The TTL of the new value
+        * can be set dynamically by altering $ttl in the callback (by reference).
         *
         * Usually, callbacks ignore the current value, but it can be used
         * to maintain "most recent X" values that come from time or sequence
@@ -333,7 +338,7 @@ class WANObjectCache {
         * @code
         *     $key = wfMemcKey( 'cat-recent-actions', $catId );
         *     // Function that derives the new key value given the old value
-        *     $callback = function( $cValue ) { ... };
+        *     $callback = function( $cValue, &$ttl ) { ... };
         *     // Get the key value from cache or from source on cache miss;
         *     // try to only let one cluster thread manage doing cache updates
         *     $opts = array( 'lockTSE' => 5, 'lowTTL' => 10 );
@@ -362,7 +367,9 @@ class WANObjectCache {
         *
         * @param string $key Cache key
         * @param callable $callback Value generation function
-        * @param integer $ttl Seconds to live when the key is updated [0=forever]
+        * @param integer $ttl Seconds to live for key updates. Special values are:
+        *   - WANObjectCache::TTL_NONE        : cache forever
+        *   - WANObjectCache::TTL_UNCACHEABLE : do not cache at all
         * @param array $checkKeys List of "check" keys
         * @param array $opts Options map:
         *   - lowTTL  : consider pre-emptive updates when the current TTL (sec)
@@ -426,10 +433,10 @@ class WANObjectCache {
                }
 
                // Generate the new value from the callback...
-               $value = call_user_func( $callback, $cValue );
+               $value = call_user_func_array( $callback, array( $cValue, &$ttl ) );
                // When delete() is called, writes are write-holed by the tombstone,
                // so use a special stash key to pass the new value around threads.
-               if ( $value !== false && ( $isHot || $isTombstone ) ) {
+               if ( $value !== false && ( $isHot || $isTombstone ) && $ttl >= 0 ) {
                        $this->cache->set( self::STASH_KEY_PREFIX . $key, $value, $tempTTL );
                }
 
@@ -437,7 +444,7 @@ class WANObjectCache {
                        $this->cache->unlock( $key );
                }
 
-               if ( $value !== false ) {
+               if ( $value !== false && $ttl >= 0 ) {
                        // Update the cache; this will fail if the key is tombstoned
                        $this->set( $key, $value, $ttl );
                }
index 4b9a754..23a2993 100644 (file)
@@ -152,8 +152,10 @@ class ExtensionProcessor implements Processor {
 
        protected function extractHooks( array $info ) {
                if ( isset( $info['Hooks'] ) ) {
-                       foreach ( $info['Hooks'] as $name => $callable ) {
-                               $this->globals['wgHooks'][$name][] = $callable;
+                       foreach ( $info['Hooks'] as $name => $value ) {
+                               foreach ( (array)$value as $callback ) {
+                                       $this->globals['wgHooks'][$name][] = $callback;
+                               }
                        }
                        $this->processed[] = 'Hooks';
                }
index e930fd3..391f108 100644 (file)
@@ -21,7 +21,12 @@ interface Processor {
        public function extractInfo( $path, array $info );
 
        /**
-        * @return array With 'globals', 'defines', 'callbacks', 'credits' keys.
+        * @return array With following keys:
+        *              'globals' - variables to be set to $GLOBALS
+        *              'defines' - constants to define
+        *              'callbacks' - functions to be executed by the registry
+        *              'credits' - metadata to be stored by registry
+        *              'attributes' - registration info which isn't a global variable
         */
        public function getExtractedInfo();
 }
index c2cd812..6b918e9 100644 (file)
@@ -724,7 +724,6 @@ class ContribsPager extends ReverseChronologicalPager {
                        $limit,
                        $descending
                );
-               $pager = $this;
 
                /*
                 * This hook will allow extensions to add in additional queries, so they can get their data
@@ -749,7 +748,7 @@ class ContribsPager extends ReverseChronologicalPager {
                ) );
                Hooks::run(
                        'ContribsPager::reallyDoQuery',
-                       array( &$data, $pager, $offset, $limit, $descending )
+                       array( &$data, $this, $offset, $limit, $descending )
                );
 
                $result = array();
index 9e4bbbe..387c174 100644 (file)
@@ -88,15 +88,13 @@ class DeletedContribsPager extends IndexPager {
         * @return ResultWrapper
         */
        function reallyDoQuery( $offset, $limit, $descending ) {
-               $pager = $this;
-
                $data = array( parent::reallyDoQuery( $offset, $limit, $descending ) );
 
                // This hook will allow extensions to add in additional queries, nearly
                // identical to ContribsPager::reallyDoQuery.
                Hooks::run(
                        'DeletedContribsPager::reallyDoQuery',
-                       array( &$data, $pager, $offset, $limit, $descending )
+                       array( &$data, $this, $offset, $limit, $descending )
                );
 
                $result = array();
index 2f9e747..e88507f 100644 (file)
        "querypage-disabled": "Ista pachina especial ye desactivata por motivos de rendimiento.",
        "booksources": "Fuents de libros",
        "booksources-search-legend": "Mirar fuents de libros",
+       "booksources-search": "Mirar",
        "booksources-text": "Contino ye una lista de vinclos ta atros puestos an que venden libros nuevos y usatos, talment bi haiga más información sobre os libros que ye mirando.",
        "booksources-invalid-isbn": "O numero d'ISBN dato pareix que no ye conforme; comprebe si no bi ha garra error en copiar d'a fuent orichinal.",
        "specialloguserlabel": "Fedor:",
index f9f0365..ef82495 100644 (file)
        "title-invalid-characters": "Запытаная назва старонкі ўтрымлівае няслушныя сымбалі: «$1».",
        "title-invalid-relative": "Назва мае адносны шлях. Адносныя назвы старонак (./, ../) няслушныя, бо яны часта робяцца недаступнымі, калі апрацоўваюцца браўзэрам карыстальніка.",
        "title-invalid-magic-tilde": "Запытаная назва старонкі ўтрымлівае недазволенае спалучэньне тыльдаў (<nowiki>~~~</nowiki>).",
+       "title-invalid-too-long": "Запытаная назва старонкі занадта доўгая. Яна ня мусіць быць даўжэй за $1 байтаў у кадаваньні UTF-8.",
        "perfcached": "Наступныя зьвесткі кэшаваныя і могуць быць састарэлымі. У кэшы {{PLURAL:$1|даступны|даступныя}} ня больш за $1 {{PLURAL:$1|вынік|вынікі|вынікаў}}.",
        "perfcachedts": "Наступныя зьвесткі кэшаваныя і апошні раз былі абноўленыя $1. У кэшы {{PLURAL:$4|даступны|даступныя}} ня больш за $4 {{PLURAL:$4|вынік|вынікі|вынікаў}}.",
        "querypage-no-updates": "Абнаўленьні гэтай старонкі цяпер адключаныя. Зьвесткі ня будуць абнаўляцца.",
index 32ca11e..29ab958 100644 (file)
        "missingcommentheader": "'''Дагадаийтар.''' Ахьа хӀокху къамелан дӀахьедар/корта билгал бина бац. Кнопка «{{int:savearticle}}» юху тӀетаӀича хийцамах лаьцна хӀума доцуш Ӏалашбира бу.",
        "summary-preview": "Цуьнах лаьцна хирду:",
        "subject-preview": "Коьрта могӀа хира бу:",
+       "previewerrortext": "Хьан хийцамашка хьалха хьажа гӀертачу хенахь гӀалат даьлла.",
        "blockedtitle": "Декъашхочун блоктоьхана",
        "blockedtext": "'''Хьан декъашхочун дӀаяздар я IP-адрес блоктоьхна ду.'''\n\nБлоктоьхна куьйгалхочо $1.\nБилгалдина бахьна: «''$2''».\n\n* Блоктохар доладелла: $8\n* Блоктохар чекхдолу: $6\n* Блоктохаран Ӏалашо: $7\n\nХьа йиш ю $1 декъашхочуьнга дехардан я кхечу муьлха [[{{MediaWiki:Grouppage-sysop}}|куьйгалхочуьнга]].\nТергам бе, хьа таро яц «декъашхочунга кехат» олу функци лелаян, хьан [[Special:Preferences|гӀирс нисбар чохь]] нийса электронан поштан адрес яздина дацахь, я кехаташ кхехӀитарна а блоктоьхна елахь.\nХьан IP-адрес — $3, блоктохаран идентификатор — $5.\nДехар до, хьайн хаам чохь билгалде и.",
        "blockednoreason": "бахьана билгалдина дац",
index 78adf0a..0c235a1 100644 (file)
        "no-null-revision": "No se pudo crear una nueva revisión nula para la página «$1»",
        "badtitle": "Título incorrecto",
        "badtitletext": "El título de la página solicitada está vacío, no es válido, o es un enlace interidioma o interwiki incorrecto.\nPuede que contenga uno o más caracteres que no se pueden usar en los títulos.",
+       "title-invalid-interwiki": "El título contiene un enlace interwiki",
+       "title-invalid-characters": "El título  de la página solicitada contiene caracteres no válidos: \"$1\".",
+       "title-invalid-leading-colon": "El título de la página solicitada contiene un caracater (:) no válido en el comienzo.",
        "perfcached": "Los siguientes datos provienen de la caché y pueden no estar actualizados. La caché puede contener {{PLURAL:$1|un resultado|$1 resultados}} como máximo.",
        "perfcachedts": "Los siguientes datos provienen de la caché, y fueron actualizados por última vez a fecha de: $1. La caché contiene {{PLURAL:$4|un resultado|$4 resultados}} como máximo.",
        "querypage-no-updates": "Actualmente las actualizaciones de esta página están desactivadas. Estos datos no serán actualizados a corto plazo.",
index 9c13d6e..8bab518 100644 (file)
        "movepagetalktext": "La page de discussion associée, si présente, sera automatiquement renommée '''sauf si :'''\n* vous déplacez la page vers un autre espace de noms, ou\n* une page de discussion non vide existe déjà sous le nouveau nom, ou\n* vous décochez la case ci-dessous.\n\nDans ces cas-là, vous devrez renommer ou fusionner cette page de discussion manuellement si vous le désirez.",
        "movearticle": "Renommer la page :",
        "moveuserpage-warning": "'''Attention :''' Vous êtes sur le point de renommer une page d’utilisateur. Veuillez noter que seule la page sera renommée et que l’utilisateur '''ne''' sera '''pas''' renommé.",
-       "movecategorypage-warning": "<strong>Avertissement :</strong> Vous êtes sur le point de renommer une page de catégorie. Veuillez noter que seule la page sera renommée et que toutes les pages dans l'ancienne catégorie ne seront <em>pas</em> transférées dans la nouvelle.",
+       "movecategorypage-warning": "<strong>Avertissement :</strong> Vous êtes sur le point de renommer une page de catégorie. Veuillez noter que seule la catégorie sera renommée et <em>qu’aucune</em> des pages de l’ancienne catégorie ne sera transférée dans la nouvelle.",
        "movenologintext": "Pour pouvoir renommer une page, vous devez être [[Special:UserLogin|identifié{{GENDER:||e}}]] avec un compte utilisateur enregistré et d'ancienneté suffisante.",
        "movenotallowed": "Vous n'avez pas la permission de renommer les pages.",
        "movenotallowedfile": "Vous n'avez pas la permission de renommer les fichiers.",
index f30174b..70c2c0a 100644 (file)
        "right-sendemail": "다른 사용자에게 이메일 보내기",
        "right-passwordreset": "비밀번호 재설정 이메일을 보기",
        "right-managechangetags": "데이터베이스에서 [[Special:Tags|태그]]를 만들거나 지우기",
+       "right-applychangetags": "자신이 편집할 때 [[Special:Tags|태그]]를 적용하기",
+       "right-changetags": "문서의 특정 판과 특정 기록 항목에 임의의 [[Special:Tags|태그]]를 추가하거나 제거하기",
        "newuserlogpage": "사용자 만들기 기록",
        "newuserlogpagetext": "사용자가 만들어진 기록입니다.",
        "rightslog": "사용자 권한 기록",
        "action-editmyprivateinfo": "자신의 개인정보 편집",
        "action-editcontentmodel": "문서의 콘텐츠 모델을 편집",
        "action-managechangetags": "데이터베이스에서 태그를 만들거나 지울",
+       "action-applychangetags": "당신이 편집할 때 태그를 적용하기",
+       "action-changetags": "문서의 특정 판과 특정 기록 항목에 임의의 태그를 추가하거나 제거하기",
        "nchanges": "$1개 {{PLURAL:$1|바뀜}}",
        "enhancedrc-since-last-visit": "{{PLURAL:$1|마지막 방문 이후}} $1개",
        "enhancedrc-history": "역사",
index ed289f8..1c48612 100644 (file)
        "createacct-error": "Error in ratione creanda",
        "createaccounterror": "Rationem creare non potuit: $1",
        "nocookiesnew": "Ratio usoris creata est, sed conventum non apertum est. {{SITENAME}} ''Cookies'' utitur in usorum conventa aperiendo. Cookies tua debiles sunt. Eis potestatem fac, tum conventum aperi cum nomine usoris tesseraque tua nova.",
-       "nocookieslogin": "{{SITENAME}} ''Cookies'' utitur in usorum conventa aperiendo. Cookies tua debiles sunt. Eis potestatem fac, tum conare denuo.",
+       "nocookieslogin": "{{SITENAME}} ''Cookies'' in conventis collatorum aperiendis adhibentur. ''Cookies'' tua debilitata sunt. Eis potestatem fac, tum conare denuo.",
        "noname": "Nomen usoris ratum non designavisti.",
        "loginsuccesstitle": "Conventum prospere apertum est",
        "loginsuccess": "'''Apud {{grammar:accusative|{{SITENAME}}}} agnosceris nomine \"$1\".'''",
index 41a5b85..49de490 100644 (file)
        "no-null-revision": "Nie można utworzyć zerowej wersji strony \"$1\"",
        "badtitle": "Niepoprawny tytuł",
        "badtitletext": "Podano niepoprawny tytuł strony. Prawdopodobnie jest pusty lub zawiera znaki, których użycie jest zabronione.",
+       "title-invalid-empty": "Żądany tytuł strony jest pusty lub zawiera tylko nazwę przestrzeni nazw.",
+       "title-invalid-utf8": "Żądany tytuł strony zawiera błędny ciąg znaków UTF-8.",
        "title-invalid-interwiki": "Tytuł zawiera link interwiki",
+       "title-invalid-talk-namespace": "Żądany tytuł strony dotyczy strony dyskusji, która nie istnieje.",
+       "title-invalid-characters": "Żądany tytuł strony zawiera błędne znaki: \"$1\".",
+       "title-invalid-magic-tilde": "Żądany tytuł strony zawiera błędną, magiczną sekwencję tyld (<nowiki>~~~</nowiki>)",
        "perfcached": "Poniższe dane są kopią z pamięci podręcznej i mogą być nieaktualne. W pamięci podręcznej {{PLURAL:$1|znajduje|znajdują|znajduje}} się maksymalnie {{PLURAL:$1|jeden wynik|$1 wyniki|$1 wyników}}.",
        "perfcachedts": "Poniższe dane są kopią z pamięci podręcznej. Ostatnia aktualizacja odbyła się $1. W pamięci podręcznej {{PLURAL:$4|znajduje|znajdują|znajduje}} się maksymalnie {{PLURAL:$4|jeden wynik|$4 wyniki|$4 wyników}}.",
        "querypage-no-updates": "Uaktualnienia dla tej strony są obecnie wyłączone. Znajdujące się tutaj dane nie zostaną odświeżone.",
index 630e6bf..cd286ec 100644 (file)
        "feb": "Fev.",
        "mar": "Mar.",
        "apr": "Abr.",
-       "may": "Maio",
+       "may": "Mai.",
        "jun": "Jun.",
        "jul": "Jul.",
        "aug": "Ago.",
        "currentevents": "Notícias",
        "currentevents-url": "Project:Notícias",
        "disclaimers": "Exoneração de responsabilidade",
-       "disclaimerpage": "Project:Aviso_geral",
+       "disclaimerpage": "Project:Aviso geral",
        "edithelp": "Ajuda de edição",
        "helppage-top-gethelp": "Ajuda",
        "mainpage": "Página principal",
        "portal": "Portal comunitário",
        "portal-url": "Project:Portal comunitário",
        "privacy": "Política de privacidade",
-       "privacypage": "Project:Política_de_privacidade",
+       "privacypage": "Project:Política de privacidade",
        "badaccess": "Erro de permissão",
        "badaccess-group0": "Não está autorizado a executar a operação solicitada.",
        "badaccess-groups": "A operação solicitada está limitada a utilizadores {{PLURAL:$2|do grupo|de um dos seguintes grupos}}: $1.",
index fd58eea..b11cad1 100644 (file)
        "feedback-termsofuse": "Label with an agreement about the terms of use.",
        "feedback-thanks": "Thanks message, appears if feedback was successful. Parameters:\n* $1 - \"Feedback\"\n* $2 - Feedback page URL",
        "feedback-thanks-title": "The title of the thank you dialog at the end of the submission process.\n{{Identical|Thank you}}",
-       "feedback-useragent": "A label denoting the user agent in the feedback that is posted to the feedback page.",
+       "feedback-useragent": "A label denoting the user agent in the feedback that is posted to the feedback page.\n{{Identical|User agent}}",
        "searchsuggest-search": "Greyed out default text in the simple search box in the Vector skin. (It disappears and lets the user enter the requested search terms when the search box receives focus.)\n\n{{Identical|Search}}",
        "searchsuggest-containing": "Label used in the special item of the search suggestions list which gives the user an option to perform a full text search for the term.",
        "api-error-badaccess-groups": "API error message that can be used for client side localisation of API errors.",
index d436b51..4b4e98d 100644 (file)
        "log-name-pagelang": "Журнал изменения языка",
        "log-description-pagelang": "Это журнал изменений в языках страницы.",
        "logentry-pagelang-pagelang": "$1 изменил{{GENDER:$2||а}} язык страницы для $3 с $4 на $5.",
-       "default-skin-not-found": "Упс! Тема оформления по умолчанию для вашей вики <code>$wgDefaultSkin</code>, <code>$1</code> недоступна.\n\nВаша установка, похоже, содержит {{PLURAL:$4|следующую тему|следующие темы}} оформления. См. [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual:Skin configuration] для получения информации о том, как включить {{PLURAL:$4|её|их и выбрать тему по умолчанию}}.\n\n$2\n\n; Если вы только что установили MediaWiki:\n: Вы, видимо, сделали это с Git или непосредственно из исходного кода с использованием другого способа. Тогда такое возможно. Попробуйте установить некоторые темы из [https://www.mediawiki.org/wiki/Category:All_skins каталога тем оформления сайта mediawiki.org]:\n:* Загрузив [https://www.mediawiki.org/wiki/Download архив установочных файлов], который содержит несколько тем оформления и расширений. Вы можете скопировать папку <code>skins/</code> из него.\n:* Загрузив архивы отдельных тем оформления с [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* Клонировав один из репозиториев <code>mediawiki/skins/*</code> через git в подпапку <code  dir=\"ltr\">skins/</code> папки, куда установлена MediaWiki.\n: Это не должно навредить вашему репозиторию, если вы MediaWiki-разработчик. См. [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual:Skin configuration] для получения информации о том, как включить темы оформления и выбрать тему по умолчанию.\n; Если вы только что обновили MediaWiki:\n: MediaWiki версии 1.24 и новее больше не включает автоматически установленные темы (см. [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]).\nВы можете вставить {{PLURAL:$5|следующую строку|следующие строки}} в <code>LocalSettings.php</code>, чтобы включить {{PLURAL:$5|установленную в текущее время тему|все установленные в текущее время темы}} оформления: \n\n<pre dir=\"ltr\">$3</pre>\n\n\n; Если вы только что изменили <code>LocalSettings.php</code>:\n: Перепроверьте названия тем на наличие опечаток.",
-       "default-skin-not-found-no-skins": "Упс! Тема оформления по умолчанию для вашей вики <code>$wgDefaultSkin</code>, <code>$1</code> недоступна.\n\nУ вас нет установленных тем оформления.\n\n; Если вы только что установили или обновили MediaWiki:\n: Вы, видимо, сделали это с Git или непосредственно из исходного кода с использованием другого способа. Тогда такое возможно. MediaWiki версии 1.24 и новее не содержат темы оформления в основном репозитории. Попробуйте установить некоторые темы из [https://www.mediawiki.org/wiki/Category:All_skins каталога тем оформления сайта mediawiki.org]:\n:* Загрузив [https://www.mediawiki.org/wiki/Download архив установочных файлов], который содержит несколько тем оформления и расширений. Вы можете скопировать папку <code>skins/</code> из него.\n:* Загрузив архивы отдельных тем оформления с [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* Клонировав один из репозиториев <code>mediawiki/skins/*</code> через git в подпапку <code dir=\"ltr\">skins/</code> папки, куда установлена MediaWiki.\n: Это не должно навредить вашему репозиторию, если вы MediaWiki-разработчик. См. [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual:Skin configuration] для получения информации о том, как включить темы оформления и выбрать тему по умолчанию.",
+       "default-skin-not-found": "Упс! Тема оформления по умолчанию для вашей вики <code>$wgDefaultSkin</code>, <code>$1</code> недоступна.\n\nВаша установка, похоже, содержит {{PLURAL:$4|следующую тему|следующие темы}} оформления. См. [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual:Skin configuration] с информацией о том, как включить {{PLURAL:$4|её|их и выбрать тему по умолчанию}}.\n\n$2\n\n; Если вы только что установили MediaWiki:\n: Вы, видимо, сделали это с Git или непосредственно из исходного кода с использованием другого способа. Тогда такое возможно. Попробуйте установить некоторые темы из [https://www.mediawiki.org/wiki/Category:All_skins каталога тем оформления сайта mediawiki.org]:\n:* скачав [https://www.mediawiki.org/wiki/Download архив установочных файлов], который содержит несколько тем оформления и расширений; вы можете скопировать из него папку <code>skins/</code>;\n:* скачав архивы отдельных тем оформления с [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org];\n:* клонировав один из репозиториев <code>mediawiki/skins/*</code> через git в подпапку <code  dir=\"ltr\">skins/</code> папки, куда установлена MediaWiki.\n: Это не должно навредить вашему репозиторию Git, если вы разработчик MediaWiki. См. [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual:Skin configuration] с информацией о том, как включить темы оформления и выбрать тему по умолчанию.\n; Если вы только что обновили MediaWiki:\n: MediaWiki версии 1.24 и новее больше не включает автоматически установленные темы (см. [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]).\nВы можете вставить {{PLURAL:$5|следующую строку|следующие строки}} в <code>LocalSettings.php</code>, чтобы включить {{PLURAL:$5|установленную в текущее время тему|все установленные в текущее время темы}} оформления: \n\n<pre dir=\"ltr\">$3</pre>\n\n; Если вы только что изменили <code>LocalSettings.php</code>:\n: Перепроверьте названия тем на наличие опечаток.",
+       "default-skin-not-found-no-skins": "Упс! Тема оформления по умолчанию для вашей вики <code>$wgDefaultSkin</code>, <code>$1</code> недоступна.\n\nУ вас нет установленных тем оформления.\n\n; Если вы только что установили или обновили MediaWiki:\n: Вы, видимо, сделали это с Git или непосредственно из исходного кода с использованием другого способа. Тогда такое возможно. MediaWiki версии 1.24 и новее не содержат темы оформления в основном репозитории. Попробуйте установить некоторые темы из [https://www.mediawiki.org/wiki/Category:All_skins каталога тем оформления сайта mediawiki.org]:\n:* crfxfd [https://www.mediawiki.org/wiki/Download архив установочных файлов], который содержит несколько тем оформления и расширений; вы можете скопировать папку <code>skins/</code> из него;\n:* скачав архивы отдельных тем оформления с [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org];\n:* rлонировав один из репозиториев <code>mediawiki/skins/*</code> через git в подпапку <code dir=\"ltr\">skins/</code> папки, куда установлена MediaWiki.\n: Это не должно навредить вашему репозиторию Git, если вы разработчик MediaWiki. См. [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual:Skin configuration] с информацией о том, как включить темы оформления и выбрать тему по умолчанию.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (включено)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''отключено''')",
        "mediastatistics": "Медиа-статистика",
index b5ea7b7..a91cc95 100644 (file)
@@ -23,11 +23,11 @@ class ArrayUtilsTest extends PHPUnit_Framework_TestCase {
        }
 
        function provideFindLowerBound() {
-               $self = $this;
-               $indexValueCallback = function ( $size ) use ( $self ) {
-                       return function ( $val ) use ( $self, $size ) {
-                               $self->assertTrue( $val >= 0 );
-                               $self->assertTrue( $val < $size );
+               $that = $this;
+               $indexValueCallback = function ( $size ) use ( $that ) {
+                       return function ( $val ) use ( $that, $size ) {
+                               $that->assertTrue( $val >= 0 );
+                               $that->assertTrue( $val < $size );
                                return $val;
                        };
                };
index 3161d18..3e284c8 100644 (file)
@@ -86,13 +86,22 @@ class WANObjectCacheTest extends MediaWikiTestCase {
                $cKey2 = wfRandomString();
 
                $wasSet = 0;
-               $func = function() use ( &$wasSet, $value ) { ++$wasSet; return $value; };
+               $func = function( $old, &$ttl ) use ( &$wasSet, $value ) {
+                       ++$wasSet;
+                       $ttl = 20; // override with another value
+                       return $value;
+               };
 
                $wasSet = 0;
                $v = $cache->getWithSetCallback( $key, $func, 30, array(), array( 'lockTSE' => 5 ) );
                $this->assertEquals( $v, $value );
                $this->assertEquals( 1, $wasSet, "Value regenerated" );
 
+               $curTTL = null;
+               $v = $cache->get( $key, $curTTL );
+               $this->assertLessThanOrEqual( 20, $curTTL, 'Current TTL between 19-20 (overriden)' );
+               $this->assertGreaterThanOrEqual( 19, $curTTL, 'Current TTL between 19-20 (overriden)' );
+
                $wasSet = 0;
                $v = $cache->getWithSetCallback( $key, $func, 30, array(), array( 'lockTSE' => 5 ) );
                $this->assertEquals( $v, $value );
index b95316c..d47ffa9 100644 (file)
@@ -36,6 +36,10 @@ class ExtensionProcessorTest extends MediaWikiTestCase {
        }
 
        public static function provideRegisterHooks() {
+               // Format:
+               // Current $wgHooks
+               // Content in extension.json
+               // Expected value of $wgHooks
                return array(
                        // No hooks
                        array(
@@ -64,6 +68,22 @@ class ExtensionProcessorTest extends MediaWikiTestCase {
                                        'FooBaz' => array( 'FooBazCallback' ),
                                ),
                        ),
+                       // Callbacks for FooBaz wrapped in an array
+                       array(
+                               array(),
+                               array( 'Hooks' => array( 'FooBaz' => array( 'Callback1' ) ) ) + self::$default,
+                               array(
+                                       'FooBaz' => array( 'Callback1' ),
+                               ),
+                       ),
+                       // Multiple callbacks for FooBaz hook
+                       array(
+                               array(),
+                               array( 'Hooks' => array( 'FooBaz' => array( 'Callback1', 'Callback2' ) ) ) + self::$default,
+                               array(
+                                       'FooBaz' => array( 'Callback1', 'Callback2' ),
+                               ),
+                       ),
                );
        }
 
index d0a7980..4305ceb 100644 (file)
@@ -96,17 +96,17 @@ class CachingSiteStoreTest extends MediaWikiTestCase {
                        ->getMock();
 
                // php 5.3 compatibility!
-               $self = $this;
+               $that = $this;
 
                $dbSiteStore->expects( $this->any() )
                        ->method( 'getSite' )
-                       ->will( $this->returnValue( $self->getTestSite() ) );
+                       ->will( $this->returnValue( $that->getTestSite() ) );
 
                $dbSiteStore->expects( $this->any() )
                        ->method( 'getSites' )
-                       ->will( $this->returnCallback( function() use( $self ) {
+                       ->will( $this->returnCallback( function() use ( $that ) {
                                $siteList = new SiteList();
-                               $siteList->setSite( $self->getTestSite() );
+                               $siteList->setSite( $that->getTestSite() );
 
                                return $siteList;
                        } ) );
index cb0316a..64b195d 100644 (file)
@@ -34,11 +34,11 @@ class SiteImporterTest extends PHPUnit_Framework_TestCase {
        private function newSiteImporter( array $expectedSites, $errorCount ) {
                $store = $this->getMock( 'SiteStore' );
 
-               $self = $this;
+               $that = $this;
                $store->expects( $this->once() )
                        ->method( 'saveSites' )
-                       ->will( $this->returnCallback( function ( $sites ) use ( $expectedSites, $self ) {
-                               $self->assertSitesEqual( $expectedSites, $sites );
+                       ->will( $this->returnCallback( function ( $sites ) use ( $expectedSites, $that ) {
+                               $that->assertSitesEqual( $expectedSites, $sites );
                        } ) );
 
                $store->expects( $this->any() )