Merge "resourceloader: Remove checkCssHandles for modules without styles"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 28 Aug 2018 21:55:00 +0000 (21:55 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 28 Aug 2018 21:55:00 +0000 (21:55 +0000)
32 files changed:
includes/DefaultSettings.php
includes/registration/VersionChecker.php
includes/revisiondelete/RevDelArchiveItem.php
includes/revisiondelete/RevDelArchivedFileItem.php
includes/revisiondelete/RevDelArchivedRevisionItem.php
includes/revisiondelete/RevDelFileItem.php
includes/revisiondelete/RevDelRevisionItem.php
includes/specials/SpecialDeletedContributions.php
languages/i18n/ast.json
languages/i18n/be-tarask.json
languages/i18n/bg.json
languages/i18n/de.json
languages/i18n/fa.json
languages/i18n/gcr.json
languages/i18n/my.json
languages/i18n/nl.json
languages/i18n/nn.json
languages/i18n/ru.json
languages/i18n/sr-ec.json
languages/i18n/tr.json
languages/i18n/tt-cyrl.json
languages/i18n/ur.json
languages/i18n/zh-hant.json
maintenance/resources/foreign-resources.yaml
maintenance/resources/manageForeignResources.php
resources/src/mediawiki.base/mediawiki.base.js
resources/src/mediawiki.notification/notification.js
resources/src/startup/mediawiki.js
resources/src/startup/startup.js
tests/phan/config.php
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/includes/Storage/RevisionStoreDbTestBase.php

index ea368bc..2499077 100644 (file)
@@ -4399,7 +4399,7 @@ $wgPreprocessorCacheThreshold = 1000;
 $wgEnableScaryTranscluding = false;
 
 /**
- * Expiry time for transcluded templates cached in transcache database table.
+ * Expiry time for transcluded templates cached in object cache.
  * Only used $wgEnableInterwikiTranscluding is set to true.
  */
 $wgTranscludeCacheExpiry = 3600;
index 59853b4..1569e08 100644 (file)
@@ -183,23 +183,19 @@ class VersionChecker {
                                'missing' => $dependencyName,
                        ];
                }
+               if ( $constraint === '*' ) {
+                       // short-circuit since any version is OK.
+                       return false;
+               }
                // Check if the dependency has specified a version
                if ( !isset( $this->loaded[$dependencyName]['version'] ) ) {
-                       // If we depend upon any version, and none is set, that's fine.
-                       if ( $constraint === '*' ) {
-                               wfDebug( "{$dependencyName} does not expose its version, but {$checkedExt}"
-                                       . " mentions it with constraint '*'. Assume it's ok so." );
-                               return false;
-                       } else {
-                               // Otherwise, mark it as incompatible.
-                               $msg = "{$dependencyName} does not expose its version, but {$checkedExt}"
-                                       . " requires: {$constraint}.";
-                               return [
-                                       'msg' => $msg,
-                                       'type' => "incompatible-$type",
-                                       'incompatible' => $checkedExt,
-                               ];
-                       }
+                       $msg = "{$dependencyName} does not expose its version, but {$checkedExt}"
+                               . " requires: {$constraint}.";
+                       return [
+                               'msg' => $msg,
+                               'type' => "incompatible-$type",
+                               'incompatible' => $checkedExt,
+                       ];
                } else {
                        // Try to get a constraint for the dependency version
                        try {
index 679acc6..11f2d13 100644 (file)
  * Item class for a archive table row
  */
 class RevDelArchiveItem extends RevDelRevisionItem {
-       public function __construct( $list, $row ) {
-               RevDelItem::__construct( $list, $row );
-               $this->revision = Revision::newFromArchiveRow( $row,
-                       [ 'page' => $this->list->title->getArticleID() ] );
+       protected static function initRevision( $list, $row ) {
+               return Revision::newFromArchiveRow( $row,
+                       [ 'page' => $list->title->getArticleID() ] );
        }
 
        public function getIdField() {
index d36fac9..00e40a0 100644 (file)
@@ -29,11 +29,14 @@ class RevDelArchivedFileItem extends RevDelFileItem {
        protected $lockFile;
 
        public function __construct( $list, $row ) {
-               RevDelItem::__construct( $list, $row );
-               $this->file = ArchivedFile::newFromRow( $row );
+               parent::__construct( $list, $row );
                $this->lockFile = RepoGroup::singleton()->getLocalRepo()->newFile( $row->fa_name );
        }
 
+       protected static function initFile( $list, $row ) {
+               return ArchivedFile::newFromRow( $row );
+       }
+
        public function getIdField() {
                return 'fa_id';
        }
index d839fcf..fd214e1 100644 (file)
  * used via RevDelRevisionList.
  */
 class RevDelArchivedRevisionItem extends RevDelArchiveItem {
-       public function __construct( $list, $row ) {
-               RevDelItem::__construct( $list, $row );
-
-               $this->revision = Revision::newFromArchiveRow( $row,
-                       [ 'page' => $this->list->title->getArticleID() ] );
-       }
-
        public function getIdField() {
                return 'ar_rev_id';
        }
index 0ca84d7..c7941b7 100644 (file)
@@ -30,7 +30,18 @@ class RevDelFileItem extends RevDelItem {
 
        public function __construct( $list, $row ) {
                parent::__construct( $list, $row );
-               $this->file = RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row );
+               $this->file = static::initFile( $list, $row );
+       }
+
+       /**
+        * Create file object from $row sourced from $list
+        *
+        * @param RevDelFileList $list
+        * @param mixed $row
+        * @return mixed
+        */
+       protected static function initFile( $list, $row ) {
+               return RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row );
        }
 
        public function getIdField() {
index 7b5d130..2cfa2ab 100644 (file)
@@ -28,7 +28,18 @@ class RevDelRevisionItem extends RevDelItem {
 
        public function __construct( $list, $row ) {
                parent::__construct( $list, $row );
-               $this->revision = new Revision( $row );
+               $this->revision = static::initRevision( $list, $row );
+       }
+
+       /**
+        * Create revision object from $row sourced from $list
+        *
+        * @param RevisionListBase $list
+        * @param mixed $row
+        * @return Revision
+        */
+       protected static function initRevision( $list, $row ) {
+               return new Revision( $row );
        }
 
        public function getIdField() {
index 975d64e..3f87712 100644 (file)
@@ -61,7 +61,9 @@ class DeletedContributionsPage extends SpecialPage {
                $opts->validateIntBounds( 'limit', 0, $this->getConfig()->get( 'QueryPageDefaultLimit' ) );
 
                if ( $par !== null ) {
-                       $opts->setValue( 'target', $par );
+                       // Beautify the username
+                       $par = User::getCanonicalName( $par, false );
+                       $opts->setValue( 'target', (string)$par );
                }
 
                $ns = $opts->getValue( 'namespace' );
index aaea4c7..b1977cf 100644 (file)
        "confirm-unwatch-top": "¿Desaniciar esta páxina de la to llista de vixilancia?",
        "confirm-rollback-button": "Aceutar",
        "confirm-rollback-top": "¿Revertir les ediciones a esta páxina?",
+       "confirm-mcrundo-title": "Desfacer un cambéu",
+       "mcrundofailed": "Falló desfacer",
+       "mcrundo-missingparam": "Faltan parámetros riquíos na solicitú.",
+       "mcrundo-changed": "La páxina cambió desque visti les diferencies. Revisa'l cambiu nuevu.",
        "quotation-marks": "«$1»",
        "imgmultipageprev": "← páxina anterior",
        "imgmultipagenext": "páxina siguiente →",
index b26a8ba..98d0ee6 100644 (file)
        "confirm-rollback-top": "Адкаціць праўкі на гэтай старонцы?",
        "confirm-mcrundo-title": "Адмяніць зьмену",
        "mcrundofailed": "Адмена не атрымалася",
+       "mcrundo-missingparam": "Адсутнічаюць абавязковыя парамэтры для запыту.",
+       "mcrundo-changed": "Гэтая старонка была зьмененая з моманту, калі вы праглядалі зьмены. Калі ласка, праглядзіце новую зьмену.",
        "quotation-marks": "«$1»",
        "imgmultipageprev": "← папярэдняя старонка",
        "imgmultipagenext": "наступная старонка →",
index 7d39af6..ee6699b 100644 (file)
        "ns-specialprotected": "Специалните страници не могат да бъдат редактирани.",
        "titleprotected": "Тази страница е била защитена срещу създаване от [[User:$1|$1]].\nПосочената причина е <em>$2</em>.",
        "filereadonlyerror": "Файлът „$1“ не може да бъде променен, тъй като файловото хранилище „$2“ е в режим само за четене.\n\nСистемният администратор, който го е заключил, е посочил следната причина: „$3“.",
+       "invalidtitle": "Невалидно заглавие",
        "invalidtitle-knownnamespace": "Невалидно заглавие с именно пространство „$2“ и текст „$3“",
        "invalidtitle-unknownnamespace": "Невалидно заглавие с неразпознато именно пространство номер $1 и текст „$2“",
        "exception-nologin": "Не сте влезли в системата",
        "rcfilters-group-results-by-page": "Групиране на резултатите по страница",
        "rcfilters-activefilters": "Активни филтри",
        "rcfilters-activefilters-hide": "Скриване",
+       "rcfilters-activefilters-show": "Показване",
        "rcfilters-advancedfilters": "Разширени филтри",
        "rcfilters-limit-title": "Резултати за показване",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|промяна|промени}}, $2",
index 6428414..96b50ec 100644 (file)
        "edit-error-long": "Fehler:\n\n$1",
        "revid": "Version $1",
        "pageid": "Seitenkennung $1",
-       "interfaceadmin-info": "$1\n\nBerechtigungen für das Bearbeiten von wikiweiten CSS/JS/JSON-Dateien wurden kürzlich von dem Recht <code>editinterface</code> getrennt. Falls du nicht verstehst, warum du diesen Fehler erhältst, siehe bitte [[mw:MediaWiki_1.32/interface-admin]].",
+       "interfaceadmin-info": "$1\n\nBerechtigungen für das Bearbeiten von wikiweiten CSS/JS/JSON-Dateien wurden kürzlich vom Recht <code>editinterface</code> getrennt. Falls du nicht verstehst, warum du diesen Fehler erhältst, siehe [[mw:MediaWiki_1.32/interface-admin]].",
        "rawhtml-notallowed": "&lt;html&gt;-Tags können nicht außerhalb von normalen Seiten verwendet werden.",
        "gotointerwiki": "{{SITENAME}} verlassen",
        "gotointerwiki-invalid": "Der angegebene Titel ist ungültig.",
index ea902bb..609f692 100644 (file)
        "activeusers-noresult": "کاربری پیدا نشد.",
        "activeusers-submit": "نمایش کاربران فعال",
        "listgrouprights": "اختیارات گروه‌های کاربری",
-       "listgrouprights-summary": "فهرست زیر شامل گروه‌های کاربری تعریف شده در این ویکی و اختیارات داده شده به آن‌ها است.\nاطلاعات بیشتر در مورد هر یک از اختیارات را در [[{{MediaWiki:Listgrouprights-helppage}}]] بیابید.",
+       "listgrouprights-summary": "فهرست زیر شامل گروه‌های کاربری تعریف شده در این ویکی و اختیارات داده شده به آن‌ها است.\nاطلاعات بیشتر در مورد هر کدام از آنها را در [[{{MediaWiki:Listgrouprights-helppage}}|اختیارات گروه‌های کاربری]] بیابید.",
        "listgrouprights-key": "* <span class=\"listgrouprights-granted\">اختیارات داده‌شده</span>\n* <span class=\"listgrouprights-revoked\">اختیارات گرفته‌شده</span>",
        "listgrouprights-group": "گروه",
        "listgrouprights-rights": "دسترسی‌ها",
index 261420e..2889465 100644 (file)
        "userlogin-yourname-ph": "Antré zòt non di itilizatò",
        "createacct-another-username-ph": "Antré non-an di itilizatò",
        "yourpassword": "Mo di pas :",
-       "userlogin-yourpassword": "Mo di pas",
+       "userlogin-yourpassword": "Modipas",
        "userlogin-yourpassword-ph": "Antré zòt mo di pas",
        "createacct-yourpassword-ph": "Antré oun mo di pas",
        "yourpasswordagain": "Konfirmé mo di pas :",
-       "createacct-yourpasswordagain": "Konfirmé mo di pas",
+       "createacct-yourpasswordagain": "Konfirmen modipas-a",
        "createacct-yourpasswordagain-ph": "Antré òkò menm mo di pas",
        "userlogin-remembermypassword": "Gardé mo sésyon aktiv",
        "userlogin-signwithsecure": "Itilizé roun konnègsyon sékirizé",
index 45bb7b6..3cbb4a7 100644 (file)
        "sig_tip": "အချိန်ပါပြသော သင့်လက်မှတ်",
        "hr_tip": "မျဉ်းလဲ (စိစစ်သုံးရန်)",
        "summary": "အ​ကျဉ်း​ချုပ်​ -",
-       "subject": "အကြောင်းအရာ -",
+       "subject": "အကြောင်းအရာ:",
        "minoredit": "အရေးမကြီးသော ​ပြင်​ဆင်​မှု ​ဖြစ်​သည်​",
        "watchthis": "ဤစာမျက်နှာကို စောင့်ကြည့်ရန်",
        "savearticle": "ဤစာမျက်နှာကို သိမ်းရန်",
        "allmessages": "စနစ်၏ သတင်းများ",
        "allmessagesname": "အမည်",
        "allmessagesdefault": "ပုံမှန် အသိပေးချက် စာသား",
+       "allmessagescurrent": "လက်ရှိ မက်ဆေ့စာသား",
        "allmessages-filter-legend": "စစ်ထုတ်ခြင်း",
        "allmessages-filter-unmodified": "မပြုပြင်ထားသော",
        "allmessages-filter-all": "အားလုံး",
        "tags-title": "အမည်တွဲများ",
        "tags-tag": "အမည်တွဲ အမည်",
        "tags-description-header": "ဆိုလိုရင်းအဓိပ္ပာယ် အပြည့်အစုံ",
+       "tags-source-header": "ရင်းမြစ်",
        "tags-active-yes": "မှန်",
        "tags-active-no": "မလုပ်ပါ",
        "tags-source-extension": "ဆော့ဝဲလ်မှ သတ်မှတ်ထားသော",
        "htmlform-submit": "ထည့်သွင်းရန်",
        "htmlform-reset": "ပြောင်းလဲထားသည်များ မလုပ်တော့ရန်",
        "htmlform-selectorother-other": "အခြား",
+       "htmlform-no": "မလုပ်ပါ",
        "htmlform-chosen-placeholder": "လုပ်ဆောင်ချက်တစ်ခု ရွေးချယ်ရန်",
        "htmlform-cloner-create": "ပို၍ ထပ်ပေါင်းရန်",
        "htmlform-cloner-delete": "ဖယ်ရှားရန်",
index da1d16f..8716ae9 100644 (file)
        "confirm-rollback-top": "Bewerkingen op deze pagina ongedaan maken?",
        "confirm-mcrundo-title": "Een wijziging ongedaan maken",
        "mcrundofailed": "Ongedaan maken mislukt",
-       "mcrundo-missingparam": "Er ontbreken benodigde parameters in het verzoek.",
+       "mcrundo-missingparam": "Er ontbreken nodige parameters in het verzoek.",
        "quotation-marks": "\"$1\"",
        "imgmultipageprev": "← vorige pagina",
        "imgmultipagenext": "volgende pagina →",
index 154264a..c0eb191 100644 (file)
        "rcfilters-watchlist-markseen-button": "Merk alle endringar som sette",
        "rcfilters-watchlist-edit-watchlist-button": "Endra lista over sider du overvaker",
        "rcfilters-watchlist-showupdated": "Sider du ikkje har vitja sidan dei vart endra er viste med <strong>feit</strong> skrift.",
+       "rcfilters-filter-showlinkedfrom-label": "Vis endringar på sider det vert lenkja til på sida",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Sider som det vert lenkja til på</strong> den valde sida",
+       "rcfilters-filter-showlinkedto-label": "Vis endringar på sider som lenkjar til sida",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>Sider som lenkjar til</strong> den valde sida",
        "rcnotefrom": "Nedanfor er endringane gjorde sidan <strong>$2</strong> viste (opp til <strong>$1</strong> stykke)",
        "rclistfromreset": "Nullstill datoval",
        "rclistfrom": "Vis nye endringar sidan $3 $2",
index 1f509d9..39bd60d 100644 (file)
                        "AttemptToCallNil",
                        "Stjn",
                        "Vlad5250",
-                       "Marshmallych"
+                       "Marshmallych",
+                       "Atsirlin"
                ]
        },
        "tog-underline": "Подчёркивание ссылок:",
        "jumpto": "Перейти к:",
        "jumptonavigation": "навигация",
        "jumptosearch": "поиск",
-       "view-pool-error": "Ð\98звиниÑ\82е, Ð² Ð½Ð°Ñ\81Ñ\82оÑ\8fÑ\89ий Ð¼Ð¾Ð¼ÐµÐ½Ñ\82 Ñ\81еÑ\80веÑ\80Ñ\8b Ð¿ÐµÑ\80егÑ\80Ñ\83женÑ\8b.\nСлиÑ\88ком Ð¼Ð½Ð¾Ð³Ð¾ Ñ\83Ñ\87аÑ\81Ñ\82ников Ð¿Ñ\8bÑ\82аÑ\8eÑ\82Ñ\81Ñ\8f ÐµÑ\91 Ð¿Ñ\80оÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c.\nПожалуйста, подождите немного перед повторной попыткой обращения к этой странице.\n\n$1",
+       "view-pool-error": "Ð\98звиниÑ\82е, Ð² Ð½Ð°Ñ\81Ñ\82оÑ\8fÑ\89ий Ð¼Ð¾Ð¼ÐµÐ½Ñ\82 Ñ\81еÑ\80веÑ\80Ñ\8b Ð¿ÐµÑ\80егÑ\80Ñ\83женÑ\8b.\nСлиÑ\88ком Ð¼Ð½Ð¾Ð³Ð¾ Ñ\83Ñ\87аÑ\81Ñ\82ников Ð¿Ñ\8bÑ\82аÑ\8eÑ\82Ñ\81Ñ\8f Ð¿Ñ\80оÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c ÐµÑ\91 Ð¾Ð´Ð½Ð¾Ð²Ñ\80еменно.\nПожалуйста, подождите немного перед повторной попыткой обращения к этой странице.\n\n$1",
        "generic-pool-error": "Извините, в настоящий момент серверы перегружены.\nСлишком много участников пытаются просмотреть этот ресурс.\nПожалуйста, подождите и повторите попытку обращения к нему позже.",
        "pool-timeout": "Истекло время ожидания блокировки",
        "pool-queuefull": "Пул запросов полон",
        "privacypage": "Project:Политика конфиденциальности",
        "badaccess": "Ошибка доступа",
        "badaccess-group0": "Вы не можете выполнить запрошенное действие.",
-       "badaccess-groups": "Ð\97апÑ\80оÑ\88енное Ð´ÐµÐ¹Ñ\81Ñ\82вие Ð¼Ð¾Ð³Ñ\83Ñ\82 Ð²Ñ\8bполнÑ\8fÑ\82Ñ\8c Ñ\82олÑ\8cко Ñ\83Ñ\87аÑ\81Ñ\82ники {{PLURAL:$2|1=из Ð³Ñ\80Ñ\83ппÑ\8b Â«$1»|одной Ð¸Ð· Ñ\81ледÑ\83Ñ\8eÑ\89иÑ\85 Ð³Ñ\80Ñ\83пп: $1}}",
+       "badaccess-groups": "Запрошенное действие могут выполнять участники {{PLURAL:$2|1=из группы «$1»|одной из следующих групп: $1}}",
        "versionrequired": "Требуется MediaWiki версии $1",
        "versionrequiredtext": "Для работы с этой страницей требуется MediaWiki версии $1. См. [[Special:Version|информацию о программном обеспечении]].",
        "ok": "OK",
        "perfcachedts": "Данные взяты из кэша; последний раз он обновлялся в $1. В кэше хранится не более {{PLURAL:$4|1=одной записи|$4 записи|$4 записей}}.",
        "querypage-no-updates": "Обновление этой страницы сейчас отключено.\nПредставленные здесь данные не будут обновляться.",
        "viewsource": "Просмотр кода",
-       "viewsource-title": "Ð\9fÑ\80оÑ\81моÑ\82Ñ\80 Ð¸Ñ\81Ñ\85одного Ñ\82екÑ\81Ñ\82а страницы $1",
+       "viewsource-title": "Ð\9fÑ\80оÑ\81моÑ\82Ñ\80 ÐºÐ¾Ð´а страницы $1",
        "actionthrottled": "Ограничение по скорости",
        "actionthrottledtext": "Вы исчерпали установленное для борьбы со спамом ограничение на максимальное количество попыток выполнения запрошенного действия в короткий промежуток времени.\nПожалуйста, повторите попытку через несколько минут.",
        "protectedpagetext": "Эта страница защищена для предотвращения её редактирования или совершений других действий.",
        "virus-scanfailed": "ошибка сканирования (код $1)",
        "virus-unknownscanner": "неизвестный антивирус:",
        "logouttext": "<strong>Вы завершили сеанс работы.</strong>\n\nНекоторые страницы могут продолжить отображаться так, как будто вы все ещё не завершили сеанс, пока вы не обновите кэш браузера.",
-       "cannotlogoutnow-title": "Невозможно выйти прямо сейчас",
-       "cannotlogoutnow-text": "Нельзя выйти во время использования $1.",
+       "cannotlogoutnow-title": "Ð\9dевозможно Ð²Ñ\8bйÑ\82и Ð¸Ð· Ñ\81иÑ\81Ñ\82емÑ\8b Ð¿Ñ\80Ñ\8fмо Ñ\81ейÑ\87аÑ\81",
+       "cannotlogoutnow-text": "Ð\9dелÑ\8cзÑ\8f Ð²Ñ\8bйÑ\82и Ð¸Ð· Ñ\81иÑ\81Ñ\82емÑ\8b Ð²Ð¾ Ð²Ñ\80емÑ\8f Ð¸Ñ\81полÑ\8cзованиÑ\8f $1.",
        "welcomeuser": "Добро пожаловать, $1!",
-       "welcomecreation-msg": "Ваша учётная запись успешно создана.\nТеперь вы также можете провести  [[Special:Preferences|персональную настройку]] сайта {{SITENAME}}.",
+       "welcomecreation-msg": "Ваша учётная запись была создана.\nТеперь вы также можете изменить [[Special:Preferences|персональные настройки]] для сайта {{SITENAME}}, если вы желаете.",
        "yourname": "Имя учётной записи:",
        "userlogin-yourname": "Имя учётной записи",
        "userlogin-yourname-ph": "Введите имя вашей учётной записи",
        "userlogin-signwithsecure": "Защищённое соединение",
        "cannotlogin-title": "Невозможно войти",
        "cannotlogin-text": "Вход в систему невозможен.",
-       "cannotloginnow-title": "Невозможно войти прямо сейчас",
+       "cannotloginnow-title": "Ð\9dевозможно Ð²Ð¾Ð¹Ñ\82и Ð² Ñ\81иÑ\81Ñ\82емÑ\83 Ð¿Ñ\80Ñ\8fмо Ñ\81ейÑ\87аÑ\81",
        "cannotloginnow-text": "Нельзя войти во время использования $1.",
        "cannotcreateaccount-title": "Невозможно создать учётные записи",
        "cannotcreateaccount-text": "Прямое создание учетных записей не включено в этой вики.",
        "userlogout": "Завершение сеанса",
        "notloggedin": "Вы не представились системе",
        "userlogin-noaccount": "Нет учётной записи?",
-       "userlogin-joinproject": "Присоединиться к проекту",
+       "userlogin-joinproject": "Присоединиться к проекту {{SITENAME}}.",
        "createaccount": "Создать учётную запись",
        "userlogin-resetpassword-link": "Сбросить ваш пароль?",
        "userlogin-helplink2": "Помощь по входу",
        "createacct-error": "Ошибка создания учётной записи",
        "createaccounterror": "Невозможно создать учётную запись: $1",
        "nocookiesnew": "Участник зарегистрирован, но не представлен. {{SITENAME}} использует «cookies» для представления участников. У вас «cookies» запрещены. Пожалуйста, разрешите их, а затем представьтесь со своиим новым именем участника и паролем.",
-       "nocookieslogin": "{{SITENAME}} использует «cookies» для представления участников. Вы их отключили. Пожалуйста, включите их и попробуйте снова.",
+       "nocookieslogin": "{{SITENAME}} использует «cookies»-файлы для представления участников. Вы отключили использование «cookies»-файлов. Пожалуйста, включите использование «cookies»-файлов и попробуйте снова.",
        "nocookiesfornew": "Учётная запись участника не была создана из-за невозможности проверить её источник. \nУбедитесь, что включены «cookies», обновите страницу и попробуйте ещё раз.",
        "nocookiesforlogin": "{{int:nocookieslogin}}",
        "createacct-loginerror": "Учётная запись была успешно создана, но вы не смогли войти в систему автоматически. Пожалуйста, [[Special:UserLogin|авторизуйтесь вручную]].",
        "createacct-another-realname-tip": "Настоящее имя (необязательное поле).\nЕсли вы укажете его, то оно будет использовано для того, чтобы показать, кем была внесена правка страницы.",
        "pt-login": "Войти",
        "pt-login-button": "Войти",
-       "pt-login-continue-button": "Продолжить процедуру входа",
+       "pt-login-continue-button": "Продолжить процедуру входа в систему",
        "pt-createaccount": "Создать учётную запись",
        "pt-userlogout": "Выйти",
        "php-mail-error-unknown": "Неизвестная ошибка в PHP-функции mail()",
        "undo-main-slot-only": "Правка не может быть отменена, поскольку оно включает контент вне основного слота.",
        "undo-norev": "Правка не может быть отменена, так как её не существует или она была удалена.",
        "undo-nochange": "Правка, похоже, уже была отменена.",
-       "undo-summary": "Отмена правки $1, сделанной {{gender:$2|участником|участницей}} [[Special:Contributions/$2|$2]] ([[User talk:$2|обсуждение]])",
+       "undo-summary": "Отмена правки $1, сделанной [[Special:Contributions/$2|$2]] ([[User talk:$2|обсуждение]])",
        "undo-summary-username-hidden": "Отмена правки $1, сделанной участником, чьё имя скрыто",
        "cantcreateaccount-text": "Создание учётных записей с этого IP-адреса (<strong>$1</strong>) было заблокировано {{GENDER:$3|участником|участницей|}} [[User:$3|$3]].\n\n$3 {{GENDER:$3|указал|указала}} следующую причину: <em>$2</em>.",
        "cantcreateaccount-range-text": "{{GENDER:$3|Участник|Участница}} [[User:$3|$3]] {{GENDER:$3|установил|установила}} запрет на создание учётных записей для диапазона IP-адресов <strong>$1</strong>, включающего ваш IP-адрес (<strong>$4</strong>). \n\nБыла указана следующая причина: <em>$2</em>.",
        "last": "пред.",
        "page_first": "первая",
        "page_last": "последняя",
-       "histlegend": "Выбор версий: отметьте версии страницы, которые вы хотите сравнить, и нажмите <strong>{{int:compare-submit}}/strong>.<br />\nПояснения: <strong>({{int:cur}})/strong> — отличия от текущей версии; <strong>({{int:last}})/strong> — отличия от предшествующей версии; <strong>{{int:minoreditletter}}/strong> — незначительные изменения.",
+       "histlegend": "Выбор версий: отметьте версии страницы, которые вы хотите сравнить, и нажмите <strong>{{int:compare-submit}}</strong>.<br />\nПояснения: <strong>({{int:cur}})</strong> — отличия от текущей версии; <strong>({{int:last}})</strong> — отличия от предшествующей версии; <strong>{{int:minoreditletter}}</strong> — незначительные изменения.",
        "history-fieldset-title": "Поиск правок",
        "history-show-deleted": "Только удалённые правки",
        "histfirst": "старейшие",
        "rev-showdeleted": "показать",
        "revisiondelete": "Удалить/восстановить версии страницы",
        "revdelete-nooldid-title": "Не задана целевая версия",
-       "revdelete-nooldid-text": "Ð\92Ñ\8b Ð½Ðµ Ð·Ð°Ð´Ð°Ð»Ð¸ Ð²ÐµÑ\80Ñ\81иÑ\8e (веÑ\80Ñ\81ии), Ð¸Ð»Ð¸ Ñ\83казаннаÑ\8f Ð²ÐµÑ\80Ñ\81иÑ\8f Ð½Ðµ Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82, или же вы пытаетесь скрыть текущую версию.",
+       "revdelete-nooldid-text": "ЦелеваÑ\8f Ð²ÐµÑ\80Ñ\81иÑ\8f Ð½Ðµ Ð·Ð°Ð´Ð°Ð½Ñ\8b, Ñ\83казаннаÑ\8f Ð²ÐµÑ\80Ñ\81иÑ\8f Ð½Ðµ Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 или же вы пытаетесь скрыть текущую версию.",
        "revdelete-no-file": "Указанный файл не существует.",
        "revdelete-show-file-confirm": "Вы уверены, что вы хотите просмотреть удалённую версию файла «<nowiki>$1</nowiki>» от $2, $3?",
        "revdelete-show-file-submit": "Да",
        "default": "по умолчанию",
        "prefs-files": "Файлы",
        "prefs-custom-css": "Собственный CSS",
-       "prefs-custom-json": "Ð\9fолÑ\8cзоваÑ\82елÑ\8cÑ\81кий JSON",
+       "prefs-custom-json": "СобÑ\81Ñ\82веннÑ\8bй JSON",
        "prefs-custom-js": "Собственный JS",
        "prefs-common-config": "Общие CSS/JSON/JavaScript для всех тем оформления:",
        "prefs-reset-intro": "Эта страница может быть использована для сброса ваших настроек на стандартные.\nУчтите, что это действие невозможно отменить.",
        "userrights-groupsmember": "Состоит в группах:",
        "userrights-groupsmember-auto": "Неявно состоит в группах:",
        "userrights-groupsmember-type": "$1",
-       "userrights-groups-help": "Вы можете изменить группы, в которые входит {{GENDER:$1|этот участник|эта участница}}.\n* Если около названия группы стоит отметка — {{GENDER:$1|участник|участница}} входит в эту группу.\n* Если отметка не стоит — {{GENDER:$1|участник|участница}} не входит в эту группу.\n* Символ * указывает на то, что вы не сможете удалить {{GENDER:$1|участника|участницу}} из группы, если добавите {{GENDER:$1|его|её}} в неё (или наоборот).\n* Символ # указывает на то, что вы можете только отложить время истечения членства в этой группы, вы не можете перенести его на более ранний срок.",
+       "userrights-groups-help": "Вы можете изменить группы, в которые входит {{GENDER:$1|этот участник|эта участница}}.\n* Если около названия группы стоит отметка — {{GENDER:$1|участник|участница}} входит в эту группу.\n* Если отметка не стоит — {{GENDER:$1|участник|участница}} не входит в эту группу.\n* Символ * указывает на то, что вы не сможете удалить {{GENDER:$1|участника|участницу}} из группы, если добавите {{GENDER:$1|его|её}} в неё (или наоборот).\n* Символ # указывает на то, что вы можете только отложить, но не перенести время истечения членства в этой группе на более ранний срок.",
        "userrights-reason": "Причина:",
        "userrights-no-interwiki": "У вас нет разрешения изменять права участников в других вики.",
        "userrights-nodatabase": "База данных $1 не существует или расположена не локально.",
        "block": "Блокировка участника",
        "unblock": "Разблокировка участника",
        "blockip": "Заблокировать {{GENDER:$1|участника|участницу}}",
-       "blockiptext": "Используйте форму ниже, чтобы заблокировать возможность записи с определённого IP-адреса или имени участника.\nЭто может быть сделано только для предотвращения вандализма и только в соответствии с [[{{MediaWiki:Policy-url}}|правилами]].\nНиже укажите конкретную причину (к примеру, процитируйте некоторые страницы с признаками вандализма).\nВы можете заблокировать диапазоны IP-адресов, используя [https://ru.wikipedia.org/wiki/Бесклассовая_адресация CIDR]-синтаксис. Максимально допустимый диапазон — /$1 для протокола IPv4 и /$2 для протокола IPv6.",
+       "blockiptext": "Используйте форму ниже, чтобы заблокировать возможность редактирования с определённого IP-адреса или имени участника.\nЭтот инструмент следует использовать для предотвращения вандализма и только в соответствии с [[{{MediaWiki:Policy-url}}|правилами]].\nНиже укажите конкретную причину (к примеру, процитируйте некоторые страницы с признаками вандализма).\nВы можете заблокировать диапазоны IP-адресов, используя [https://ru.wikipedia.org/wiki/Бесклассовая_адресация CIDR]-синтаксис. Максимально допустимый диапазон — /$1 для протокола IPv4 и /$2 для протокола IPv6.",
        "ipaddressorusername": "IP-адрес или имя участника:",
        "ipbexpiry": "Закончится через:",
        "ipbreason": "Причина:",
        "ipboptions": "2 часа:2 hours,1 день:1 day,3 дня:3 days,1 неделя:1 week,2 недели:2 weeks,1 месяц:1 month,3 месяца:3 months,6 месяцев:6 months,1 год:1 year,бессрочно:infinite",
        "ipbhidename": "Скрыть имя участника из правок и списков",
        "ipbwatchuser": "Добавить в список наблюдения личную страницу участника и его страницу обсуждения",
-       "ipb-disableusertalk": "Запретить этому участнику редактировать свою страницу обсуждения во время блокировки",
+       "ipb-disableusertalk": "Запретить этому участнику редактировать свою страницу обсуждения",
        "ipb-change-block": "Переблокировать участника с этими настройками",
        "ipb-confirm": "Подтвердить блокировку",
        "badipaddress": "IP-адрес записан в неправильном формате, или участника с таким именем не существует.",
        "autoblocklist-submit": "Найти",
        "autoblocklist-legend": "Список автоблокировок",
        "autoblocklist-localblocks": "{{PLURAL:$1|Локальная автоблокировка|Локальные автоблокировки}}",
-       "autoblocklist-total-autoblocks": "Ð\92Ñ\81его Ð°Ð²Ñ\82облоков: $1",
+       "autoblocklist-total-autoblocks": "Ð\92Ñ\81его Ð°Ð²Ñ\82облокиÑ\80овок: $1",
        "autoblocklist-empty": "Список автоблокировок пуст.",
        "autoblocklist-otherblocks": "{{PLURAL:$1|Другая автоблокировка|Другие автоблокировки}}",
        "ipblocklist": "Заблокированные участники",
        "moveuserpage-warning": "<strong>Внимание:</strong> вы собираетесь переименовать страницу участника. Пожалуйста, обратите внимание, что переименована будет только страница, участник <strong>не</strong> будет переименован.",
        "movecategorypage-warning": "<strong>Предупреждение:</strong> Вы собираетесь переименовать страницу категории. Пожалуйста, обратите внимание, что будет переименована только эта страница, а все страницы старой категории <em>не</em> будут перекатегоризованы в новую.",
        "movenologintext": "Вы должны [[Special:UserLogin|представиться системе]],\nчтобы иметь возможность переименовать страницы.",
-       "movenotallowed": "У вас нет разрешения переименовывать страницы.",
-       "movenotallowedfile": "У вас нет разрешения переименовывать файлы.",
-       "cant-move-user-page": "У вас нет разрешения переименовывать основные страницы участников.",
+       "movenotallowed": "У вас нет прав на переименовывание страниц.",
+       "movenotallowedfile": "У вас нет прав на переименовывание файлов.",
+       "cant-move-user-page": "У вас нет прав на переименовывание основных страниц участников.",
        "cant-move-to-user-page": "У вас нет прав переименовывать страницу в страницу участника (можно переименовать в подстраницу).",
-       "cant-move-category-page": "У вас нет разрешения переименовывать страницы категорий.",
-       "cant-move-to-category-page": "У вас нет разрешения переименовывать страницы в страницу категории.",
-       "cant-move-subpages": "У вас нет разрешения переименовывать подстраницы.",
+       "cant-move-category-page": "У вас нет прав на переименовывание страниц категорий.",
+       "cant-move-to-category-page": "У вас нет прав на переименовывание страницы в страницу категории.",
+       "cant-move-subpages": "У вас нет прав на переименовывание подстраниц.",
        "namespace-nosubpages": "Пространство имён «$1» не разрешает создание страниц.",
        "newtitle": "Новое название:",
        "move-watch": "Добавить в список наблюдения исходную и целевую страницы",
        "movenosubpage": "У этой страницы нет подстраниц.",
        "movereason": "Причина:",
        "revertmove": "возврат",
-       "delete_and_move_text": "ЦелеваÑ\8f Ñ\81траница с именем «[[:$1]]» уже существует. \nХотите удалить её, чтобы сделать возможным переименование?",
+       "delete_and_move_text": "Страница с именем «[[:$1]]» уже существует. \nХотите удалить её, чтобы сделать возможным переименование?",
        "delete_and_move_confirm": "Да, удалить эту страницу",
        "delete_and_move_reason": "Удалено для возможности переименования «[[$1]]»",
        "selfmove": "Невозможно переименовать страницу: исходное и новое имя страницы совпадают.",
        "immobile-target-namespace-iw": "Ссылка интервики не может быть использована для переименования.",
        "immobile-source-page": "Эту страницу нельзя переименовать.",
        "immobile-target-page": "Нельзя присвоить странице это имя.",
-       "bad-target-model": "Невозможно преобразовать $1 в $2: несовместимые модели данных.",
+       "bad-target-model": "Невозможно преобразовать $1 в $2. У страниц несовместимые модели содержимого.",
        "imagenocrossnamespace": "Невозможно дать файлу имя из другого пространства имён",
-       "nonfile-cannot-move-to-file": "Невозможно переименовывать страницы в файлы",
+       "nonfile-cannot-move-to-file": "Невозможно переименовывать не-файловые страницы в файлы",
        "imagetypemismatch": "Новое расширение файла не соответствует его типу",
        "imageinvalidfilename": "Целевое имя файла ошибочно",
        "fix-double-redirects": "Исправить перенаправления, указывающие на прежнее название",
        "filedelete-archive-read-only": "Архивная директория «$1» не доступна для записи веб-серверу.",
        "previousdiff": "← Предыдущая правка",
        "nextdiff": "Следующая правка →",
-       "mediawarning": "'''Внимание'''. Этот тип файла может содержать вредоносный программный код.\nПри его запуске ваша система может быть заражена.",
+       "mediawarning": "<strong>Внимание</strong>. Этот тип файла может содержать вредоносный программный код.\nПри его запуске ваша система может быть заражена.",
        "imagemaxsize": "Ограничение на размер изображения:<br />''(для страницы описания файла)''",
        "thumbsize": "Размер уменьшенной версии изображения:",
        "widthheight": "$1 × $2",
        "edit-error-long": "Ошибки:\n\n$1",
        "revid": "версия $1",
        "pageid": "ID страницы $1",
-       "interfaceadmin-info": "$1\n\nПрава на редактирование общесайтных CSS/JS/JSON были недавно вынесены из права <code>editinterface</code>. Если вы не понимаете, почему вы наткнулись на эту ошибку, см. [[mw:MediaWiki_1.32/interface-admin]].",
+       "interfaceadmin-info": "$1\n\nПрава на редактирование общесайтных CSS/JS/JSON-файлов были недавно вынесены из права <code>editinterface</code>. Если вы не понимаете, почему вы наткнулись на эту ошибку, см. [[mw:MediaWiki_1.32/interface-admin]].",
        "rawhtml-notallowed": "&lt;html&gt; теги могут быть использованы только в пределах обычных страниц.",
        "gotointerwiki": "Покидаем {{grammar:accusative|{{SITENAME}}}}...",
        "gotointerwiki-invalid": "Указан некорректный заголовок.",
index 32399b9..9ad3fb2 100644 (file)
        "php-uploaddisabledtext": "Отпремање датотека је онемогућено у PHP-у.\nПроверите подешавања file_uploads.",
        "uploadscripted": "Датотека садржи HTML или скриптни код који може бити погрешно протумачен од стране прегледача.",
        "upload-scripted-pi-callback": "Датотека која садржи инструкције за обраду XML стилског облика се не може отпремити.",
-       "upload-scripted-dtd": "Ð\9dе Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ð¾Ñ\82пÑ\80емим SVG Ð´Ð°Ñ\82оÑ\82еке које садрже нестандардну DTD декларацију.",
+       "upload-scripted-dtd": "Ð\9dиÑ\98е Ð¼Ð¾Ð³Ñ\83Ñ\9bе Ð¾Ñ\82пÑ\80емаÑ\9aе SVG Ð´Ð°Ñ\82оÑ\82ека које садрже нестандардну DTD декларацију.",
        "uploaded-script-svg": "Пронађен скриптни елеменат „$1“ у постављеној SVG датотеци.",
        "uploaded-hostile-svg": "Пронађен небезбедан CSS у стилском елементу постављене SVG датотеке.",
        "uploaded-event-handler-on-svg": "Није дозвољено постављање атрибута који контролишу догађаје <code>$1=\"$2\"</code> у SVG датотекама.",
index ad7a331..415a27a 100644 (file)
        "log": "Günlükler",
        "logeventslist-submit": "Göster",
        "logeventslist-more-filters": "Daha fazla süzgeç:",
+       "logeventslist-patrol-log": "Devriye günlüğü",
+       "logeventslist-tag-log": "Etiket günlüğü",
        "all-logs-page": "Tüm genel günlükler",
        "alllogstext": "{{SITENAME}} için mevcut tüm günlüklerin birleşik gösterimi.\nGünlük tipini, kullanıcı adını (büyük-küçük harf duyarlı), ya da etkilenen sayfayı (yine büyük-küçük harf duyarlı) seçerek görünümü daraltabilirsiniz.",
        "logempty": "Kayıtlarda eşleşen bilgi yok.",
        "dellogpage": "Silme günlüğü",
        "dellogpagetext": "Aşağıda en son silme işlemlerinin bir listesi bulunmaktadır.",
        "deletionlog": "silme günlüğü",
+       "logentry-create-create": "$1, $3 adlı sayfayı {{GENDER:$2|oluşturdu}}",
        "reverted": "Önceki sürüm geri getirildi",
        "deletecomment": "Neden:",
        "deleteotherreason": "Diğer/ilave neden:",
index 2330ae4..789dc16 100644 (file)
        "compare-rev1": "Беренче юрама",
        "compare-rev2": "Икенче юрама",
        "compare-submit": "Чагыштыр",
+       "permanentlink": "Даими сылтама",
        "dberr-problems": "Гафу итегез! Сайтта техник кыенлыклар чыкты.",
        "dberr-again": "Сәхифәне берничә минуттан соң яңартып карагыз.",
        "dberr-info": "(Мәгълүматлар базасы серверы белән тоташырга мөмкин түгел: $1)",
index ca421c9..8ed22c4 100644 (file)
        "move-page-legend": "منتقلئ صفحہ",
        "movepagetext": "درج ذیل فارم کے ذریعہ صفحہ کو نیا نام دیا جاسکتا ہے، اس کے ساتھ صفحہ کا تاریخچہ بھی منتقل ہو جائے گا اور نئے عنوان کے جانب قدیم عنوان کو رجوع مکرر کردیا جائے گا۔\n\nاس بات کا یقین کر لیں کہ [[Special:DoubleRedirects|دوہرے]] یا [[Special:BrokenRedirects|شکستہ رجوع مکررات]] موجود نہ ہوں۔\n\nنیز آپ اس بات کے بھی ذمہ دار ہیں کہ روابط انہیں جگہوں سے مربوط رہیں جہاں سے ابھی ہیں۔\n\nخیال رہے کہ اگر نئے عنوان سے کوئی صفحہ پہلے سے موجود ہو تو یہ صفحہ منتقل '''نہیں''' ہوگا، ہاں اگر صفحہ خالی ہو اور اس کا گذشتہ ترمیمی تاریخچہ موجود نہ ہو تو منتقل کیا جا سکتا ہے۔\nاس کا مطلب یہ ہے کہ آپ سے اگر غلطی ہوجائے تو آپ صفحہ کو اسی جگہ لوٹا سکتے ہیں، تاہم موجود صفحہ پر برتحریر (overwrite) نہیں کرسکتے۔\n\n<strong>اطلاع:</strong>\nکسی اہم اور مقبول صفحہ کی منتقلی، غیرمتوقع اور پریشان کن بھی ہی ہوسکتی ہے اس لیے منتقلی سے قبل یقین کرلیں کہ آپ اس کے منطقی نتائج سے باخبر ہیں۔",
        "movepagetext-noredirectfixer": "درج ذیل فارم کے ذریعہ صفحہ کو نیا نام دیا جاسکتا ہے، اس کے ساتھ صفحہ کا تاریخچہ بھی منتقل ہو جائے گا اور نئے عنوان کے جانب قدیم عنوان کو رجوع مکرر کردیا جائے گا۔\n\nاس بات کا یقین کر لیں کہ [[Special:DoubleRedirects|دوہرے]] یا [[Special:BrokenRedirects|شکستہ رجوع مکررات]] موجود نہ ہوں۔\n\nنیز آپ اس بات کے بھی ذمہ دار ہیں کہ روابط انہیں جگہوں سے مربوط رہیں جہاں سے ابھی ہیں۔\n\nخیال رہے کہ اگر نئے عنوان سے کوئی صفحہ پہلے سے موجود ہو تو یہ صفحہ منتقل '''نہیں''' ہوگا، ہاں اگر صفحہ خالی ہو اور اس کا گذشتہ ترمیمی تاریخچہ موجود نہ ہو تو منتقل کیا جا سکتا ہے۔\nاس کا مطلب یہ ہے کہ آپ سے اگر غلطی ہوجائے تو آپ صفحہ کو اسی جگہ لوٹا سکتے ہیں، تاہم موجود صفحہ پر برتحریر (overwrite) نہیں کرسکتے۔\n\n<strong>اطلاع:</strong>\nکسی اہم اور مقبول صفحہ کی منتقلی، غیرمتوقع اور پریشان کن بھی ہی ہوسکتی ہے اس لیے منتقلی سے قبل یقین کرلیں کہ آپ اس کے منطقی نتائج سے باخبر ہیں۔",
-       "movepagetalktext": "اگر آپ اس خانے کو نشان زد کریں تو ملحقہ تبادلہ خیال صفحہ بھی نئے عنوان کی جانب خودکار طور پر منتقل ہو جائے گا اگر اس عنوان کے تحت پہلے سے کوئی تبادلۂ خیال صفحہ موجود نہ ہو۔\n\nاس صورت میں آپ کو دستی طور پر اس صفحہ کو منتقل ضم کرنا ہوگا۔",
+       "movepagetalktext": "اگر آپ اس خانے کو نشان زد کریں تو ملحقہ تبادلہ خیال صفحہ بھی (بشرطیکہ موجود ہو) نئے عنوان کی جانب خودکار طور پر منتقل ہو جائے گا۔\n\nاگر آپ نے اس خانہ کو نشان زد نہیں کیا تو ملحقہ تبادلہ خیال صفحہ کو دستی طور پر منتقل کرکے ضم کرنا ہوگا۔",
        "moveuserpage-warning": "<strong>انتباہ:</strong> آپ صارف صفحہ کو منتقل کر رہے ہیں۔ واضح رہے کہ اس منتقلی کے بعد صارف کا محض صفحہ منتقل ہوگا، اس کا صارف نام تبدیل <em>نہیں</em> ہوگا۔",
        "movecategorypage-warning": "<strong>انتباہ:</strong> آپ زمرہ منتقل کر رہے ہیں۔ واضح رہے کہ منتقلی کے بعد اس زمرے میں موجود صفحات نئے زمرے میں منتقل <em>نہیں</em> ہونگے۔",
        "movenologintext": "صفحہ کو منتقل کرنے کے لیے آپ کو اپنے کھاتے میں [[Special:UserLogin|داخل ہونا]] ضروری ہے۔",
index 5f57a44..d20f14a 100644 (file)
        "edit-error-long": "錯誤:\n\n$1",
        "revid": "修訂 $1",
        "pageid": "頁面 ID $1",
-       "interfaceadmin-info": "$1\n\n編輯全站 CSS/JS/JSON 檔案的權限,剛剛已從 <code>editinterface</code> 權限裡拆分。若您不清楚為何會收到此錯誤,請查看 [[mw:MediaWiki_1.32/interface-admin]]。",
+       "interfaceadmin-info": "$1\n\n編輯全站 CSS/JS/JSON 檔案的權限,近期已從 <code>editinterface</code> 權限裡拆分。若您不清楚為何會收到此錯誤,請查看 [[mw:MediaWiki_1.32/interface-admin]]。",
        "rawhtml-notallowed": "&lt;html&gt; 標籤無法在一般頁面之外使用。",
        "gotointerwiki": "離開 {{SITENAME}}",
        "gotointerwiki-invalid": "指定的標題無效。",
index b8d9848..6a02eea 100644 (file)
@@ -1,17 +1,39 @@
 ### Format of this file
 #
 # The top-level keys are module names (as registered in Resources.php).
-# The values of these keys are resource descriptors.
+# Each top-level key holds a resource descriptor that must have one of
+# the following `type` values:
 #
-# In each resource descriptor object, the `src` and `integrity` keys are required.
+# - `tar`: For tarball archive (may be gzip-compressed).
+# - `file: For a plain file.
+# - `multi-file`: For multiple plain files.
 #
-# * `src`: Full URL to a remote resource.
-# * `integrity`: Cryptographic hash used to verify the remote content.
-#    Uses the "integrity metadata" format defined at <https://www.w3.org/TR/SRI/>.
-# * `dest`: An object mapping paths from the remote resource to a destination in
-#    `/resources/lib/$module/`. The value may be omitted to indicate that
-#    paths should be extracted to the destination directory itself.
+### Type tar
+#
+# The `src` and `integrity` keys are quired.
+#
+# * `src`: Full URL to thes remote resource.
+# * `integrity`: Cryptographic hash (integrity metadata format per <https://www.w3.org/TR/SRI/>).
+# * `dest`: An object mapping paths to files or directory from the remote resource to a destination
+#    in the module directory. The value of key in dest may be omitted, which will extract the key
+#    directly to the module directory.
+#
+### Type file
+#
+# The `src` and `integrity` keys are quired.
+#
+# * `src`: Full URL to thes remote resource.
+# * `integrity`: Cryptographic hash (integrity metadata format per <https://www.w3.org/TR/SRI/>).
+# * `dest`: The name of the file in the module directory. Default: Basename of URL.
+#
+### Type mult-file
+#
+# The `files` key is required.
+#
+# * `files`: An object mapping destination paths to an object containing `src` and `integrity`
+#    keys.
 oojs:
+  type: tar
   src: https://registry.npmjs.org/oojs/-/oojs-2.2.2.tgz
   integrity: sha256-ebgQW2EGrSkBCnDJBGqDpsBDjA3PMN/M8U5DyLHt9mw=
   dest:
@@ -20,6 +42,7 @@ oojs:
     package/LICENSE-MIT:
     package/README.md:
 oojs-ui:
+  type: tar
   src: https://registry.npmjs.org/oojs-ui/-/oojs-ui-0.28.0.tgz
   integrity: sha384-j8bzlCPrfS4sca+U9JO9tdcewDlLlDlOVOsLn+Vqlcg5GU59vLSd7TVm4FiuTowy
   dest:
@@ -48,3 +71,18 @@ oojs-ui:
     package/dist/History.md:
     package/dist/LICENSE-MIT:
     package/dist/README.md:
+jquery:
+  type: file
+  src: https://code.jquery.com/jquery-3.2.1.js
+  # From https://code.jquery.com/jquery/
+  integrity: sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE=
+  dest: jquery.js
+qunitjs:
+  type: multi-file
+  files:
+    qunit.js:
+      src: https://code.jquery.com/qunit/qunit-2.6.0.js
+      integrity: sha384-5O3bKbJBbAbxsqV+w/I1fcXgWJgbqM+hmYAPOE9aELSYpcTEsv48X8H+Hnq66V/9
+    qunit.css:
+      src: https://code.jquery.com/qunit/qunit-2.6.0.css
+      integrity: sha384-8vDvsmsuiD7tCQyC+pW2LOwDDgsluGsIPeCqr3rHsDSF2k4WpmfvKKxcgSV5zPai
index 528d6e7..41e579b 100644 (file)
@@ -30,6 +30,8 @@ require_once __DIR__ . '/../Maintenance.php';
 class ManageForeignResources extends Maintenance {
        private $defaultAlgo = 'sha384';
        private $tmpParentDir;
+       private $action;
+       private $failAfterOutput = false;
 
        public function __construct() {
                global $IP;
@@ -40,17 +42,16 @@ Manage foreign resources registered with ResourceLoader.
 This helps developers to download, verify and update local copies of upstream
 libraries registered as ResourceLoader modules. See also foreign-resources.yaml.
 
-For sources that don't publish an integrity hash, leave the value empty at
-first, and run this script with --make-sri to compute the hashes.
+For sources that don't publish an integrity hash, omit "integrity" (or leave empty)
+and run the "make-sri" action to compute the missing hashes.
 
 This script runs in dry mode by default. Use --update to actually change, remove,
 or add files to /resources/lib/.
 TEXT
                );
+               $this->addArg( 'action', 'One of "update", "verify" or "make-sri"', true );
                $this->addArg( 'module', 'Name of a single module (Default: all)', false );
-               $this->addOption( 'update', ' resources/lib/ missing integrity metadata' );
-               $this->addOption( 'make-sri', 'Compute missing integrity metadata' );
-               $this->addOption( 'verbose', 'Be verbose' );
+               $this->addOption( 'verbose', 'Be verbose', false, false, 'v' );
 
                // Use a directory in $IP instead of wfTempDir() because
                // PHP's rename() does not work across file systems.
@@ -59,67 +60,127 @@ TEXT
 
        public function execute() {
                global $IP;
-               $module = $this->getArg();
-               $makeSRI = $this->hasOption( 'make-sri' );
+               $this->action = $this->getArg( 0 );
+               if ( !in_array( $this->action, [ 'update', 'verify', 'make-sri' ] ) ) {
+                       $this->fatalError( "Invalid action argument." );
+               }
 
                $registry = $this->parseBasicYaml(
                        file_get_contents( __DIR__ . '/foreign-resources.yaml' )
                );
+               $module = $this->getArg( 1, 'all' );
                foreach ( $registry as $moduleName => $info ) {
-                       if ( $module !== null && $moduleName !== $module ) {
+                       if ( $module !== 'all' && $moduleName !== $module ) {
                                continue;
                        }
                        $this->verbose( "\n### {$moduleName}\n\n" );
+                       $destDir = "{$IP}/resources/lib/$moduleName";
 
-                       // Validate required keys
-                       $info += [ 'src' => null, 'integrity' => null, 'dest' => null ];
-                       if ( $info['src'] === null ) {
-                               $this->fatalError( "Module '$moduleName' must have a 'src' key." );
+                       if ( $this->action === 'update' ) {
+                               $this->output( "... updating '{$moduleName}'\n" );
+                               $this->verbose( "... emptying /resources/lib/$moduleName\n" );
+                               wfRecursiveRemoveDir( $destDir );
+                       } elseif ( $this->action === 'verify' ) {
+                               $this->output( "... verifying '{$moduleName}'\n" );
+                       } else {
+                               $this->output( "... checking '{$moduleName}'\n" );
                        }
-                       $integrity = is_string( $info['integrity'] ) ? $info['integrity'] : $makeSRI;
-                       if ( $integrity === false ) {
-                               $this->fatalError( "Module '$moduleName' must have an 'integrity' key." );
+
+                       $this->verbose( "... preparing {$this->tmpParentDir}\n" );
+                       wfRecursiveRemoveDir( $this->tmpParentDir );
+                       if ( !wfMkdirParents( $this->tmpParentDir ) ) {
+                               $this->fatalError( "Unable to create {$this->tmpParentDir}" );
                        }
 
-                       // Download the resource
-                       $data = Http::get( $info['src'], [ 'followRedirects' => false ] );
-                       if ( $data === false ) {
-                               $this->fatalError( "Failed to download resource for '$moduleName'." );
+                       if ( !isset( $info['type'] ) ) {
+                               $this->fatalError( "Module '$moduleName' must have a 'type' key." );
+                       }
+                       switch ( $info['type'] ) {
+                               case 'tar':
+                                       $this->handleTypeTar( $moduleName, $destDir, $info );
+                                       break;
+                               case 'file':
+                                       $this->handleTypeFile( $moduleName, $destDir, $info );
+                                       break;
+                               case 'multi-file':
+                                       $this->handleTypeMultiFile( $moduleName, $destDir, $info );
+                                       break;
+                               default:
+                                       $this->fatalError( "Unknown type '{$info['type']}' for '$moduleName'" );
                        }
+               }
 
-                       // Validate integrity metadata
-                       $this->output( "... checking integrity of '{$moduleName}'\n" );
-                       $algo = $integrity === true ? $this->defaultAlgo : explode( '-', $integrity )[0];
-                       $actualIntegrity = $algo . '-' . base64_encode( hash( $algo, $data, true ) );
-                       if ( $integrity === true ) {
-                               $this->output( "Integrity for '{$moduleName}':\n\t${actualIntegrity}\n" );
-                               continue;
-                       } elseif ( $integrity !== $actualIntegrity ) {
-                               $this->fatalError( "Integrity check failed for '{$moduleName}:\n" .
-                                       "Expected: {$integrity}\n" .
-                                       "Actual: {$actualIntegrity}"
+               $this->cleanUp();
+               $this->output( "\nDone!\n" );
+               if ( $this->failAfterOutput ) {
+                       // The verify mode should check all modules/files and fail after, not during.
+                       return false;
+               }
+       }
+
+       private function fetch( $src, $integrity ) {
+               $data = Http::get( $src, [ 'followRedirects' => false ] );
+               if ( $data === false ) {
+                       $this->fatalError( "Failed to download resource at {$src}" );
+               }
+               $algo = $integrity === null ? $this->defaultAlgo : explode( '-', $integrity )[0];
+               $actualIntegrity = $algo . '-' . base64_encode( hash( $algo, $data, true ) );
+               if ( $integrity === $actualIntegrity ) {
+                       $this->verbose( "... passed integrity check for {$src}\n" );
+               } else {
+                       if ( $this->action === 'make-sri' ) {
+                               $this->output( "Integrity for {$src}\n\tintegrity: ${actualIntegrity}\n" );
+                       } else {
+                               $this->fatalError( "Integrity check failed for {$src}\n" .
+                                       "\tExpected: {$integrity}\n" .
+                                       "\tActual: {$actualIntegrity}"
                                );
                        }
-
-                       // Determine destination
-                       $destDir = "{$IP}/resources/lib/$moduleName";
-                       $this->output( "... extracting files for '{$moduleName}'\n" );
-                       $this->handleTypeTar( $moduleName, $data, $destDir, $info );
                }
+               return $data;
+       }
 
-               // Clean up
-               wfRecursiveRemoveDir( $this->tmpParentDir );
-               $this->output( "\nDone!\n" );
+       private function handleTypeFile( $moduleName, $destDir, array $info ) {
+               if ( !isset( $info['src'] ) ) {
+                       $this->fatalError( "Module '$moduleName' must have a 'src' key." );
+               }
+               $data = $this->fetch( $info['src'], $info['integrity'] ?? null );
+               $dest = $info['dest'] ?? basename( $info['src'] );
+               $path = "$destDir/$dest";
+               if ( $this->action === 'verify' && sha1_file( $path ) !== sha1( $data ) ) {
+                       $this->fatalError( "File for '$moduleName' is different." );
+               } elseif ( $this->action === 'update' ) {
+                       wfMkdirParents( $destDir );
+                       file_put_contents( "$destDir/$dest", $data );
+               }
        }
 
-       private function handleTypeTar( $moduleName, $data, $destDir, array $info ) {
-               global $IP;
-               wfRecursiveRemoveDir( $this->tmpParentDir );
-               if ( !wfMkdirParents( $this->tmpParentDir ) ) {
-                       $this->fatalError( "Unable to create {$this->tmpParentDir}" );
+       private function handleTypeMultiFile( $moduleName, $destDir, array $info ) {
+               if ( !isset( $info['files'] ) ) {
+                       $this->fatalError( "Module '$moduleName' must have a 'files' key." );
                }
+               foreach ( $info['files'] as $dest => $file ) {
+                       if ( !isset( $file['src'] ) ) {
+                               $this->fatalError( "Module '$moduleName' file '$dest' must have a 'src' key." );
+                       }
+                       $data = $this->fetch( $file['src'], $file['integrity'] ?? null );
+                       $path = "$destDir/$dest";
+                       if ( $this->action === 'verify' && sha1_file( $path ) !== sha1( $data ) ) {
+                               $this->fatalError( "File '$dest' for '$moduleName' is different." );
+                       } elseif ( $this->action === 'update' ) {
+                               wfMkdirParents( $destDir );
+                               file_put_contents( "$destDir/$dest", $data );
+                       }
+               }
+       }
 
-               // Write resource to temporary file and open it
+       private function handleTypeTar( $moduleName, $destDir, array $info ) {
+               $info += [ 'src' => null, 'integrity' => null, 'dest' => null ];
+               if ( $info['src'] === null ) {
+                       $this->fatalError( "Module '$moduleName' must have a 'src' key." );
+               }
+               // Download the resource to a temporary file and open it
+               $data = $this->fetch( $info['src'], $info['integrity' ] );
                $tmpFile = "{$this->tmpParentDir}/$moduleName.tar";
                $this->verbose( "... writing '$moduleName' src to $tmpFile\n" );
                file_put_contents( $tmpFile, $data );
@@ -129,46 +190,45 @@ TEXT
                unset( $data, $p );
 
                if ( $info['dest'] === null ) {
-                       // Replace the entire directory as-is
-                       if ( !$this->hasOption( 'update' ) ) {
-                               $this->output( "[dry run] Would replace /resources/lib/$moduleName\n" );
-                       } else {
-                               wfRecursiveRemoveDir( $destDir );
-                               if ( !rename( $tmpDir, $destDir ) ) {
-                                       $this->fatalError( "Could not move $destDir to $tmpDir." );
-                               }
-                       }
-                       return;
-               }
-
-               // Create and/or empty the destination
-               if ( !$this->hasOption( 'update' ) ) {
-                       $this->output( "... [dry run] would empty /resources/lib/$moduleName\n" );
+                       // Default: Replace the entire directory
+                       $toCopy = [ $tmpDir => $destDir ];
                } else {
-                       wfRecursiveRemoveDir( $destDir );
-                       wfMkdirParents( $destDir );
-               }
-
-               // Expand and normalise the 'dest' entries
-               $toCopy = [];
-               foreach ( $info['dest'] as $fromSubPath => $toSubPath ) {
-                       // Use glob() to expand wildcards and check existence
-                       $fromPaths = glob( "{$tmpDir}/{$fromSubPath}", GLOB_BRACE );
-                       if ( !$fromPaths ) {
-                               $this->fatalError( "Path '$fromSubPath' of '$moduleName' not found." );
-                       }
-                       foreach ( $fromPaths as $fromPath ) {
-                               $toCopy[$fromPath] = $toSubPath === null
-                                       ? "$destDir/" . basename( $fromPath )
-                                       : "$destDir/$toSubPath/" . basename( $fromPath );
+                       // Expand and normalise the 'dest' entries
+                       $toCopy = [];
+                       foreach ( $info['dest'] as $fromSubPath => $toSubPath ) {
+                               // Use glob() to expand wildcards and check existence
+                               $fromPaths = glob( "{$tmpDir}/{$fromSubPath}", GLOB_BRACE );
+                               if ( !$fromPaths ) {
+                                       $this->fatalError( "Path '$fromSubPath' of '$moduleName' not found." );
+                               }
+                               foreach ( $fromPaths as $fromPath ) {
+                                       $toCopy[$fromPath] = $toSubPath === null
+                                               ? "$destDir/" . basename( $fromPath )
+                                               : "$destDir/$toSubPath/" . basename( $fromPath );
+                               }
                        }
                }
                foreach ( $toCopy as $from => $to ) {
-                       if ( !$this->hasOption( 'update' ) ) {
-                               $shortFrom = strtr( $from, [ "$tmpDir/" => '' ] );
-                               $shortTo = strtr( $to, [ "$IP/" => '' ] );
-                               $this->output( "... [dry run] would move $shortFrom to $shortTo\n" );
-                       } else {
+                       if ( $this->action === 'verify' ) {
+                               $this->verbose( "... verifying $to\n" );
+                               if ( is_dir( $from ) ) {
+                                       $rii = new RecursiveIteratorIterator( new RecursiveDirectoryIterator(
+                                               $from,
+                                               RecursiveDirectoryIterator::SKIP_DOTS
+                                       ) );
+                                       foreach ( $rii as $file ) {
+                                               $remote = $file->getPathname();
+                                               $local = strtr( $remote, [ $from => $to ] );
+                                               if ( sha1_file( $remote ) !== sha1_file( $local ) ) {
+                                                       $this->error( "File '$local' is different." );
+                                                       $this->failAfterOutput = true;
+                                               }
+                                       }
+                               } elseif ( sha1_file( $from ) !== sha1_file( $to ) ) {
+                                       $this->error( "File '$to' is different." );
+                                       $this->failAfterOutput = true;
+                               }
+                       } elseif ( $this->action === 'update' ) {
                                $this->verbose( "... moving $from to $to\n" );
                                wfMkdirParents( dirname( $to ) );
                                if ( !rename( $from, $to ) ) {
@@ -184,6 +244,15 @@ TEXT
                }
        }
 
+       private function cleanUp() {
+               wfRecursiveRemoveDir( $this->tmpParentDir );
+       }
+
+       protected function fatalError( $msg, $exitCode = 1 ) {
+               $this->cleanUp();
+               parent::fatalError( $msg, $exitCode );
+       }
+
        /**
         * Basic YAML parser.
         *
index 9536b67..284b21a 100644 (file)
@@ -22,7 +22,6 @@
                mwLoaderTrack = mw.track,
                trackCallbacks = $.Callbacks( 'memory' ),
                trackHandlers = [],
-               hasOwn = Object.prototype.hasOwnProperty,
                queue;
 
        /**
         * @class mw.hook
         */
        mw.hook = ( function () {
-               var lists = {};
+               var lists = Object.create( null );
 
                /**
                 * Create an instance of mw.hook.
                 * @return {mw.hook}
                 */
                return function ( name ) {
-                       var list = hasOwn.call( lists, name ) ?
-                               lists[ name ] :
-                               lists[ name ] = $.Callbacks( 'memory' );
+                       var list = lists[ name ] || ( lists[ name ] = $.Callbacks( 'memory' ) );
 
                        return {
                                /**
index aa86a4b..a163a3d 100644 (file)
@@ -2,7 +2,7 @@
        'use strict';
 
        var notification,
-               // The #mw-notification-area div that all notifications are contained inside.
+               // The .mw-notification-area div that all notifications are contained inside.
                $area,
                // Number of open notification boxes at any time
                openNotificationCount = 0,
 
                // Write to the DOM:
                // Prepend the notification area to the content area and save its object.
+               // The ID attribute here is deprecated.
                $area = $( '<div id="mw-notification-area" class="mw-notification-area mw-notification-area-layout"></div>' )
                        // Pause auto-hide timers when the mouse is in the notification area.
                        .on( {
index a425b85..3fb7ffc 100644 (file)
                         * @class
                         */
                        function StringSet() {
-                               this.set = {};
+                               this.set = Object.create( null );
                        }
                        StringSet.prototype.add = function ( value ) {
                                this.set[ value ] = true;
                        };
                        StringSet.prototype.has = function ( value ) {
-                               return hasOwn.call( this.set, value );
+                               return value in this.set;
                        };
                        return StringSet;
                }() );
         *  copied in one direction only. Changes to globals do not reflect in the map.
         */
        function Map( global ) {
-               this.values = {};
+               this.values = Object.create( null );
                if ( global === true ) {
                        // Override #set to also set the global variable
                        this.set = function ( selection, value ) {
                                results = {};
                                for ( i = 0; i < selection.length; i++ ) {
                                        if ( typeof selection[ i ] === 'string' ) {
-                                               results[ selection[ i ] ] = hasOwn.call( this.values, selection[ i ] ) ?
+                                               results[ selection[ i ] ] = selection[ i ] in this.values ?
                                                        this.values[ selection[ i ] ] :
                                                        fallback;
                                        }
                        }
 
                        if ( typeof selection === 'string' ) {
-                               return hasOwn.call( this.values, selection ) ?
+                               return selection in this.values ?
                                        this.values[ selection ] :
                                        fallback;
                        }
                        var i;
                        if ( Array.isArray( selection ) ) {
                                for ( i = 0; i < selection.length; i++ ) {
-                                       if ( typeof selection[ i ] !== 'string' || !hasOwn.call( this.values, selection[ i ] ) ) {
+                                       if ( typeof selection[ i ] !== 'string' || !( selection[ i ] in this.values ) ) {
                                                return false;
                                        }
                                }
                                return true;
                        }
-                       return typeof selection === 'string' && hasOwn.call( this.values, selection );
+                       return typeof selection === 'string' && selection in this.values;
                }
        };
 
index 7e7fd6a..ee72166 100644 (file)
@@ -145,5 +145,5 @@ window.isCompatible = function ( str ) {
        // This embeds mediawiki.js, which defines 'mw' and 'mw.loader'.
        $CODE.defineLoader();
 
-       mw.requestIdleCallback( startUp );
+       startUp();
 }() );
index f76b1e3..585ebb9 100644 (file)
@@ -346,8 +346,6 @@ return [
                "PhanUndeclaredMethod",
                // approximate error count: 1224
                "PhanUndeclaredProperty",
-               // approximate error count: 3
-               "PhanUndeclaredStaticMethod",
                // approximate error count: 58
                "PhanUndeclaredVariableDim",
        ],
index 34f93ad..5cc45f5 100644 (file)
@@ -110,6 +110,11 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
         */
        private $loggers = [];
 
+       /**
+        * @var LoggerInterface
+        */
+       private $testLogger;
+
        /**
         * Table name prefixes. Oracle likes it shorter.
         */
@@ -132,6 +137,11 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
 
                $this->backupGlobals = false;
                $this->backupStaticAttributes = false;
+               $this->testLogger = self::getTestLogger();
+       }
+
+       private static function getTestLogger() {
+               return LoggerFactory::getInstance( 'tests-phpunit' );
        }
 
        public function __destruct() {
@@ -447,6 +457,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
 
                if ( !self::$dbSetup || $this->needsDB() ) {
                        // set up a DB connection for this test to use
+                       $this->testLogger->info( "Setting up DB for " . $this->toString() );
 
                        self::$useTemporaryTables = !$this->getCliArg( 'use-normal-tables' );
                        self::$reuseDB = $this->getCliArg( 'reuse-db' );
@@ -473,9 +484,12 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        $needsResetDB = true;
                }
 
+               $this->testLogger->info( "Starting test " . $this->toString() );
                parent::run( $result );
+               $this->testLogger->info( "Finished test " . $this->toString() );
 
                if ( $needsResetDB ) {
+                       $this->testLogger->info( "Resetting DB" );
                        $this->resetDB( $this->db, $this->tablesUsed );
                }
        }
@@ -566,7 +580,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        }
                        // Check for unsafe queries
                        if ( $this->db->getType() === 'mysql' ) {
-                               $this->db->query( "SET sql_mode = 'STRICT_ALL_TABLES'" );
+                               $this->db->query( "SET sql_mode = 'STRICT_ALL_TABLES'", __METHOD__ );
                        }
                }
 
@@ -618,7 +632,8 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                                $this->db->rollback( __METHOD__, 'flush' );
                        }
                        if ( $this->db->getType() === 'mysql' ) {
-                               $this->db->query( "SET sql_mode = " . $this->db->addQuotes( $wgSQLMode ) );
+                               $this->db->query( "SET sql_mode = " . $this->db->addQuotes( $wgSQLMode ),
+                                       __METHOD__ );
                        }
                }
 
@@ -1205,6 +1220,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
         * @since 1.32
         */
        protected function addCoreDBData() {
+               $this->testLogger->info( __METHOD__ );
                if ( $this->db->getType() == 'oracle' ) {
                        # Insert 0 user to prevent FK violations
                        # Anonymous user
@@ -1449,7 +1465,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                // Assuming this isn't needed for External Store database, and not sure if the procedure
                // would be available there.
                if ( $db->getType() == 'oracle' ) {
-                       $db->query( 'BEGIN FILL_WIKI_INFO; END;' );
+                       $db->query( 'BEGIN FILL_WIKI_INFO; END;', __METHOD__ );
                }
 
                Hooks::run( 'UnitTestsAfterDatabaseSetup', [ $db, $prefix ] );
index 8137b27..6679754 100644 (file)
@@ -77,15 +77,12 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
 
                $this->tablesUsed += $this->getMcrTablesToReset();
 
-               $this->setMwGlobals(
-                       'wgMultiContentRevisionSchemaMigrationStage',
-                       $this->getMcrMigrationStage()
-               );
-
-               $this->setMwGlobals(
-                       'wgContentHandlerUseDB',
-                       $this->getContentHandlerUseDB()
-               );
+               $this->setMwGlobals( [
+                       'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
+                       'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
+                       'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
+                       'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
+               ] );
 
                $this->overrideMwServices();
        }