Merge "Fix broken label in Special:Import due to duplicate ID"
authorMusikAnimal <musikanimal@gmail.com>
Wed, 27 Jun 2018 20:05:45 +0000 (20:05 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 27 Jun 2018 20:05:45 +0000 (20:05 +0000)
76 files changed:
autoload.php
includes/DefaultSettings.php
includes/api/ApiOptions.php
includes/api/i18n/cs.json
includes/api/i18n/fr.json
includes/api/i18n/ko.json
includes/api/i18n/ru.json
includes/changes/ChangesList.php
includes/changes/EnhancedChangesList.php
includes/changes/OldChangesList.php
includes/htmlform/fields/HTMLSelectNamespace.php
includes/installer/i18n/bn.json
includes/installer/i18n/he.json
includes/libs/objectcache/ReplicatedBagOStuff.php
includes/media/FormatMetadata.php
includes/parser/Parser.php
includes/parser/Sanitizer.php
includes/resourceloader/ResourceLoaderFileModule.php
includes/resourceloader/ResourceLoaderImageModule.php
includes/resourceloader/ResourceLoaderStartUpModule.php
includes/templates/EnhancedChangesListGroup.mustache
languages/i18n/be-tarask.json
languages/i18n/bn.json
languages/i18n/bs.json
languages/i18n/de.json
languages/i18n/es.json
languages/i18n/eu.json
languages/i18n/fi.json
languages/i18n/fr.json
languages/i18n/gcr.json
languages/i18n/got.json
languages/i18n/he.json
languages/i18n/inh.json
languages/i18n/lez.json
languages/i18n/lv.json
languages/i18n/mni.json
languages/i18n/my.json
languages/i18n/nap.json
languages/i18n/nl.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/ru.json
languages/i18n/sah.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/yi.json
languages/i18n/zgh.json
languages/i18n/zh-hant.json
maintenance/populateChangeTagDef.php
maintenance/populateContentTables.php [new file with mode: 0644]
resources/Resources.php
resources/src/mediawiki.base/mediawiki.base.js
resources/src/mediawiki.inspect.js
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.mixins.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ChangesListWrapperWidget.less
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterItemHighlightButton.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterMenuOptionWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterTagMultiselectWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.HighlightColorPickerWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.HighlightPopupWidget.js [new file with mode: 0644]
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ItemMenuOptionWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MenuSelectWidget.js
resources/src/mediawiki.ui/components/checkbox.less
resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js [deleted file]
resources/src/mediawiki.widgets/mw.widgets.CategoryMultiselectWidget.js
resources/src/mediawiki.widgets/mw.widgets.CategoryTagItemWidget.js [new file with mode: 0644]
tests/parser/DbTestRecorder.php
tests/parser/parserTests.txt
tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php
tests/phpunit/tests/MediaWikiTestCaseSchema1Test.php
tests/phpunit/tests/MediaWikiTestCaseSchema2Test.php
tests/selenium/wdio-mediawiki/CHANGELOG.md
tests/selenium/wdio-mediawiki/package.json

index 6b1f981..887d32a 100644 (file)
@@ -1105,6 +1105,7 @@ $wgAutoloadLocalClasses = [
        'PopulateCategory' => __DIR__ . '/maintenance/populateCategory.php',
        'PopulateChangeTagDef' => __DIR__ . '/maintenance/populateChangeTagDef.php',
        'PopulateContentModel' => __DIR__ . '/maintenance/populateContentModel.php',
+       'PopulateContentTables' => __DIR__ . '/maintenance/populateContentTables.php',
        'PopulateExternallinksIndex60' => __DIR__ . '/maintenance/populateExternallinksIndex60.php',
        'PopulateFilearchiveSha1' => __DIR__ . '/maintenance/populateFilearchiveSha1.php',
        'PopulateImageSha1' => __DIR__ . '/maintenance/populateImageSha1.php',
index 8b25672..3771df1 100644 (file)
@@ -1892,6 +1892,8 @@ $wgDBmwschema = null;
 
 /**
  * Default group to use when getting database connections.
+ * Will be used as default query group in ILoadBalancer::getConnection.
+ * @since 1.32
  */
 $wgDBDefaultGroup = null;
 
index f30b44c..fe7d10d 100644 (file)
@@ -29,11 +29,15 @@ use MediaWiki\MediaWikiServices;
  * @ingroup API
  */
 class ApiOptions extends ApiBase {
+       /** @var User User account to modify */
+       private $userForUpdates;
+
        /**
         * Changes preferences of the current user.
         */
        public function execute() {
-               if ( $this->getUser()->isAnon() ) {
+               $user = $this->getUserForUpdates();
+               if ( !$user || $user->isAnon() ) {
                        $this->dieWithError(
                                [ 'apierror-mustbeloggedin', $this->msg( 'action-editmyoptions' ) ], 'notloggedin'
                        );
@@ -48,16 +52,8 @@ class ApiOptions extends ApiBase {
                        $this->dieWithError( [ 'apierror-missingparam', 'optionname' ] );
                }
 
-               // Load the user from the master to reduce CAS errors on double post (T95839)
-               $user = $this->getUser()->getInstanceForUpdate();
-               if ( !$user ) {
-                       $this->dieWithError(
-                               [ 'apierror-mustbeloggedin', $this->msg( 'action-editmyoptions' ) ], 'notloggedin'
-                       );
-               }
-
                if ( $params['reset'] ) {
-                       $user->resetOptions( $params['resetkinds'], $this->getContext() );
+                       $this->resetPreferences( $params['resetkinds'] );
                        $changed = true;
                }
 
@@ -76,8 +72,7 @@ class ApiOptions extends ApiBase {
                        $this->dieWithError( 'apierror-nochanges' );
                }
 
-               $preferencesFactory = MediaWikiServices::getInstance()->getPreferencesFactory();
-               $prefs = $preferencesFactory->getFormDescriptor( $user, $this->getContext() );
+               $prefs = $this->getPreferences();
                $prefsKinds = $user->getOptionKinds( $this->getContext(), $changes );
 
                $htmlForm = null;
@@ -117,7 +112,7 @@ class ApiOptions extends ApiBase {
                                        break;
                        }
                        if ( $validation === true ) {
-                               $user->setOption( $key, $value );
+                               $this->setPreference( $key, $value );
                                $changed = true;
                        } else {
                                $this->addWarning( [ 'apiwarn-validationfailed', wfEscapeWikiText( $key ), $validation ] );
@@ -125,13 +120,59 @@ class ApiOptions extends ApiBase {
                }
 
                if ( $changed ) {
-                       // Commit changes
-                       $user->saveSettings();
+                       $this->commitChanges();
                }
 
                $this->getResult()->addValue( null, $this->getModuleName(), 'success' );
        }
 
+       /**
+        * Load the user from the master to reduce CAS errors on double post (T95839)
+        *
+        * @return null|User
+        */
+       protected function getUserForUpdates() {
+               if ( !$this->userForUpdates ) {
+                       $this->userForUpdates = $this->getUser()->getInstanceForUpdate();
+               }
+
+               return $this->userForUpdates;
+       }
+
+       /**
+        * Returns preferences form descriptor
+        * @return mixed[][]
+        */
+       protected function getPreferences() {
+               $preferencesFactory = MediaWikiServices::getInstance()->getPreferencesFactory();
+               return $preferencesFactory->getFormDescriptor( $this->getUserForUpdates(),
+                       $this->getContext() );
+       }
+
+       /**
+        * @param string[] $kinds One or more types returned by User::listOptionKinds() or 'all'
+        */
+       protected function resetPreferences( array $kinds ) {
+               $this->getUserForUpdates()->resetOptions( $kinds, $this->getContext() );
+       }
+
+       /**
+        * Sets one user preference to be applied by commitChanges()
+        *
+        * @param string $preference
+        * @param mixed $value
+        */
+       protected function setPreference( $preference, $value ) {
+               $this->getUserForUpdates()->setOption( $preference, $value );
+       }
+
+       /**
+        * Applies changes to user preferences
+        */
+       protected function commitChanges() {
+               $this->getUserForUpdates()->saveSettings();
+       }
+
        public function mustBePosted() {
                return true;
        }
index c69f267..09e4106 100644 (file)
@@ -15,7 +15,7 @@
                        "Ilimanaq29"
                ]
        },
-       "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Dokumentace]]\n* [[mw:Special:MyLanguage/API:FAQ|Otázky a odpovědi]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api E-mailová konference]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Oznámení k API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Chyby a požadavky]\n</div>\n<strong>Stav:</strong> Všechny funkce uvedené na této stránce by měly fungovat, ale API se stále aktivně vyvíjí a může se kdykoli změnit. Upozornění na změny získáte přihlášením se k [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ e-mailové konferenci mediawiki-api-announce].\n\n<strong>Chybné požadavky:</strong> Pokud jsou do API zaslány chybné požadavky, bude vrácena HTTP hlavička s klíčem „MediaWiki-API-Error“ a hodnota této hlavičky a chybový kód budou nastaveny na stejnou hodnotu. Více informací najdete [[mw:Special:MyLanguage/API:Errors_and_warnings|v dokumentaci]].\n\n<strong>Testování:</strong> Pro jednoduché testování požadavků na API zkuste [[Special:ApiSandbox]].",
+       "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Dokumentace]]\n* [[mw:Special:MyLanguage/API:FAQ|Otázky a odpovědi]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api E-mailová konference]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Oznámení k API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Chyby a požadavky]\n</div>\n<strong>Stav:</strong> Všechny funkce uvedené na této stránce by měly fungovat, ale API se stále aktivně vyvíjí a může se kdykoli změnit. Upozornění na změny získáte přihlášením se k [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ e-mailové konferenci mediawiki-api-announce].\n\n<strong>Chybné požadavky:</strong> Pokud jsou do API zaslány chybné požadavky, bude vrácena HTTP hlavička s klíčem „MediaWiki-API-Error“ a hodnota této hlavičky a chybový kód budou nastaveny na stejnou hodnotu. Více informací najdete [[mw:Special:MyLanguage/API:Errors_and_warnings|v dokumentaci]].\n\n<p class=\"mw-apisandbox-link\"><strong>Testování:</strong> Pro jednoduché testování požadavků na API zkuste [[Special:ApiSandbox]].</p>",
        "apihelp-main-param-action": "Která akce se má provést.",
        "apihelp-main-param-format": "Formát výstupu.",
        "apihelp-main-param-maxlag": "Maximální zpoždění lze použít, když je MediaWiki nainstalováno na cluster s replikovanou databází. Abyste se vyhnuli zhoršování už tak špatného replikačního zpoždění, můžete tímto parametrem nechat klienta čekat, dokud replikační zpoždění neklesne pod uvedenou hodnotu. V případě příliš vysokého zpoždění se vrátí chybový kód „<samp>maxlag</samp>“ s hlášením typu „<samp>Waiting for $host: $lag seconds lagged</samp>“.<br />Více informací najdete v [[mw:Special:MyLanguage/Manual:Maxlag_parameter|příručce]].",
index a80ff50..0759e35 100644 (file)
        "apihelp-query+filerepoinfo-param-prop": "Quelles propriétés récupérer du référentiel (les propriétés disponibles peuvent varier sur les autres wikis).",
        "apihelp-query+filerepoinfo-paramvalue-prop-apiurl": "URL vers l’API du dépôt — utile pour obtenir des informations sur l’image depuis l’hôte.",
        "apihelp-query+filerepoinfo-paramvalue-prop-articlepath": "<var>[[mw:Special:MyLanguage/Manual:$wgArticlePath|$wgArticlePath]]</var> du wiki du dépôt, ou équivalent.",
-       "apihelp-query+filerepoinfo-paramvalue-prop-canUpload": "Si les fichiers peuvent être téléchargés sur ce dépôt, par ex. via CORS et l’authentification partagée.",
+       "apihelp-query+filerepoinfo-paramvalue-prop-canUpload": "Si les fichiers peuvent être téléversés sur ce dépôt, par exemple via CORS et l’authentification partagée.",
        "apihelp-query+filerepoinfo-paramvalue-prop-displayname": "Le nom lisible du wiki du dépôt.",
        "apihelp-query+filerepoinfo-paramvalue-prop-favicon": "URL de l'icône favorite du dépôt du wiki, depuis <var>[[mw:Special:MyLanguage/Manual:$wgFavicon|$wgFavicon]]</var>.",
        "apihelp-query+filerepoinfo-paramvalue-prop-fetchDescription": "Si les pages de description de fichier sont récupérées de ce dépôt lors de l’affichage des pages de description de fichier locales.",
index 626cb18..e2b6bb4 100644 (file)
        "apihelp-query+filearchive-paramvalue-prop-metadata": "그림의 버전에 대한 Exif 메타데이터를 나열합니다.",
        "apihelp-query+filearchive-example-simple": "삭제된 모든 파일의 목록을 표시합니다.",
        "apihelp-query+filerepoinfo-summary": "위키에 구성된 그림 저장소에 대한 메타 정보를 반환합니다.",
+       "apihelp-query+filerepoinfo-paramvalue-prop-apiurl": "저장소 API의 URL - 호스트로부터 이미지 정보를 가져오는데 유용합니다.",
+       "apihelp-query+filerepoinfo-paramvalue-prop-canUpload": "파일을 이 저장소에 올릴 수 있는지의 여부. (예: CORS를 통해, 공유 인증을 통해)",
        "apihelp-query+filerepoinfo-paramvalue-prop-displayname": "사람이 식별할 수 있는 저장소 위키의 이름입니다.",
        "apihelp-query+filerepoinfo-paramvalue-prop-local": "해당 저장소가 로컬인지 아닌지의 여부입니다.",
+       "apihelp-query+filerepoinfo-paramvalue-prop-rootUrl": "이미지 경로의 루트 URL 경로입니다.",
+       "apihelp-query+filerepoinfo-paramvalue-prop-thumbUrl": "섬네일 경로의 루트 URL 경로입니다.",
        "apihelp-query+filerepoinfo-example-simple": "파일 저장소의 정보를 가져옵니다.",
        "apihelp-query+fileusage-summary": "제시된 파일을 사용하는 모든 문서를 찾습니다.",
        "apihelp-query+fileusage-param-prop": "얻고자 하는 속성:",
index e04f090..414a252 100644 (file)
@@ -32,7 +32,8 @@
                        "Happy13241",
                        "Ole Yves",
                        "AttemptToCallNil",
-                       "Movses"
+                       "Movses",
+                       "Stjn"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Документация]]\n* [[mw:Special:MyLanguage/API:FAQ|ЧаВО]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Почтовая рассылка]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Новости API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Ошибки и запросы]\n</div>\n<strong>Статус:</strong> MediaWiki API — зрелый и стабильный интерфейс, активно поддерживаемый и улучшаемый. Мы стараемся избегать ломающих изменений, однако изредка они могут быть необходимы. Подпишитесь на [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ почтовую рассылку mediawiki-api-announce], чтобы быть в курсе обновлений.\n\n<strong>Ошибочные запросы:</strong> Если API получает запрос с ошибкой, вернётся заголовок HTTP с ключом «MediaWiki-API-Error», после чего значение заголовка и код ошибки будут отправлены обратно и установлены в то же значение. Более подробную информацию см. [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Ошибки и предупреждения]].\n\n<p class=\"mw-apisandbox-link\"><strong>Тестирование:</strong> для удобства тестирования API-запросов, см. [[Special:ApiSandbox]].</p>",
index 703acd6..0bf3eb4 100644 (file)
@@ -115,6 +115,31 @@ class ChangesList extends ContextSource {
                throw new RuntimeException( 'recentChangesLine should be implemented' );
        }
 
+       /**
+        * Get the container for highlights that are used in the new StructuredFilters
+        * system
+        *
+        * @return string HTML structure of the highlight container div
+        */
+       protected function getHighlightsContainerDiv() {
+               $highlightColorDivs = '';
+               foreach ( [ 'none', 'c1', 'c2', 'c3', 'c4', 'c5' ] as $color ) {
+                       $highlightColorDivs .= Html::rawElement(
+                               'div',
+                               [
+                                       'class' => 'mw-rcfilters-ui-highlights-color-' . $color,
+                                       'data-color' => $color
+                               ]
+                       );
+               }
+
+               return Html::rawElement(
+                       'div',
+                       [ 'class' => 'mw-rcfilters-ui-highlights' ],
+                       $highlightColorDivs
+               );
+       }
+
        /**
         * Sets the list to use a "<li class='watchlist-(namespace)-(page)'>" tag
         * @param bool $value
index 81eccbc..0c56fdd 100644 (file)
@@ -705,9 +705,14 @@ class EnhancedChangesList extends ChangesList {
                }
 
                $line = Html::openElement( 'table', $attribs ) . Html::openElement( 'tr' );
+               // Highlight block
+               $line .= Html::rawElement( 'td', [],
+                       $this->getHighlightsContainerDiv()
+               );
+
                $line .= Html::rawElement( 'td', [], '<span class="mw-enhancedchanges-arrow-space"></span>' );
                $line .= Html::rawElement( 'td', [ 'class' => 'mw-changeslist-line-prefix' ], $prefix );
-               $line .= '<td class="mw-enhanced-rc">';
+               $line .= '<td class="mw-enhanced-rc" colspan="2">';
 
                if ( isset( $data['recentChangesFlags'] ) ) {
                        $line .= $this->recentChangesFlags( $data['recentChangesFlags'] );
index 88c3c22..51ee481 100644 (file)
@@ -63,6 +63,7 @@ class OldChangesList extends ChangesList {
                $dateheader = ''; // $html now contains only <li>...</li>, for hooks' convenience.
                $this->insertDateHeader( $dateheader, $rc->mAttribs['rc_timestamp'] );
 
+               $html = $this->getHighlightsContainerDiv() . $html;
                $attribs['class'] = implode( ' ', $classes );
 
                return $dateheader . Html::rawElement( 'li', $attribs,  $html ) . "\n";
index f13aa17..7f74b3b 100644 (file)
@@ -3,6 +3,10 @@
  * Wrapper for Html::namespaceSelector to use in HTMLForm
  */
 class HTMLSelectNamespace extends HTMLFormField {
+
+       /** @var string|null */
+       protected $mAllValue;
+
        public function __construct( $params ) {
                parent::__construct( $params );
 
index ad74add..a2448c4 100644 (file)
@@ -8,7 +8,8 @@
                        "Aftabuzzaman",
                        "Hasive",
                        "আজিজ",
-                       "Elias Ahmmad"
+                       "Elias Ahmmad",
+                       "আফতাবুজ্জামান"
                ]
        },
        "config-desc": "মিডিয়াউইকির জন্য ইন্সটলার",
index bc860d9..990b3bc 100644 (file)
        "config-support-info": "מדיה־ויקי תומכת במערכות מסדי הנתונים הבאות:\n\n$1\n\nאם אינך רואה את מסד הנתונים שלך ברשימה, יש לעקוב אחר ההוראות המקושרות לעיל כדי להפעיל את התמיכה.",
        "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] הוא היעד העיקרי עבור מדיה־ויקי ולו התמיכה הטובה ביותר. מדיה־ויקי עובדת גם עם [{{int:version-db-mariadb-url}} MariaDB] ועם [{{int:version-db-percona-url}} Percona Server], שתואמים ל־MySQL. (ר׳ [https://secure.php.net/manual/en/mysql.installation.php how to compile PHP with MySQL support])",
        "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] הוא מסד נתונים נפוץ בקוד פתוח והוא נפוץ בתור חלופה ל־MySQL. (ר׳ [https://secure.php.net/manual/en/pgsql.installation.php how to compile PHP with PostgreSQL support]).",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] הוא מסד נתונים קליל עם תמיכה טובה מאוד. (ר׳ [http://www.php.net/manual/en/pdo.installation.php How to compile PHP with SQLite support], משתמש ב־PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] הוא מסד נתונים עסקי מסחרי. (ר׳ [http://www.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] הוא מסד נתונים קליל עם תמיכה טובה מאוד. (ר׳ [https://secure.php.net/manual/en/pdo.installation.php How to compile PHP with SQLite support], משתמש ב־PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] הוא מסד נתונים עסקי מסחרי. (ר׳ [https://secure.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])",
        "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] הוא מסד נתונים עסקי מסחרי לחלונות. ([https://secure.php.net/manual/en/sqlsrv.installation.php How to compile PHP with SQLSRV support])",
        "config-header-mysql": "הגדרות MySQL",
        "config-header-postgres": "הגדרות PostgreSQL",
        "config-license-help": "אתרי ויקי ציבוריים רבים מפרסמים את כל התרומות [https://freedomdefined.org/Definition ברישיון חופשי].\nזה עוזר ליצור תחושה של בעלות קהילתית ומעודד תרומה לאורך זמן.\nזה בדרך כלל לא נחוץ לאתר ויקי פרטי או אתר של חברה מסחרית.\n\nאם האפשרות להשתמש בטקסט מוויקיפדיה והאפשרות שוויקיפדיה תוכל תקבל עותקים של טקסטים מהוויקי שלך חשובות לך, כדאי לבחור ב<strong>{{int:config-license-cc-by-sa}}</strong>.\n\nויקיפדיה השתמשה בעבר ברישיון החופשי למסמכים של גנו (GNU FDL או GFDL).\nהוא עדיין רישיון תקין, אבל קשה להבנה.\nכמו־כן, קשה לעשות שימוש חוזר ביצירות שפורסמו לפי GFDL.",
        "config-email-settings": "הגדרות דוא״ל",
        "config-enable-email": "להפעיל דוא״ל יוצא",
-       "config-enable-email-help": "אם אתם רוצים שדוא״ל יעבוד, [Config-dbsupport-oracle/manual/en/mail.configuration.php אפשרויות הדוא״ל של PHP] צריכות להיות מוגדרות נכון.\nאם אינכם רוצים להפעיל שום אפשרויות דוא״ל, כבו אותן כאן ועכשיו.",
+       "config-enable-email-help": "אם אתם רוצים שדוא״ל יעבוד, [https://secure.php.net/manual/en/mail.configuration.php אפשרויות הדוא״ל של PHP] צריכות להיות מוגדרות נכון.\nאם אינכם רוצים להפעיל שום אפשרויות דוא״ל, כבו אותן כאן ועכשיו.",
        "config-email-user": "להפעיל שליחת דוא״ל ממשתמש למשתמש",
        "config-email-user-help": "לאפשר לכל המשתמשים לשלוח אחד לשני דוא״ל אם הם הפעילו את זה בהעדפות שלהם.",
        "config-email-usertalk": "להפעיל הודעות על דף שיחת משתמש",
index 56b6e0e..1c14f7c 100644 (file)
@@ -128,4 +128,12 @@ class ReplicatedBagOStuff extends BagOStuff {
                $this->writeStore->clearLastError();
                $this->readStore->clearLastError();
        }
+
+       public function makeKey( $class, $component = null ) {
+               return $this->writeStore->makeKey( ...func_get_args() );
+       }
+
+       public function makeGlobalKey( $class, $component = null ) {
+               return $this->writeStore->makeGlobalKey( ...func_get_args() );
+       }
 }
index 9ebc63f..b98d7f1 100644 (file)
@@ -271,7 +271,7 @@ class FormatMetadata extends ContextSource {
                                        // TODO: YCbCrCoefficients  #p27 (see annex E)
                                        case 'ExifVersion':
                                        case 'FlashpixVersion':
-                                               $val = "$val" / 100;
+                                               $val = (int)$val / 100;
                                                break;
 
                                        case 'ColorSpace':
index a1b3064..0270828 100644 (file)
@@ -1353,15 +1353,7 @@ class Parser {
                }
 
                # Clean up special characters, only run once, next-to-last before doBlockLevels
-               $fixtags = [
-                       # French spaces, last one Guillemet-left
-                       # only if there is something before the space
-                       '/(.) (?=\\?|:|;|!|%|\\302\\273)/' => '\\1&#160;',
-                       # french spaces, Guillemet-right
-                       '/(\\302\\253) /' => '\\1&#160;',
-                       '/&#160;(!\s*important)/' => ' \\1', # Beware of CSS magic word !important, T13874.
-               ];
-               $text = preg_replace( array_keys( $fixtags ), array_values( $fixtags ), $text );
+               $text = Sanitizer::armorFrenchSpaces( $text );
 
                $text = $this->doBlockLevels( $text, $linestart );
 
index ff543db..21498f8 100644 (file)
@@ -1141,6 +1141,27 @@ class Sanitizer {
                return $encValue;
        }
 
+       /**
+        * Armor French spaces with a replacement character
+        *
+        * @since 1.32
+        * @param string $text Text to armor
+        * @param string $space Space character for the French spaces, defaults to '&#160;'
+        * @return string Armored text
+        */
+       public static function armorFrenchSpaces( $text, $space = '&#160;' ) {
+               // Replace $ with \$ and \ with \\
+               $space = preg_replace( '#(?<!\\\\)(\\$|\\\\)#', '\\\\$1', $space );
+               $fixtags = [
+                       # French spaces, last one Guillemet-left
+                       # only if there is something before the space
+                       '/(.) (?=[?:;!%»])/u' => "\\1$space",
+                       # French spaces, Guillemet-right
+                       '/(«) /u' => "\\1$space",
+               ];
+               return preg_replace( array_keys( $fixtags ), array_values( $fixtags ), $text );
+       }
+
        /**
         * Encode an attribute value for HTML tags, with extra armoring
         * against further wiki processing.
@@ -1168,6 +1189,9 @@ class Sanitizer {
                        '__'   => '&#95;_',
                ] );
 
+               # Armor against French spaces detection (T5158)
+               $encValue = self::armorFrenchSpaces( $encValue, '&#32;' );
+
                # Stupid hack
                $encValue = preg_replace_callback(
                        '/((?i)' . wfUrlProtocols() . ')/',
index e572aa4..68ea0c0 100644 (file)
@@ -486,16 +486,13 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
        }
 
        /**
-        * Helper method to gather file hashes for getDefinitionSummary.
-        *
-        * This function is context-sensitive, only computing hashes of files relevant to the
-        * given language, skin, etc.
+        * Helper method for getDefinitionSummary.
         *
         * @see ResourceLoaderModule::getFileDependencies
         * @param ResourceLoaderContext $context
         * @return array
         */
-       protected function getFileHashes( ResourceLoaderContext $context ) {
+       private function getFileHashes( ResourceLoaderContext $context ) {
                $files = [];
 
                // Flatten style files into $files
@@ -673,12 +670,12 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
        }
 
        /**
-        * Get a list of file paths for all scripts in this module, in order of proper execution.
+        * Get a list of script file paths for this module, in order of proper execution.
         *
         * @param ResourceLoaderContext $context
         * @return array List of file paths
         */
-       protected function getScriptFiles( ResourceLoaderContext $context ) {
+       private function getScriptFiles( ResourceLoaderContext $context ) {
                $files = array_merge(
                        $this->scripts,
                        $this->getLanguageScripts( $context->getLanguage() ),
@@ -717,6 +714,9 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
        /**
         * Get a list of file paths for all styles in this module, in order of proper inclusion.
         *
+        * This is considered a private method. Exposed for internal use by WebInstallerOutput.
+        *
+        * @private
         * @param ResourceLoaderContext $context
         * @return array List of file paths
         */
@@ -790,13 +790,13 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
        }
 
        /**
-        * Gets the contents of a list of JavaScript files.
+        * Get the contents of a list of JavaScript files. Helper for getScript().
         *
         * @param array $scripts List of file paths to scripts to read, remap and concetenate
-        * @throws MWException
         * @return string Concatenated and remapped JavaScript data from $scripts
+        * @throws MWException
         */
-       protected function readScriptFiles( array $scripts ) {
+       private function readScriptFiles( array $scripts ) {
                if ( empty( $scripts ) ) {
                        return '';
                }
@@ -819,17 +819,17 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
        }
 
        /**
-        * Gets the contents of a list of CSS files.
+        * Get the contents of a list of CSS files.
+        *
+        * This is considered a private method. Exposed for internal use by WebInstallerOutput.
         *
-        * @param array $styles List of media type/list of file paths pairs, to read, remap and
-        * concetenate
+        * @private
+        * @param array $styles Map of media type to file paths to read, remap, and concatenate
         * @param bool $flip
         * @param ResourceLoaderContext $context
-        *
-        * @throws MWException
         * @return array List of concatenated and remapped CSS data from $styles,
         *     keyed by media type
-        *
+        * @throws MWException
         * @since 1.27 Calling this method without a ResourceLoaderContext instance
         *   is deprecated.
         */
index e1bddcc..26d5e98 100644 (file)
@@ -426,7 +426,7 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
         * @param ResourceLoaderContext $context
         * @return array
         */
-       protected function getFileHashes( ResourceLoaderContext $context ) {
+       private function getFileHashes( ResourceLoaderContext $context ) {
                $this->loadFromDefinition();
                $files = [];
                foreach ( $this->getImages( $context ) as $name => $image ) {
index 120f559..b051d40 100644 (file)
@@ -429,8 +429,8 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                        // Detect changes to the module registrations
                        'moduleHashes' => $this->getAllModuleHashes( $context ),
 
-                       'fileMtimes' => [
-                               filemtime( "$IP/resources/src/startup.js" ),
+                       'fileHashes' => [
+                               $this->safeFileHash( "$IP/resources/src/startup.js" ),
                        ],
                ];
                return $summary;
index 6493df8..24f0613 100644 (file)
@@ -1,10 +1,20 @@
 <table class="{{# tableClasses }}{{ . }} {{/ tableClasses }}" data-mw-ts="{{{ fullTimestamp }}}">
-       <tr>
+       <tr class="mw-rcfilters-ui-highlights-enhanced-toplevel">
+               <td>
+                       <div class="mw-rcfilters-ui-highlights">
+                               <div class="mw-rcfilters-ui-highlights-color-none" data-color="none"></div>
+                               <div class="mw-rcfilters-ui-highlights-color-c1" data-color="c1"></div>
+                               <div class="mw-rcfilters-ui-highlights-color-c2" data-color="c2"></div>
+                               <div class="mw-rcfilters-ui-highlights-color-c3" data-color="c3"></div>
+                               <div class="mw-rcfilters-ui-highlights-color-c4" data-color="c4"></div>
+                               <div class="mw-rcfilters-ui-highlights-color-c5" data-color="c5"></div>
+                       </div>
+               </td>
                <td>
                        <span class="mw-collapsible-toggle mw-collapsible-arrow mw-enhancedchanges-arrow mw-enhancedchanges-arrow-space"></span>
                </td>
                <td class="mw-changeslist-line-prefix">{{{ prefix }}}</td>
-               <td class="mw-enhanced-rc">{{{ collectedRcFlags }}}&#160;{{ timestamp }}&#160;</td>
+               <td class="mw-enhanced-rc" colspan="2">{{{ collectedRcFlags }}}&#160;{{ timestamp }}&#160;</td>
                <td class="mw-changeslist-line-inner">
                        {{# rev-deleted-event }}<span class="history-deleted">{{{ . }}}</span>{{/ rev-deleted-event }}
                        {{{ articleLink }}}{{{ languageDirMark }}}{{{ logText }}}
                </td>
        </tr>
        {{# lines }}
-       <tr class="{{# classes }}{{ . }} {{/ classes }}"{{{ attribs }}}>
+       <tr class="mw-rcfilters-ui-highlights-enhanced-nested {{# classes }}{{ . }} {{/ classes }}"{{{ attribs }}}>
+               <td></td>
                <td></td>
                <td></td>
                <td class="mw-enhanced-rc">{{{ recentChangesFlags }}}&#160;</td>
+               <td>
+                       <div class="mw-rcfilters-ui-highlights mw-enhanced-rc-nested">
+                               <div class="mw-rcfilters-ui-highlights-color-none" data-color="none"></div>
+                               <div class="mw-rcfilters-ui-highlights-color-c1" data-color="c1"></div>
+                               <div class="mw-rcfilters-ui-highlights-color-c2" data-color="c2"></div>
+                               <div class="mw-rcfilters-ui-highlights-color-c3" data-color="c3"></div>
+                               <div class="mw-rcfilters-ui-highlights-color-c4" data-color="c4"></div>
+                               <div class="mw-rcfilters-ui-highlights-color-c5" data-color="c5"></div>
+                       </div>
+               </td>
                <td class="mw-enhanced-rc-nested" data-target-page="{{ targetTitle }}">
                        {{# timestampLink }}
                        <span class="mw-enhanced-rc-time">{{{ . }}}</span>
index de9cec0..15e292d 100644 (file)
        "largefileserver": "Памер гэтага файлу перавышае максымальна дазволены сэрвэрам.",
        "emptyfile": "Загружаны файл, здаецца, пусты. Магчыма гэта адбылося з-за памылкі ў назьве файлу. Калі ласка, удакладніце, ці вы сапраўды жадаеце загрузіць гэты файл.",
        "windows-nonascii-filename": "Гэтая вікі не падтрымлівае назвы файлаў з спэцыяльнымі сымбалямі.",
-       "fileexists": "Файл з такой назвай ужо існуе. Калі ласка, праверце <strong>[[:$1]]</strong>, калі Вы ня ўпэўненыя, што жадаеце яго замяніць. [[$1|thumb]]",
-       "filepageexists": "Старонка апісаньня для гэтага файла ўжо існуе як <strong>[[:$1]]</strong>, але файла з такой назвай няма.\nАпісаньне якое Вы дадалі ня зьявіцца на старонцы апісаньня.\nКаб яно там зьявілася, Вам трэба рэдагаваць яе самастойна.\n[[$1|thumb]]",
+       "fileexists": "Файл з такой назвай ужо існуе. Калі ласка, праверце <strong>[[:$1]]</strong>, калі {{GENDER:|вы}} ня ўпэўненыя, што жадаеце яго замяніць.\n[[$1|thumb]]",
+       "filepageexists": "Старонка апісаньня для гэтага файлу ўжо існуе як <strong>[[:$1]]</strong>, але файлу з такой назвай няма.\nАпісаньне якое вы дадалі ня зьявіцца на старонцы апісаньня.\nКаб яно там зьявілася, вам трэба рэдагаваць яе самастойна.\n[[$1|thumb]]",
        "fileexists-extension": "Файл з падобнай назвай ужо існуе: [[$2|thumb]]\n* Назва загружанага файла: <strong>[[:$1]]</strong>\n* Назва існуючага файла: <strong>[[:$2]]</strong>\nМагчыма, вы жадаеце выкарыстаць адрозную назву?",
        "fileexists-thumbnail-yes": "Верагодна файл зьяўляецца паменшанай копіяй ''(мініятурай)''. [[$1|thumb]]\nКалі ласка, праверце файл <strong>[[:$1]]</strong>.\nКалі правераны файл зьяўляецца той жа выявай, то загрузка мініятуры ня мае сэнсу.",
        "file-thumbnail-no": "Назва файла пачынаецца з <strong>$1</strong>.\nВерагодна гэта паменшаная копія выявы ''(мініятура)''.\nКалі Вы маеце гэтую выяву ў поўным памеры, загрузіце яе, альбо зьмяніце назву файла.",
index 7585117..4cbc07b 100644 (file)
@@ -37,7 +37,8 @@
                        "Mohammed Galib Hasan",
                        "এম আবু সাঈদ",
                        "Shahadat1971",
-                       "Rasal Lia"
+                       "Rasal Lia",
+                       "আফতাবুজ্জামান"
                ]
        },
        "tog-underline": "সংযোগের নিচে দাগ দেখানো হোক:",
        "cantrollback": "পূর্বের সংস্করণে ফেরত যাওয়া সম্ভব হল না, সর্বশেষ সম্পাদনাকারী এই নিবন্ধটির একমাত্র লেখক।",
        "alreadyrolled": "[[User:$2|$2]] ([[User talk:$2|আলাপ]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) দ্বারা সম্পাদিত [[:$1]]-এর সর্বশেষ সম্পাদনাটি পুনর্বহাল করা যাচ্ছে না;\nঅন্য কোন ব্যবহারকারী এই পাতা ইতিমধ্যে সম্পাদনা বা পুনর্বহাল করেছেন।\n\nএই পাতায় সর্বশেষ সম্পাদনা করেছেন [[User:$3|$3]] ([[User talk:$3|আলাপ]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]])।",
        "editcomment": "সম্পাদনা সারাংশ ছিল: \"''$1''\"।",
-       "revertpage": "[[Special:Contributions/$2|$2]] ([[User talk:$2|আলাপ]]) এর সম্পাদিত সংস্করণ হতে [[User:$1|$1]] এর সম্পাদিত সর্বশেষ সংস্করণে ফেরত যাওয়া হয়েছে।",
-       "revertpage-nouser": "একজন গোপন ব্যবহারকারী কর্তৃক সম্পাদিত সম্পাদনাটি বাতিলপূর্বক {{GENDER:$1|[[User:$1|$1]]}}-এর সর্বশেষ সম্পাদনায় ফেরত যাওয়া হয়েছে",
+       "revertpage": "[[Special:Contributions/$2|$2]] ([[User talk:$2|আলাপ]])-এর সম্পাদিত সংস্করণ হতে [[User:$1|$1]]-এর সম্পাদিত সর্বশেষ সংস্করণে ফেরত যাওয়া হয়েছে",
+       "revertpage-nouser": "একজন গোপন ব্যবহারকারী কর্তৃক সম্পাদিত সম্পাদনাটি বাতিলপূর্বক {{GENDER:$1|[[User:$1|$1]]}}-এর সর্বশেষ সম্পাদনায় ফেরত যাওয়া হয়েছে",
        "rollback-success": "{{GENDER:$3|$1}}-এর সম্পাদনাগুলি পূর্বাবস্থায় ফিরিয়ে নেওয়া হয়েছে; {{GENDER:$4|$2}}-এর করা শেষ সংস্করণে পাতাটি ফেরত নেওয়া হয়েছে।",
        "rollback-success-notify": "$1-এর সম্পাদনাগুলি বাতিল করা হয়েছে; \n$2-এর করা শেষ সংস্করণে ফেরত নেওয়া হয়েছে। [$3 পরিবর্তন দেখুন]",
        "sessionfailure-title": "সেশন পরিত্যক্ত",
index c5036eb..a5250de 100644 (file)
        "prefs-misc": "Razno",
        "prefs-resetpass": "Promijeni lozinku",
        "prefs-changeemail": "Promijeni ili ukloni adresu e-pošte",
-       "prefs-setemail": "Postavite e-mail adresu",
+       "prefs-setemail": "Postavi adresu e-pošte",
        "prefs-email": "Opcije e-pošte",
        "prefs-rendering": "Izgled",
        "saveprefs": "Sačuvaj",
        "badsig": "Loš sirovi potpis.\nProvjerite HTML tagove.",
        "badsiglength": "Vaš potpis je predug.\nMora biti manji od $1 {{PLURAL:$1|znaka|znaka|znakova}}.",
        "yourgender": "Kako želite da se predstavite?",
-       "gender-unknown": "Kad Vas spominje, softver će pokušati izbjegavati rod kad god je to moguće",
+       "gender-unknown": "Kad Vas spominje, softver će koristiti rodno neutralne riječi kad god je to moguće",
        "gender-male": "On uređuje wiki stranice",
        "gender-female": "Ona uređuje wiki stranice",
        "prefs-help-gender": "Ova postavka nije obavezna.\nSoftver koristi datu vrijednost da bi Vam se obratio i spomenuo Vas drugima koristeći odgovarajući gramatički rod.\nPodatak će biti javan.",
        "tooltip-pt-createaccount": "Ohrabrujemo vas da otvorite nalog i prijavite se, međutim to nije obavezno",
        "tooltip-ca-talk": "Razgovor o sadržaju",
        "tooltip-ca-edit": "Uredi ovu stranicu",
-       "tooltip-ca-addsection": "Započnite novu sekciju.",
+       "tooltip-ca-addsection": "Započni novu sekciju.",
        "tooltip-ca-viewsource": "Ova stranica je zaštićena.\nMožete joj vidjeti izvorni kôd",
        "tooltip-ca-history": "Prethodne verzije ove stranice.",
        "tooltip-ca-protect": "Zaštitite stranicu od budućih izmjena",
        "tooltip-search": "Pretraži {{GRAMMAR:akuzativ|{{SITENAME}}}}",
        "tooltip-search-go": "Idi na stranicu s tačno ovim imenom ako postoji",
        "tooltip-search-fulltext": "Pretražite stranice s ovim tekstom",
-       "tooltip-p-logo": "Posjetite početnu stranicu",
-       "tooltip-n-mainpage": "Posjetite početnu stranicu",
-       "tooltip-n-mainpage-description": "Posjetite početnu stranicu",
+       "tooltip-p-logo": "Posjeti početnu stranicu",
+       "tooltip-n-mainpage": "Posjeti početnu stranicu",
+       "tooltip-n-mainpage-description": "Posjeti početnu stranicu",
        "tooltip-n-portal": "O projektu, šta možete da uradite, gdje se šta nalazi",
        "tooltip-n-currentevents": "Podaci o onome na čemu se trenutno radi",
        "tooltip-n-recentchanges": "Spisak nedavnih izmjena na wiki.",
index 8fc95fb..7637779 100644 (file)
@@ -92,7 +92,8 @@
                        "Osnard",
                        "Suriyaa Kudo",
                        "KPFC",
-                       "ToBeFree"
+                       "ToBeFree",
+                       "PerfektesChaos"
                ]
        },
        "tog-underline": "Links unterstreichen:",
        "whatlinkshere-title": "Seiten, die auf „$1“ verlinken",
        "whatlinkshere-page": "Seite:",
        "linkshere": "Die folgenden Seiten verlinken auf <strong>$2</strong>:",
-       "nolinkshere": "Keine Seiten verlinken auf <strong>$2</strong>.",
-       "nolinkshere-ns": "Keine Seiten verlinken auf <strong>$2</strong> in dem ausgewählten Namensraum.",
+       "nolinkshere": "Keine Seite verlinkt auf <strong>$2</strong>.",
+       "nolinkshere-ns": "Keine Seite in dem ausgewählten Namensraum verlinkt auf <strong>$2</strong>.",
        "isredirect": "Weiterleitungsseite",
        "istemplate": "Vorlageneinbindung",
        "isimage": "Dateilink",
index 95f0955..74a7ce4 100644 (file)
                        "KATRINE1992",
                        "Athena in Wonderland",
                        "Truebamateo",
-                       "La Mantis"
+                       "La Mantis",
+                       "Amaia"
                ]
        },
        "tog-underline": "Subrayar los enlaces:",
        "converter-manual-rule-error": "Se ha detectado un error en una regla manual de conversión de idioma",
        "undo-success": "Puedes deshacer la edición. Antes de deshacer la edición, comprueba la siguiente comparación para verificar que realmente es lo que quieres hacer, y entonces guarda los cambios para así efectuar la reversión.",
        "undo-failure": "No se ha podido deshacer la edición ya que otro usuario ha realizado una edición intermedia.",
+       "undo-main-slot-only": "No se ha podido desacer el cámbio porque contiene contenido fuera del slot principal.",
        "undo-norev": "No se ha podido deshacer la edición porque no existe o ha sido borrada.",
        "undo-nochange": "Parece que ya se había deshecho la edición.",
        "undo-summary": "Se ha deshecho la revisión $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|disc.]])",
index d51ca07..c93d35d 100644 (file)
@@ -70,7 +70,7 @@
        "tog-watchlisthideminor": "Segimendu zerrendan, aldaketa txikiak ezkutatu",
        "tog-watchlisthideliu": "Ezkutatu izena emana duten lankideen aldaketak, jarraitze-zerrendan",
        "tog-watchlistreloadautomatically": "Berkargatu automatikoki jarraipen zerrenda iragazkiren bat aldatzerakoan (JavaScript beharrezkoa)",
-       "tog-watchlistunwatchlinks": "Gehitu zuzeneko ezikusi/ikusi loturak ikus-zerrendako sarreretan (JavaScript beharrezkoa funtzionaltasuna aldatzeko)",
+       "tog-watchlistunwatchlinks": "Gehitu zuzeneko ezikusi/ikusi markatzaileak ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}) aldatuak izan diren ikusitako orrietan (JavaScript beharrezkoa funtzionaltasuna erabiltzeko)",
        "tog-watchlisthideanons": "Ezkutatu lankide anonimoen aldaketak, jarraitze-zerrendan",
        "tog-watchlisthidepatrolled": "Ezkutatu patruilatutako aldaketak jarraitze-zerrendan",
        "tog-watchlisthidecategorization": "Orrialdeen kategorizazioa ezkutatu",
        "converter-manual-rule-error": "Akatsa aurkitu da hizkuntzen eskuszko konbertsio arauan",
        "undo-success": "Aldaketa desegin daiteke.\nMesedez beheko alderaketa egiaztatu, egin nahi duzuna hori dela frogatzeko, eta ondoren azpiko aldaketak gorde, aldaketa desegiten amaitzeko.",
        "undo-failure": "Ezin izan da aldaketa desegin tarteko aldaketekin gatazkak direla-eta.",
+       "undo-main-slot-only": "Aldaketa ezin da desegin, slot nagusitik kanpoko edukia daukalako.",
        "undo-norev": "Aldaketa ezin da desegin ez delako existitzen edo ezabatu zutelako.",
        "undo-nochange": "Aldaketa hau honezkero desegin da.",
        "undo-summary": "[[Special:Contributions/$2|$2]] ([[User talk:$2|eztabaida]]) wikilariaren $1 berrikuspena desegin da",
index 060a61b..f36aa8c 100644 (file)
        "rcfilters-other-review-tools": "Muut arviointityökalut",
        "rcfilters-group-results-by-page": "Ryhmitä tulokset sivujen mukaan",
        "rcfilters-activefilters": "Aktiiviset suodattimet",
+       "rcfilters-activefilters-hide": "Piilota",
+       "rcfilters-activefilters-show": "Näytä",
        "rcfilters-advancedfilters": "Kehittyneet suodattimet",
        "rcfilters-limit-title": "Näytettävät tulokset",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|muutos|muutosta}}, $2",
        "rcfilters-empty-filter": "Ei aktiivisia suodattimia. Kaikki muutokset näytetään.",
        "rcfilters-filterlist-title": "Suodattimet",
        "rcfilters-filterlist-whatsthis": "Miten nämä toimivat?",
-       "rcfilters-filterlist-feedbacklink": "Kerro mielipiteesi (uusista) suodattimista",
+       "rcfilters-filterlist-feedbacklink": "Kerro mielipiteesi näistä suodatintyökaluista",
        "rcfilters-highlightbutton-title": "Korosta tulokset",
        "rcfilters-highlightmenu-title": "Valitse väri",
        "rcfilters-highlightmenu-help": "Valitse korostusväri tälle ominaisuudelle",
        "dellogpage": "Poistoloki",
        "dellogpagetext": "Alla on loki viimeisimmistä poistoista.",
        "deletionlog": "poistoloki",
+       "logentry-create-create": "$1 {{GENDER:$2|loi}} sivun $3",
        "reverted": "Palautettu aikaisempaan versioon",
        "deletecomment": "Syy:",
        "deleteotherreason": "Muu syy tai tarkennus:",
        "blankpage": "Tyhjä sivu",
        "intentionallyblankpage": "Tämä sivu on tarkoituksellisesti tyhjä.",
        "external_image_whitelist": " #Älä muuta tätä riviä lainkaan.<pre>\n#Laita säännöllisten lausekkeiden palaset (vain osa, joka menee //-merkkien väliin) alle\n#Niitä verrataan ulkoisten (suoralinkitettyjen) kuvien URLeihin\n#Ne jotka sopivat, näytetään kuvina, muutoin kuviin näytetään vain linkit\n#Rivit, jotka alkavat #-merkillä ovat kommentteja\n#Tämä on riippumaton kirjainkoosta\n\n#Laita kaikki säännöllisten lausekkeiden palaset tämän rivit yläpuolelle. Älä muuta tätä riviä lainkaan</pre>",
-       "tags": "Voimassa olevat muutosmerkinnät",
+       "tags": "Voimassa olevat muutosten merkkaukset",
        "tag-filter": "[[Special:Tags|Merkkausten]] suodatin:",
        "tag-filter-submit": "Suodata",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Merkkaus|Merkkaukset}}]]: $2)",
index 9b3b322..6da8aae 100644 (file)
        "password-login-forbidden": "L’utilisation de ce nom d’utilisateur ou de ce mot de passe a été interdite.",
        "mailmypassword": "Réinitialiser le mot de passe",
        "passwordremindertitle": "Nouveau mot de passe temporaire pour {{SITENAME}}",
-       "passwordremindertext": "Quelqu’un (depuis l’adresse IP $1) a demandé un nouveau mot de\npasse pour {{SITENAME}} ($4). Un mot de passe temporaire pour l’utilisateur\n« $2 » a été créé et est « $3 ». Si cela était votre intention,\nvous devrez vous connecter et choisir un nouveau mot de passe.\nVotre mot de passe temporaire expirera dans $5 jour{{PLURAL:$5||s}}.\n\nSi vous n’êtes pas l’auteur de cette demande, ou si vous vous souvenez à présent de\nvotre mot de passe et ne souhaitez plus en changer, vous pouvez ignorer ce message\net continuer à utiliser votre ancien mot de passe.",
+       "passwordremindertext": "Quelqu’un (depuis l’adresse IP $1) a demandé un nouveau mot de\npasse pour {{SITENAME}} ($4). Un mot de passe temporaire pour l’utilisateur\n« $2 » a été créé et est « $3 ». Si cela était votre intention,\nvous devrez vous connecter et choisir un nouveau mot de passe.\nVotre mot de passe temporaire expirera dans $5 jour{{PLURAL:$5||s}}.\n\nSi vous n’êtes pas l’auteur de cette demande, ou si vous vous avez retrouvé votre mot de passe et ne souhaitez plus en changer, vous pouvez ignorer ce message\net continuer à utiliser votre ancien mot de passe.",
        "noemail": "Aucune adresse de courriel n’a été enregistrée pour l’utilisat{{GENDER:$1|eur|rice}} « $1 ».",
        "noemailcreate": "Vous devez fournir une adresse de courriel valide",
        "passwordsent": "Un nouveau mot de passe a été envoyé à l’adresse de courriel de l’utilisat{{GENDER:$1|eur|rice}} « $1 ».\nVeuillez vous reconnecter après l’avoir reçu.",
        "resetpass-submit-loggedin": "Changer de mot de passe",
        "resetpass-submit-cancel": "Annuler",
        "resetpass-wrong-oldpass": "Mot de passe actuel ou temporaire invalide.\nVous avez peut-être déjà changé votre mot de passe ou demandé un nouveau mot de passe temporaire.",
-       "resetpass-recycled": "Veuillez modifier votre mot de passe à quelque chose d’autre que l’actuel.",
+       "resetpass-recycled": "Veuillez modifier votre mot de passe avec autre chose que l’actuel.",
        "resetpass-temp-emailed": "Vous êtes connecté{{GENDER:||e}} avec un code temporaire fourni par courriel.\nPour terminer la connexion, vous devez fournir un nouveau mot de passe ici :",
        "resetpass-temp-password": "Mot de passe temporaire :",
        "resetpass-abort-generic": "La modification du mot de passe a été annulée par une extension.",
        "whatlinkshere-title": "Pages qui pointent vers « $1 »",
        "whatlinkshere-page": "Page :",
        "linkshere": "Les pages ci-dessous contiennent un lien vers <strong>$2</strong> :",
-       "nolinkshere": "Aucune page ne contient de lien vers <strong>$2</strong>.",
+       "nolinkshere": "Aucune page ne contient de liens vers <strong>$2</strong>.",
        "nolinkshere-ns": "Aucune page ne contient de liens vers <strong>$2</strong> dans l'espace de noms choisi.",
        "isredirect": "page de redirection",
        "istemplate": "inclusion",
index d1e6885..28978ae 100644 (file)
@@ -24,9 +24,9 @@
        "tog-minordefault": "Marké tout mo modifikasyon kou minò pa défo",
        "tog-previewontop": "Afiché prévizwalizasyon-an laro di zonn di modifikasyon",
        "tog-previewonfirst": "Afiché prévizwalizasyon-an lò di pronmyé modifikasyon",
-       "tog-enotifwatchlistpages": "Avèrti mo pa kouryé lò roun paj ou roun fiché di mo lis di swivi sa modifyé",
+       "tog-enotifwatchlistpages": "Avèrti mo pa kouryé lòské roun paj oben roun fiché di mo lis di swivi sa modifyé",
        "tog-enotifusertalkpages": "Avèrti mo pa kouryé lò mo paj di diskisyon sa modifyé",
-       "tog-enotifminoredits": "Avèrti mo pa kouryé égalman lò dé modifikasyon minò dé paj ou dé fiché",
+       "tog-enotifminoredits": "Avèrti mo pa kouryé égalman lò dé modifikasyon minò dé paj oben dé fiché",
        "tog-enotifrevealaddr": "Afiché mo adrès élèktronik andan kouryé di notifikasyon",
        "tog-shownumberswatching": "Afiché nonm-an di itilizatò an kour",
        "tog-oldsig": "Zòt signatir atchwèl :",
@@ -50,7 +50,7 @@
        "tog-prefershttps": "Toujou itilizé roun konèksyon sékirizé lò mo konèkté",
        "underline-always": "Toujou",
        "underline-never": "Janmè",
-       "underline-default": "Valò pa défo di tenm ou di navigatò",
+       "underline-default": "Valò pa défo di tenm oben di navigatò",
        "editfont-style": "Stil di polis di zonn di modifikasyon",
        "editfont-monospace": "Polis ké chas fiks",
        "editfont-sansserif": "Polis sans-serif",
        "confirmable-confirm": "Ès zòt sir{{GENDER:$1||}} ?",
        "confirmable-yes": "Wi",
        "confirmable-no": "Awa",
-       "thisisdeleted": "Ès zòt ka déziré afiché ou rèstoré $1 ?",
+       "thisisdeleted": "Ès zòt ka déziré afiché oben rèstoré $1 ?",
        "viewdeleted": "Wè $1 ?",
        "restorelink": "Wè {{PLURAL:$1|roun modifikasyon éfasé|$1 modifikasyon éfasé}}",
        "feedlinks": "Flux :",
        "noarticletext": "I pa gen atchwèlman pyès tèks asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|lansé oun sasé asou sa tit]] annan ròt paj-ya,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sasé annan opérasyon ki lyannen]\noben [{{fullurl:{{FULLPAGENAME}}|action=edit}} kréyé sa paj]</span>.",
        "noarticletext-nopermission": "I pa gen atchwèlman pyès tèks asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|fè roun sasé asou sa tit]] andan ròt paj-ya,\noben <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|paj={{FULLPAGENAMEE}}}} sasé annan journal asosyé]</span>, mè zòt pa gen pèrmisyon di kréyé sa paj.",
        "userpage-userdoesnotexist-view": "Kont itilizatò-a « $1 » pa anréjistré.",
-       "clearyourcache": "<strong>Nòt :</strong> aprè zòt anréjistré zòt modifikasyon, zòt divèt forsé roucharjman konplè di kach di zòt navigatò pou wè chanjman-yan.\n* <strong>Firefox / Safari :</strong> mentné touch-a <em>Maj</em> (<em>Shift</em>) an klikan asou bouton-an <em>Atchwalizé</em> ou présé <em>Ctrl-F5</em> ou <em>Ctrl-R</em> (<em>⌘-R</em> asou roun Mac) \n* <strong>Google Chrome :</strong> apwiyé asou <em>Ctrl-Maj-R</em> (<em>⌘-Shift-R</em> asou roun Mac) \n* <strong>Internet Explorer :</strong> mentné touch-a <em>Ctrl</em> an klikan asou bouton-an <em>Atchwalizé</em> ou présé <em>Ctrl-F5</em> \n* <strong>Opera :</strong> alé annan <em>Menu → Settings</em> (<em>Opera → Préférences</em> asou roun Mac) é answit à <em>Konfidansyalité & sékrité → Éfasé doné d'èksplorasyon-yan → Imaj ké fiché an kach</em>.",
+       "clearyourcache": "<strong>Nòt :</strong> aprè zòt anréjistré zòt modifikasyon, zòt divèt fòrsé roucharjman konplè di kach di zòt navigatò pou wè chanjman-yan.\n* <strong>Firefox / Safari :</strong> mentné touch-a <em>Maj</em> (<em>Shift</em>) an klikan asou bouton-an <em>Atchwalizé</em> oben présé <em>Ctrl-F5</em> oben <em>Ctrl-R</em> (<em>⌘-R</em> asou roun Mac) \n* <strong>Google Chrome :</strong> apiyé asou <em>Ctrl-Maj-R</em> (<em>⌘-Shift-R</em> asou roun Mac) \n* <strong>Internet Explorer :</strong> mentni touch-a <em>Ctrl</em> an klikan asou bouton-an <em>Atchwalizé</em> oben présé <em>Ctrl-F5</em> \n* <strong>Opera :</strong> alé annan <em>Menu → Settings</em> (<em>Opera → Préférences</em> asou roun Mac) é answit à <em>Konfidansyalité & sékrité → Éfasé doné d'èsplorasyon-yan → Imaj ké fiché an kach</em>.",
        "previewnote": "<strong>Raplé-zòt ki a jis roun prévizwalizasyon.</strong>\nZòt modifikasyon pa òkò anréjistré !",
        "continue-editing": "Alé kot zonn di modifikasyon",
        "editing": "Modifikasyon di $1",
        "booksources-search-legend": "Sasé parmi dé ouvraj di référans",
        "booksources-search": "Sasé",
        "specialloguserlabel": "Otò :",
-       "speciallogtitlelabel": "Sib (tit ou {{ns:user}}:non di itilizatò) :",
+       "speciallogtitlelabel": "Sib (tit oben {{ns:user}}:non di itilizatò) :",
        "log": "Journal d’opérasyon",
        "all-logs-page": "Tout journal piblik",
        "alllogstext": "Afichaj konbiné di tout journal disponib asou {{SITENAME}}.\nZòt pouvé pèrsonalizé afichaj an sélèksyonnan tip di journal, non di itilizatò oben paj-a ki konsèrné (sa Dé dannyé sa sansib à lakas).",
        "invert": "Envèrsé sélèksyon-an",
        "tooltip-invert": "Koché sa kaz pou kaché modifikasyon-yan dé paj annan lèspas di non sélèksyoné (ké lèspas di non asosyé si koché)",
        "namespace_association": "Lèspas di non asosyé",
-       "tooltip-namespace_association": "Koché sa kaz pou enklir égalman lèspas di non di diskisyon ou di sijè, asosyé à lèspas di non sélèksyoné",
+       "tooltip-namespace_association": "Koché sa kaz pou enkli égalman lèspas di non di diskisyon oben di sijè, ki asosyé à lèspas di non ki sélèksyoné",
        "blanknamespace": "(Prensipal)",
        "contributions": "Kontribisyon di {{GENDER:$1|itilizatò|itilizatris}}",
        "contributions-title": "Lis di kontribisyon-yan di itiliza{{GENDER:$1|ò|ris}}-a $1",
        "sp-contributions-logs": "journal",
        "sp-contributions-talk": "diskité",
        "sp-contributions-search": "Sasé kontribisyon-yan",
-       "sp-contributions-username": "Adrès IP ou non di itilizatò :",
+       "sp-contributions-username": "Adrès IP oben non di itilizatò :",
        "sp-contributions-toponly": "Montré ki kontribisyon-yan ki sa dannyé-ya dé artik",
        "sp-contributions-newonly": "Afiché inikman modifikasyon-yan ki sa dé kréyasyon di paj",
        "sp-contributions-submit": "Sasé",
        "tooltip-diff": "Afiché modifikasyon-yan ki zòt apòrté andan tèks-a.",
        "tooltip-compareselectedversions": "Afiché diférans-ya ant dé vèrsyon-yan sélèksyoné di sa paj",
        "tooltip-watch": "Ajouté sa paj annan zòt lis di swivi",
-       "tooltip-rollback": "« Révoké » ka anilé an roun klik modifikasyon(-an ou yan) di sa paj réyalizé pa so dannyé kontribitò",
+       "tooltip-rollback": "« Révoké » ka anilé an roun klik modifikasyon(-an oben yan) di sa paj ki réyalizé pa so dannyé kontribitò",
        "tooltip-undo": "« Anilé » ka rétabli modifikasyon présédant é ka ouvri lafinèt di modifikasyon an mòd prévizwalizasyon. I posib di ajouté roun rézon annan rézimé-a.",
        "tooltip-summary": "Antré roun brèf rézimé",
        "simpleantispam-label": "Vérifikasyon anti-pouryèl.\nPa <strong>enskri</strong> anyen isi !",
        "watchlisttools-edit": "Wè é modifyé lis di swivi",
        "watchlisttools-raw": "Modifyé lis di swivi an mòd brout",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|diskisyon]])",
-       "redirect": "Roudirijé pa ID di fiché, itilizatò, paj, révizyon ou journal",
+       "redirect": "Roudirijé pa ID di fiché, itilizatò, paj, révizyon oben journal",
        "redirect-summary": "Sa paj èspésyal ka roudirijé bò'd roun fiché (non di fiché fourni), oun paj (ID di révizyon oben di paj fourni), oun paj di itilizatò (idantifyan nimérik di itilizatò fourni), oben roun antré di journal (ID di journal fourni). Itilizasyon : [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], oben [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Validé",
        "redirect-lookup": "Sasé :",
index 2236e97..53e2ef5 100644 (file)
        "imagepage": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐍆𐌰𐌾𐌻𐌰𐌻𐌰𐌿𐍆",
        "mediawikipage": "𐌰𐌽𐌳𐌷𐌿𐌻𐌴𐌹 𐍅𐌰𐌿𐍂𐌳𐌰𐌻𐌰𐌿𐍆",
        "viewhelppage": "𐌰𐌽𐌳𐌷𐌿𐌻𐌴𐌹 𐌷𐌹𐌻𐍀𐌰𐌻𐌰𐌿𐍆",
+       "categorypage": "𐍃𐌰𐌹𐍈 𐌺𐌿𐌽𐌾𐌰𐌻𐌰𐌿𐍆",
        "viewtalkpage": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌰",
        "otherlanguages": "𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐍂𐌰𐌶𐌳𐍉𐌼",
        "redirectedfrom": "(𐌹𐍃 {{GENDER:𐍄𐌹𐌿𐌷𐌰𐌽𐍃|𐍄𐌹𐌿𐌷𐌰𐌽𐌰}} 𐌷𐌹𐌳𐍂𐌴 𐍆𐍂𐌰𐌼 $1)",
        "redirectpagesub": "𐌰𐌻𐌾𐌰𐍂 𐌱𐍂𐌹𐌲𐌲𐌰𐌽𐌳𐍃 𐌻𐌰𐌿𐍆𐍃",
        "lastmodifiedat": "𐍃𐌰 𐌻𐌰𐌿𐍆𐍃 𐌸𐌰𐍄𐌰 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄 𐌹𐌽𐌼𐌰𐌹𐌳𐌹𐌸𐍃 𐍅𐌰𐍃 $1, 𐌰𐍄 $2.",
+       "viewcount": "𐍃𐌰 𐌻𐌰𐌿𐍆𐍃 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐍃 𐌹𐍃𐍄 {{PLURAL:$1|𐌰𐌹𐌽𐌰𐌼𐌼𐌰 𐍃𐌹𐌽𐌸𐌰|$1 𐍃𐌹𐌽𐌸𐌰𐌼}}.",
        "protectedpage": "𐍆𐍂𐌹𐌸𐍉𐌽𐍃 𐌻𐌰𐌿𐍆𐍃",
        "jumpto": "𐌲𐌰𐌲𐌲 𐌳𐌿:",
        "jumptonavigation": "𐌻𐌰𐌿𐌱𐌰𐌲𐌰𐍅𐌹𐍃𐍃𐌴𐌹𐍃",
        "readonly": "𐌳𐌰𐍄𐌰𐌷𐌿𐌶𐌳 𐌻𐌿𐌺𐌰𐌽 𐌹𐍃𐍄",
        "enterlockreason": "𐌲𐌹𐍆 𐍅𐌰𐌹𐌷𐍄 𐌻𐌿𐌺𐌰, 𐌾𐌰𐌷 𐍃𐍅𐌰 𐌻𐌰𐌲𐌲𐌰𐌱𐌰 𐍆𐌰𐌿𐍂𐌸𐌹𐌶𐌴𐌹 𐌻𐌿𐌺 𐌿𐍃𐌼𐌴𐍂𐌽𐌰𐌹",
        "missing-article": "𐌳𐌰𐍄𐌰𐌷𐌿𐌶𐌳 𐌽𐌹 𐌱𐌹𐌲𐌰𐍄 𐌱𐍉𐌺𐍉𐍃 𐌻𐌰𐌿𐌱𐌹𐍃 𐌸𐌹𐌶𐌴𐌹 𐍃𐌺𐌿𐌻𐌳𐌴𐌳𐌹 𐌱𐌹𐌲𐌹𐍄𐌰𐌽, 𐌷𐌰𐌹𐍄𐌰𐌽𐍃 \"$1\" $2. \n\n𐌸𐌰𐍄𐌰 𐌿𐍆𐍄𐌰 𐍅𐌰𐌹𐍂𐌸𐌹𐌸 𐌾𐌰𐌱𐌰𐌹 𐌻𐌰𐌹𐍃𐍄𐌾𐌰𐌳𐌰 𐍆𐌰𐌹𐍂𐌽𐌾𐌰 𐌳𐌹𐍆𐍆 𐌸𐌰𐌿 𐍃𐍀𐌹𐌻𐌻𐌰𐌲𐌰𐍅𐌹𐍃𐍃 𐍃𐌴𐌹 𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌹𐌳𐌰 𐌹𐍃𐍄. 𐌾𐌰𐌱𐌰𐌹 𐌽𐌹𐍃𐍄, 𐌼𐌰𐌷𐍄𐍃 𐌹𐍃𐍄 𐌴𐌹 𐌱𐌹𐌲𐌴𐍄𐌴𐌹𐍃 𐌰𐌹𐍂𐌶𐌴𐌹𐌽 𐌹𐌽 𐍃𐌰𐌿𐍆𐍄𐍅𐌰𐌹𐍂𐌰. \n\n𐌱𐌹𐌳𐌾𐌰𐌼 𐌸𐌿𐌺, 𐌼𐌴𐍂𐌴𐌹 𐌸𐌰𐍄𐌰 𐌳𐌿 [[Special:ListUsers/sysop\n|𐍂𐌴𐌹𐌺]] 𐌲𐌹𐍆𐌿𐌷 𐌲𐌰𐍅𐌹𐍃.",
+       "filedeleteerror": "𐌼𐌰𐌷𐍄𐍃 𐌽𐌹 𐍅𐌰𐍃 𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌾𐌰𐌽 𐍆𐌰𐌾𐌻𐌰 \"$1\".",
+       "formerror": "𐌰𐌹𐍂𐌶𐌴𐌹: 𐍆𐌰𐌿𐍂𐌼𐌰 𐌹𐌽𐍃𐌰𐌽𐌳𐌾𐌰𐌽 𐌽𐌹 𐍅𐌰𐍃 𐌼𐌰𐌷𐍄𐍃.",
        "badarticleerror": "𐌸𐍉 𐍅𐌰𐌹𐌷𐍄 𐌽𐌹 𐌼𐌰𐌲𐍄 𐍄𐌰𐌿𐌾𐌰𐌽 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰.",
        "cannotdelete-title": "𐌽𐌹 𐌼𐌰𐌲 𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌾𐌰𐌽 𐌻𐌰𐌿𐌱𐌰 \"$1\"",
        "badtitle": "𐌿𐌽𐍂𐌰𐌹𐌷𐍄𐌰𐍄𐌰 𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹",
        "viewsource-title": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐌱𐍂𐌿𐌽𐌽𐌰𐌽 𐍆𐌰𐌿𐍂 $1",
        "protectedpagetext": "𐍃𐌰 𐌻𐌰𐌿𐍆𐍃 𐌷𐌰𐌱𐌰𐌹𐌸 𐌼𐌿𐌽𐌳, 𐌴𐌹 𐌽𐌹 𐍅𐌰𐌹𐍂𐌸𐌴𐌹𐌽𐌰 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌸𐌰𐌿 𐌰𐌽𐌸𐌰𐍂𐍉𐍃 𐍅𐌰𐌹𐌷𐍄𐍃 𐌹𐌽 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰",
        "viewsourcetext": "𐌼𐌰𐌲𐍄 𐌱𐌰𐌽𐌳𐍅𐌾𐌰𐌽 𐌾𐌰𐌷 𐌺𐌰𐌿𐍀𐌾𐌰 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌸𐌹𐍃 𐌻𐌰𐌿𐌱𐌹𐍃.",
+       "viewyourtext": "𐌼𐌰𐌲𐍄 𐍃𐌰𐌹𐍈𐌰𐌽 𐌾𐌰𐌷 𐌲𐌰𐌻𐌴𐌹𐌺𐍉𐌽 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 <strong>𐌸𐌴𐌹𐌽𐌰𐌹𐌶𐍉 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉</strong> 𐌳𐌿 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰.",
+       "namespaceprotected": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐌳𐌿 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐌻𐌰𐌿𐌱𐌰𐌽𐍃 𐌹𐌽 <strong>$1</strong> 𐌽𐌰𐌼𐌰𐍂𐌿𐌼𐌰.",
        "mycustomcssprotected": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐌳𐌿 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 CSS 𐌻𐌰𐌿𐍆.",
        "mycustomjsonprotected": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐌳𐌿 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 JSON 𐌻𐌰𐌿𐍆.",
        "mycustomjsprotected": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐌳𐌿 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 JavaScript 𐌻𐌰𐌿𐍆.",
        "ns-specialprotected": "𐌿𐍃𐍃𐌹𐌽𐌳𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃 𐌽𐌹 𐌼𐌰𐌲𐌿𐌽 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌰.",
        "titleprotected": "𐌸𐌰𐍄𐌰 𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹 𐌼𐌿𐌽𐌸 𐌷𐌰𐌱𐌰𐌹𐌸 𐍆𐍂𐌰𐌼 𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐌰 𐍆𐍂𐌰𐌼 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳 [[User:$1|$1]].\n𐌲𐌹𐌱𐌰𐌽𐌰 𐍆𐌰𐌹𐍂𐌹𐌽𐌰 𐌹𐍃𐍄 <em>$2</em>.",
+       "exception-nologin-text": "𐌱𐌹𐌳𐌾𐌰𐌼 𐌸𐌿𐌺, 𐌰𐍄𐌲𐌰𐌲𐌲 𐌳𐌿 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽 𐌹𐌽 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆 𐌸𐌰𐌿 𐌸𐍉 𐍄𐌰𐌿𐌹.",
        "cannotlogoutnow-title": "𐌰𐍆𐌻𐌴𐌹𐌸𐌰𐌽 𐌽𐌿 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄",
        "cannotlogoutnow-text": "𐌸𐌰𐌽 $1 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰 𐌰𐍆𐌻𐌴𐌹𐌸𐌰𐌽 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄.",
        "welcomeuser": "𐍅𐌰𐌹𐌻𐌰 𐌰𐌽𐌳𐌰𐌽𐌴𐌼𐍃, $1!",
        "userlogin-yourpassword": "𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳",
        "userlogin-yourpassword-ph": "𐌼𐌴𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳 𐌸𐌴𐌹𐌽",
        "createacct-yourpassword-ph": "𐌼𐌴𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳",
+       "yourpasswordagain": "𐌼𐌴𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳 𐌰𐍆𐍄𐍂𐌰:",
        "createacct-yourpasswordagain": "𐌲𐌰𐍃𐌹𐌲𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳",
        "createacct-yourpasswordagain-ph": "𐌼𐌴𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳 𐌰𐍆𐍄𐍂𐌰",
        "userlogin-remembermypassword": "𐌲𐌰𐍆𐌰𐍃𐍄 𐌼𐌹𐌺 {{GENDER:𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌽𐌰|𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰}}",
        "userlogin-signwithsecure": "𐌱𐍂𐌿𐌺𐌴𐌹 𐌰𐍂𐌽𐌾𐌰𐌹𐌶𐍉𐍃 𐌲𐌰𐍅𐌹𐍃𐌰𐌹𐍃",
+       "cannotlogin-title": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄",
        "cannotlogin-text": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄.",
        "cannotloginnow-title": "𐌽𐌿 𐌽𐌹 𐌼𐌰𐌲𐍄 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽",
        "cannotloginnow-text": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄 𐌸𐌰𐌽 $1 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰.",
        "createacct-reason-ph": "𐌳𐌿𐍈𐌴 𐌸𐌿 𐍃𐌺𐌰𐍀𐌾𐌹𐍃 𐍂𐌰𐌷𐌽𐌴𐌹𐌽",
        "createacct-submit": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌸𐌴𐌹𐌽𐌰 𐍂𐌰𐌷𐌽𐌴𐌹𐌽",
        "createacct-another-submit": "𐍃𐌺𐌰𐍀𐌴𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽",
+       "createacct-continue-submit": "𐌸𐌰𐌹𐍂𐌷𐍅𐌹𐍃 𐌼𐌹𐌸 𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐌰𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐌰𐌹𐍃",
        "createacct-another-continue-submit": "𐌸𐌰𐌹𐍂𐌷𐍅𐌹𐍃 𐌼𐌹𐌸 𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐌰𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐌰𐌹𐍃",
        "createacct-benefit-heading": "{{SITENAME}} 𐍄𐌰𐍅𐌹𐌸 𐌹𐍃𐍄 𐍆𐍂𐌰𐌼 𐌼𐌰𐌽𐌽𐌰𐌼 𐍃𐍅𐌴 𐌸𐌿𐌺.",
        "createacct-benefit-body1": "{{PLURAL:$1|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃}}",
        "createacct-benefit-body2": "{{PLURAL:$1|𐌻𐌰𐌿𐍆𐍃|𐌻𐌰𐌿𐌱𐍉𐍃}}",
        "badretype": "𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌰 𐌸𐍉𐌴𐌹 𐌸𐌿 𐌲𐌰𐌼𐌴𐌻𐌹𐌳𐌴𐍃 𐌽𐌹 𐌹𐌽𐌲𐌰𐌻𐌴𐌹𐌺𐍉𐌽𐌳.",
        "usernameinprogress": "𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐌹𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐍃 𐌸𐌰𐌼𐌼𐌰 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐌹𐌽 𐌾𐌿 𐍄𐍉𐌾𐌰𐌳𐌰. 𐌱𐌹𐌳𐌾𐌰𐌼 𐌸𐌿𐌺 𐌴𐌹 𐌱𐌹𐌳𐌰𐌹𐍃.",
+       "userexists": "𐌲𐌰𐌼𐌴𐌻𐌹𐌸 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐍉 𐌾𐌿 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰.\n𐌱𐌹𐌳𐌾𐌰𐌼 𐌸𐌿𐌺, 𐍅𐌰𐌻𐌴𐌹 𐌰𐌽𐌸𐌰𐍂 𐌽𐌰𐌼𐍉.",
        "createacct-error": "𐌰𐌹𐍂𐌶𐌴𐌹 𐌹𐌽 𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐌰𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐌰𐌹𐍃",
        "createaccounterror": "𐌼𐌰𐌷𐍄𐍃 𐌽𐌹 𐍅𐌰𐍃 𐌳𐌿 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐍂𐌰𐌷𐌽𐌴𐌹𐌽: $1",
        "nocookiesfornew": "𐌱𐍂𐌿𐌺𐌾𐌰𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐍃 𐌽𐌹 𐌲𐌰𐍃𐌺𐌰𐍀𐌰𐌽𐌰 𐌿𐌽𐍄𐌴 𐍅𐌴𐌹𐍃 𐌽𐌹 𐌼𐌰𐌷𐍄𐌴𐌳𐌿𐌼 𐌱𐍂𐌿𐌽𐌽𐌰𐌽 𐌲𐌰𐍃𐌹𐌲𐌻𐌾𐌰𐌽. 𐍅𐌹𐍃 𐌰𐍂𐌽𐌹𐌱𐌰 𐌸𐌰𐍄𐌴𐌹 𐌸𐌿 𐌰𐌽𐌳𐌻𐌴𐍄𐌹𐍃 𐌺𐍉𐌺𐍉𐍃, 𐌰𐍆𐍄𐍂𐌰𐌰𐌽𐌰𐌽𐌹𐌿𐌴𐌹 𐌻𐌰𐌿𐍆 𐌾𐌰𐌷 𐍃𐍉𐌺𐌴𐌹 𐌰𐍆𐍄𐍂𐌰.",
        "nosuchuser": "𐌽𐌹𐍃𐍄 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐍃 𐌼𐌹𐌸 𐌽𐌰𐌼𐌹𐌽 \"$1\".\n𐌽𐌰𐌼𐌽𐌰 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌴 𐌼𐌰𐌲𐌿𐌽 𐌷𐌰𐌱𐌰𐌽 𐌷𐌰𐌿𐌱𐌹𐌳𐌹𐍃 𐌱𐍉𐌺𐍉𐍃.\n𐍃𐌰𐌹𐍈 𐌰𐍆𐍄𐍂𐌰 𐌸𐌴𐌹𐌽𐌰 𐌼𐌴𐌻𐌴𐌹𐌽𐍃, 𐌸𐌰𐌿 [[Special:CreateAccount|𐍃𐌺𐌰𐍀𐌴𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽]].",
        "nouserspecified": "𐍃𐌺𐌰𐌻𐍄 𐌲𐌹𐌱𐌰𐌽 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐍉.",
+       "passwordtooshort": "𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌰 𐍃𐌺𐌿𐌻𐌿𐌽 𐌼𐌰𐌹𐍃 𐌸𐌰𐌿 {{PLURAL:$1|•𐌰• 𐌱𐍉𐌺𐌰|$1 𐌱𐍉𐌺𐍉𐍃}} 𐍅𐌹𐍃𐌰𐌽.",
+       "passwordtoolong": "𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌰 𐌽𐌹 𐌼𐌰𐌲𐌿𐌽 𐍅𐌹𐍃𐌰𐌽 𐌻𐌰𐌲𐌲𐌹𐌶𐍉𐌽𐌰 𐌸𐌰𐌿 {{PLURAL:$1|•𐌰• 𐌱𐍉𐌺𐌰|$1 𐌱𐍉𐌺𐍉𐍃}}.",
        "password-login-forbidden": "𐌱𐍂𐌿𐌺𐌴𐌹𐌽𐍃 𐌸𐌹𐍃 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐌹𐌽𐍃 𐌾𐌰𐌷 𐌸𐌹𐍃 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌹𐍃 𐍆𐌰𐌿𐍂𐌱𐌹𐌿𐌳𐌰𐌽𐌰 𐌹𐍃𐍄.",
        "mailmypassword": "𐌰𐍆𐍄𐍂𐌰 𐍃𐌰𐍄𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳",
+       "noemailcreate": "𐍃𐌺𐌰𐌻𐍄 𐍂𐌰𐌹𐌷𐍄𐍉𐍃 𐌴-𐌱𐍉𐌺𐍉𐍃 𐌲𐌹𐌱𐌰𐌽.",
        "emailconfirmlink": "𐌲𐌰𐍃𐌹𐌲𐌻𐌴𐌹 𐌸𐌴𐌹𐌽𐍉𐍃 𐌴-𐌱𐍉𐌺𐍉𐍃",
        "emaildisabled": "𐍃𐌰 𐌽𐌰𐍄𐌾𐌰𐍃𐍄𐌰𐌸𐍃 𐌽𐌹 𐌼𐌰𐌲 𐍃𐌰𐌽𐌳𐌾𐌰𐌽 𐌴-𐌱𐍉𐌺𐍉𐍃.",
        "accountcreatedtext": "𐌱𐍂𐌿𐌺𐌾𐌰𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐍃 [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌹]]) 𐌲𐌰𐍃𐌺𐌰𐍀𐌰𐌽𐌰 𐌹𐍃𐍄.",
index 3b91696..8e925ca 100644 (file)
        "monthsall": "הכול",
        "confirmemail": "אימות כתובת דוא\"ל",
        "confirmemail_noemail": "אין לך כתובת דוא\"ל תקפה המוגדרת ב[[Special:Preferences|העדפות המשתמש]] שלך.",
-       "confirmemail_text": "×\99ש ×\9c×\90×\9eת ×\90ת ×\9bת×\95×\91ת ×\94×\93×\95×\90\"×\9c ×\9b×\93×\99 ×©× ×\99ת×\9f ×\99×\94×\99×\94 להשתמש בשירותי הדוא\"ל של {{SITENAME}}.\nכדי לשלוח קוד אימות לכתובת הדוא\"ל שהזנת, יש ללחוץ על הכפתור שלמטה.\nהודעת הדוא\"ל שתישלח תכלול קישור שמכיל קוד;\nיש לפתוח את הקישור בדפדפן כדי לאשר שכתובת הדוא\"ל תקפה.",
+       "confirmemail_text": "×\97×\95×\91×\94 ×\9c×\90×\9eת ×\90ת ×\9bת×\95×\91ת ×\94×\93×\95×\90\"×\9c ×\9b×\93×\99 להשתמש בשירותי הדוא\"ל של {{SITENAME}}.\nכדי לשלוח קוד אימות לכתובת הדוא\"ל שהזנת, יש ללחוץ על הכפתור שלמטה.\nהודעת הדוא\"ל שתישלח תכלול קישור שמכיל קוד;\nיש לפתוח את הקישור בדפדפן כדי לאשר שכתובת הדוא\"ל תקפה.",
        "confirmemail_pending": "קוד האימות כבר נשלח לדואר האלקטרוני שלך;\nאם יצרת את החשבון לאחרונה, כדאי להמתין מספר דקות עד שהדוא\"ל יגיע לפני בקשת קוד חדש.",
        "confirmemail_send": "שליחת קוד אימות",
        "confirmemail_sent": "הדוא\"ל עם קוד האימות נשלח.",
        "confirm-unwatch-button": "אישור",
        "confirm-unwatch-top": "להסיר את הדף הזה מרשימת המעקב שלך?",
        "confirm-rollback-button": "אישור",
-       "confirm-rollback-top": "×\9cש×\97×\96×\95ר ×\90ת ×\94ש×\99× ×\95×\99×\99×\9d ×\9c×\93×£ ×\94×\96×\94?",
+       "confirm-rollback-top": "לשחזר את השינויים לדף הזה?",
        "quotation-marks": "\"$1\"",
        "imgmultipageprev": "→ לדף הקודם",
        "imgmultipagenext": "לדף הבא ←",
        "size-exapixel": "{{PLURAL:$1|אקסה־פיקסל אחד|$1 אקסה־פיקסלים}}",
        "size-zetapixel": "{{PLURAL:$1|זטה־פיקסל אחד|$1 זטה־פיקסלים}}",
        "size-yottapixel": "{{PLURAL:$1|יוטה־פיקסל אחד|$1 יוטה־פיקסלים}}",
+       "bitrate-bits": "{{PLURAL:$1|ביט אחד|$1 ביטים}} בשנייה",
+       "bitrate-kilobits": "{{PLURAL:$1|קילו־ביט אחד|$1 קילו־ביטים}} בשנייה",
+       "bitrate-megabits": "{{PLURAL:$1|מגה־ביט אחד|$1 מגה־ביטים}} בשנייה",
+       "bitrate-gigabits": "{{PLURAL:$1|ג'יגה־ביט אחד|$1 ג'יגה־ביטים}} בשנייה",
+       "bitrate-terabits": "{{PLURAL:$1|טרה־ביט אחד|$1 טרה־ביטים}} בשנייה",
+       "bitrate-petabits": "{{PLURAL:$1|פטה־ביט אחד|$1 פטה־ביטים}} בשנייה",
+       "bitrate-exabits": "{{PLURAL:$1|אקסה־ביט אחד|$1 אקסה־ביטים}} בשנייה",
+       "bitrate-zetabits": "{{PLURAL:$1|זטה־ביט אחד|$1 זטה־ביטים}} בשנייה",
+       "bitrate-yottabits": "{{PLURAL:$1|יוטה־ביט אחד|$1 יוטה־ביטים}} בשנייה",
        "lag-warn-normal": "שינויים שבוצעו לפני פחות מ{{PLURAL:$1|שנייה אחת|־$1 שניות}} אינם מוצגים ברשימה זו.",
        "lag-warn-high": "בגלל עיכוב בעדכון בסיס הנתונים, שינויים שבוצעו לפני פחות מ{{PLURAL:$1|שנייה אחת|־$1 שניות}} אינם מוצגים ברשימה זו.",
        "watchlistedit-normal-title": "עריכת רשימת המעקב",
        "watchlistedit-normal-done": "{{PLURAL:$1|כותרת אחת הוסרה|$1 כותרות הוסרו}} מרשימת המעקב:",
        "watchlistedit-raw-title": "עריכת הרשימה הגולמית",
        "watchlistedit-raw-legend": "עריכת הרשימה הגולמית",
-       "watchlistedit-raw-explain": "×\94×\93פ×\99×\9d ×\91רש×\99×\9eת ×\94×\9eעק×\91 ×\9e×\95צ×\92×\99×\9d ×\9c×\94×\9c×\9f, ×\95× ×\99ת×\9f ×\9cער×\95×\9a ×\90×\95ת×\9d ×\91×\90×\9eצע×\95ת ×\94×\95ספ×\94 ×\95×\94סר×\94 ×©×\9c×\94×\9d ×\9e×\94רש×\99×\9e×\94;\n×\9b×\9c ×\9b×\95תרת ×\9e×\95פ×\99×¢×\94 ×\91ש×\95ר×\94 × ×¤×¨×\93ת.\n×\9c×\90×\97ר ×¡×\99×\95×\9d ×\94ער×\99×\9b×\94, ×\99ש ×\9c×\9c×\97×\95×¥ ×¢×\9c \"{{int:Watchlistedit-raw-submit}}\".\n×\91×\90פשר×\95ת×\9b×\9d גם [[Special:EditWatchlist|להשתמש בעורך הרגיל]].",
+       "watchlistedit-raw-explain": "×\94×\93פ×\99×\9d ×\91רש×\99×\9eת ×\94×\9eעק×\91 ×\9e×\95צ×\92×\99×\9d ×\9c×\94×\9c×\9f, ×\95× ×\99ת×\9f ×\9cער×\95×\9a ×\90×\95ת×\9d ×\91×\90×\9eצע×\95ת ×\94×\95ספ×\94 ×©×\9c×\94×\9d ×\9cרש×\99×\9e×\94 ×\95×\94סרת×\9d ×\9e×\9e× ×\94;\n×\9b×\9c ×\9b×\95תרת ×\9e×\95פ×\99×¢×\94 ×\91ש×\95ר×\94 × ×¤×¨×\93ת.\n×\9c×\90×\97ר ×¡×\99×\95×\9d ×\94ער×\99×\9b×\94, ×\99ש ×\9c×\9c×\97×\95×¥ ×¢×\9c \"{{int:Watchlistedit-raw-submit}}\".\n×\91×\90פשר×\95ת×\9a גם [[Special:EditWatchlist|להשתמש בעורך הרגיל]].",
        "watchlistedit-raw-titles": "דפים:",
        "watchlistedit-raw-submit": "עדכון רשימת המעקב",
        "watchlistedit-raw-done": "רשימת המעקב עודכנה.",
index 864b3d8..370d9a4 100644 (file)
        "privacypage": "Project:КъайлагIара хIамай политика",
        "badaccess": "ТIакхоачилга гӀалат",
        "badaccess-group0": "Оаш дIадийха хинна ардам кхоачашде йиш яц шун.",
-       "badaccess-groups": "ДIадийха ардам кхоачашде могаш ба алхха доакъашхой {{PLURAL:$2|1=тоабан «$1»|укх тоабаш чура: $1}}",
+       "badaccess-groups": "ДӀадийхар кхоачашде йиш йолаш ба алхха {{PLURAL:$2|1=«$1»|$1}}.",
        "versionrequired": "Эшаш я $1 версех йола MediaWiki",
        "versionrequiredtext": "Укх оагIонца болх бергболаш $1 версех йола MediaWiki эша. Хьажа [[Special:Version|програмни Iалашдарах бола хоамага]].",
        "ok": "Мег",
        "template-protected": "(лорадаь да)",
        "template-semiprotected": "(цхьа долча даькъе гIо оттадаь да)",
        "hiddencategories": "Ер оагIув {{PLURAL:$1|$1 къайла категориех|1=цаI къайла категорех}} я:",
-       "permissionserrors": "ТÓ\80акÑ\85оаÑ\87илга Ð±Ð¾ÐºÑ\8aоний гӀалат",
-       "permissionserrorstext-withaction": "Ер $2 де Хьа бокъо яц {{PLURAL:$1|1=из бахьан долаш|из бахьанаш долаш}}:",
+       "permissionserrors": "ТÓ\80акÑ\85аÑ\87аÑ\80а Ð±Ð¾ÐºÑ\8aонаÑ\88Ñ\86аÑ\80а гӀалат",
+       "permissionserrorstext-withaction": "$2 шун бокъо яц {{PLURAL:$1|1=укх бахьан}}:",
        "recreate-moveddeleted-warn": "'''Теркам бе. Хьо юхакхолла гӀерта хьалха дIаяьккха хинна оагӀув.'''\n\nДIатахка, боккъонца эший хьона из оагIув юхакхолла.\nКӀалхагIа хьекха да укх оагӀон дӀадаккхари цӀи хувцари тептараш.",
        "moveddeleted-notice": "Ер оагӀув дӀаяьккха хиннай.\nШоана новкъостала кӀалха хьахьекха да укх оагIонца дувзаденна тептараш.",
        "log-fulllog": "БIаргтоха таптарага бIарчча",
        "rcfilters-filter-minor-description": "Авторо зIамига да аьнна белгалдаь тоадаьраш.",
        "rcfilters-filter-major-label": "ЛерттIа хувцамаш",
        "rcfilters-filter-major-description": "Авторо зIамига да аьнна белгалдаьдоаца тоадаьраш.",
+       "rcfilters-filtergroup-watchlist": "Зема хьаязяьра чура оагӀонаш",
+       "rcfilters-filter-watchlist-watched-label": "Зема хьаязяьра чу",
+       "rcfilters-filter-watchlist-watched-description": "Хьа зема хьаязяьра чура оагӀонашта даь хувцамаш",
+       "rcfilters-filter-watchlist-watchednew-label": "Керда хувцамаш зема хьаязяьра чу",
+       "rcfilters-filter-watchlist-watchednew-description": "Хьа зема хьаязяьра чура оагӀонаш тӀа даь хьона хӀанзехьа бӀаргадайна доаца хувцамаш",
+       "rcfilters-filter-watchlist-notwatched-label": "Яц зема хьаязяьра чу",
+       "rcfilters-filter-watchlist-notwatched-description": "Ерригаш, Iа зем беш йола оагIонаш юкъерайоахаш.",
        "rcfilters-filtergroup-changetype": "Хувцама тайпа",
        "rcfilters-filter-pageedits-label": "ОагӀона тоадаьраш",
        "rcfilters-filter-pageedits-description": "Чулоацами, дувцара оагIонаши, оагIаташи тоаяр",
        "rcfilters-filter-lastrevision-description": "ОагIон тIа алхха тIехьара хинна хувцам.",
        "rcfilters-filter-previousrevision-label": "ТIехьара йоаца эрш",
        "rcfilters-filter-previousrevision-description": "«ТӀехьара эрш» мел доаца тоадаьраш.",
+       "rcfilters-view-tags": "Фосташ",
        "rcfilters-liveupdates-button": "Ши-шегIа кердадувлийта",
        "rcfilters-liveupdates-button-title-on": "ДIадоаде ши-шегIа кердадалар",
        "rcfilters-liveupdates-button-title-off": "Керда хувцам бешше хьахьокха",
        "unwatchedpages": "Цхьанне а зем беш йоаца оагIонаш",
        "randompage": "Цаховш нийсъенна статья",
        "statistics": "ГӀулакх-хьал",
+       "statistics-header-pages": "ОагӀонашца дола гӀулакх-хьал",
+       "statistics-header-edits": "Тоадара гӀулакх-хьал",
+       "statistics-header-users": "Доакъашхошца дола гӀулакх-хьал",
+       "statistics-header-hooks": "Кхыдолчунца дола гӀулакх-хьал",
        "statistics-articles": "Статьяш",
        "statistics-pages": "ОагIонаш",
+       "statistics-pages-desc": "Вике чу мел йола оагӀонаш, дувцара оагӀонаши юхаластараши кхыйола оагӀонаши юкъелоацаш.",
+       "statistics-files": "ДIачуяьха файлаш",
+       "statistics-edits": "{{grammar:genitive|{{SITENAME}}}} дӀаоттаяьча денз даь хувцамаш",
+       "statistics-edits-average": "Цхьан оагӀона деш долча тоадара юкъера дукхал",
        "statistics-users": "Ражача дӏаийтта доакъашхой",
        "statistics-users-active": "Хьинаре доакъашхой",
+       "statistics-users-active-desc": "Доакъашхой, {{PLURAL:$1|тӀехьарча $1 дийнахь}} цхьа моллагӀа хувцам баь бола.",
        "double-redirect-fixer": "ДӀа-хьа хьожавара оагIонаш тоаер",
        "brokenredirects-edit": "нийсъе",
        "brokenredirects-delete": "дӀаяккха",
        "importlogpage": "Импорта тептар",
        "tooltip-pt-userpage": "{{GENDER:|Хьа}} доакъашхочун оагIув",
        "tooltip-pt-mytalk": "{{GENDER:|Хьа}} дувца оттадара оагIув",
+       "tooltip-pt-anontalk": "Шун IP-цIайна лаьрхIа дувцара оагӀув",
        "tooltip-pt-preferences": "{{GENDER:|Хьа оттамаш}}",
        "tooltip-pt-watchlist": "Iа зем бу оагIонаш",
        "tooltip-pt-mycontris": "{{GENDER:|Хьа}} хувцамаш",
+       "tooltip-pt-anoncontribs": "Укх IP-цIайна тIара даь хувцамаш",
        "tooltip-pt-login": "Укхаза ражача чу а даьнна регистраци е йиш я.",
        "tooltip-pt-logout": "Аравала/яла",
-       "tooltip-pt-createaccount": "Ð¥Ñ\8cа Ð±Ð¾ÐºÑ\8aо Ñ\8f Ð´Ð°Ð³Ð°Ñ\80а Ð¹Ð¾Ð°Ð·Ñ\83в Ñ\85Ñ\8cа Ð° ÐºÑ\85елла Ñ\80ажаÑ\87а Ñ\87Ñ\83вала.",
+       "tooltip-pt-createaccount": "ШÑ\83н Ð±Ð¾ÐºÑ\8aо Ñ\8f Ð´Ð°Ð³Ð°Ñ\80а Ð¹Ð¾Ð°Ð·Ñ\83в Ñ\85Ñ\8cа Ð° ÐºÑ\85елла Ñ\80ажаÑ\87а Ñ\87Ñ\83довла.",
        "tooltip-ca-talk": "ОагIон чулоацамах лаьца дувцар",
        "tooltip-ca-edit": "Нийсъе ер оагIув",
        "tooltip-ca-addsection": "Керда дáкъа хьаде",
        "exif-iimcategory-wea": "Хаоттам",
        "namespacesall": "деррига",
        "monthsall": "деррига",
+       "confirm-purge-title": "Укх оагIон кэш ӀоцIенъе",
        "confirm_purge_button": "Мега",
+       "confirm-purge-top": "Укх оагӀон кэш ӀоцIенъйой?",
+       "confirm-purge-bottom": "Кэш ӀоцӀенъячул тӀехьагIа оагIон тӀехьара эрш хьахьокхаргья.",
        "imgmultipagenext": "тӀехьайоагӀа оагӀув →",
        "imgmultigo": "Дехьавала!",
        "imgmultigoto": "$1 оагIон тIа дехьавала",
index 657a370..5b501c8 100644 (file)
@@ -15,7 +15,8 @@
                        "Soul Train",
                        "Умар",
                        "아라",
-                       "Amire80"
+                       "Amire80",
+                       "Stjn"
                ]
        },
        "tog-underline": "ЭлячӀунрин кӀаникай цӀар чӀугун",
index 8532d20..5176eaf 100644 (file)
        "grant-generic": "\"$1\" tiesību paka",
        "grant-group-page-interaction": "Darboties ar lapām",
        "grant-group-file-interaction": "Darboties ar multimediju failiem",
+       "grant-group-watchlist-interaction": "Darboties ar tavu uzraugāmo lapu sarakstu",
        "grant-group-email": "Sūtīt e-pastu",
        "grant-group-high-volume": "Veikt liela apjoma aktivitātes",
        "grant-group-administration": "Veikt administratīvās darbības",
        "grant-group-private-information": "Piekļūt privātiem datiem par tevi",
+       "grant-group-other": "Dažādas darbības",
        "grant-blockusers": "Bloķēt un atbloķēt dalībniekus",
        "grant-createaccount": "Izveidot kontu",
        "grant-createeditmovepage": "Izveidot, labot un pārvietot lapas",
        "grant-uploadfile": "Augšupielādēt jaunus failus",
        "grant-basic": "Pamattiesības",
        "grant-viewdeleted": "Skatīt dzēstos failus un lapas",
+       "grant-viewmywatchlist": "Skatīt tavu uzraugāmo rakstu sarakstu",
        "newuserlogpage": "Jauno dalībnieku reģistrs",
        "newuserlogpagetext": "Jauno lietotājvārdu reģistrs.",
        "rightslog": "Dalībnieku tiesību reģistrs",
index 31a530a..d6033e1 100644 (file)
        "userlogin-yourname": "Username",
        "userlogin-yourname-ph": "Enter your username",
        "userlogin-yourpassword": "ꯆꯪꯁꯤꯟꯅꯕꯥ ꯋꯥꯍꯩ",
+       "createacct-yourpassword-ph": "ꯄꯥꯁꯋ꯭ꯇ ꯏꯔꯛ ꯎ",
+       "createacct-yourpasswordagain": "Confirm password",
+       "createacct-yourpasswordagain-ph": "ꯑꯃꯨꯛ ꯍꯟꯅꯥ ꯄꯥꯁꯋ꯭ꯇ ꯏꯌꯨ",
        "login": "Chang Sinba",
        "createaccount": "ꯑꯩꯒꯤ ꯑꯣꯏꯕꯥ ꯑꯃꯥ ꯁꯦꯝꯕꯥ",
+       "createacct-emailoptional": "Email address (ꯑꯇꯣꯞꯄꯥ ꯱)",
+       "createacct-email-ph": "Enter your email address",
+       "createacct-submit": "ꯅꯪꯒꯤ ꯑꯦꯀꯥꯎꯟꯇ ꯁꯦꯝꯕꯥ",
+       "createacct-benefit-heading": "{{SITENAME}} ꯁꯤ ꯅꯪꯒꯥ ꯃꯥꯟꯅꯕꯥ ꯃꯤꯑꯣꯏꯁꯤꯡꯅꯥ ꯁꯦꯝꯕꯅꯤ",
+       "createacct-benefit-body1": "{{PLURAL:$1|edit|edits}}",
+       "createacct-benefit-body2": "{{PLURAL:$1|page|pages}}",
+       "createacct-benefit-body3": "ꯍꯧꯖꯤꯛꯀꯤ {{PLURAL:$1|contributor|contributors}}",
        "loginlanguagelabel": "$1 ꯂꯣꯟ",
        "pt-login": "Chang Sinba",
        "pt-createaccount": "ꯑꯩꯒꯤ ꯑꯣꯏꯕꯥ ꯑꯃꯥ ꯁꯦꯝꯕꯥ",
        "cur": "ꯍꯧ",
        "last": "ꯃꯥꯃꯥꯡꯒꯤ",
        "rev-delundel": "ꯑꯍꯣꯡꯕꯥ ꯎꯍꯟꯂꯤꯕꯥ",
+       "difference-title": "$1 ꯒꯤ ꯑꯃꯨꯛꯍꯟꯕꯥ ꯈꯦꯠꯅꯕꯥꯒꯤ ꯃꯔꯛ",
        "lineno": "ꯂꯥ ꯏ $1",
        "editundo": "ꯇꯧꯒꯅꯨ",
+       "diff-multi-sameuser": "({{PLURAL:$1|One intermediate revision|$1 intermediate revisions}} by the same user not shown)",
        "searchresults": "ꯊꯤꯕꯒꯤ ꯐꯣꯜ",
        "searchresults-title": "Search results for \"$1\"",
        "prevn": "ꯍꯥꯟꯅꯒꯤ {{PLURAL:$1|$1}}",
        "contributions": "{{GENDER:$1|User}} ꯈꯣꯝꯒꯠꯂꯛꯄꯁꯤꯡ",
        "mycontris": "ꯈꯣꯝꯒꯠꯂꯛꯂꯤꯕꯁꯤꯡ",
        "anoncontribs": "ꯈꯣꯝꯒꯠꯂꯛꯂꯤꯕꯁꯤꯡ",
+       "month": "ꯃꯗꯨꯒꯤ ꯊꯥꯗꯒꯤ (ꯑꯃꯗꯤ ꯅꯧꯔꯤꯕꯥ)",
+       "year": "ꯃꯗꯨꯒꯤ ꯆꯥꯍꯤꯗꯒꯤ (ꯑꯃꯗꯤ ꯅꯧꯔꯤꯕꯥ)",
        "whatlinkshere": "ꯃꯁꯤꯗꯥ ꯀꯔꯤ ꯁꯝꯃꯤ",
        "whatlinkshere-title": "$1 ꯒꯥ ꯃꯔꯤ ꯂꯩꯅꯕꯥ ꯁꯝꯅꯐꯝ",
        "whatlinkshere-page": "ꯂꯥꯃꯥꯏ",
        "whatlinkshere-filters": "ꯁꯦꯡꯇꯣꯛꯐꯝ",
        "blocklink": "Thingba",
        "contribslink": "ꯐꯪꯉꯛꯄꯥ",
+       "movelogpage": "ꯂꯣꯒ ꯁꯤ ꯂꯦꯡꯍꯟꯂꯨ",
        "export": "ꯂꯥꯃꯥꯏꯁꯤꯡ ꯄꯨꯊꯣꯛꯈꯣ",
        "thumbnail-more": "ꯆꯥꯑꯣꯍꯟꯕꯥ",
        "tooltip-pt-userpage": "{{GENDER:|Your user}} ꯂꯥꯃꯥꯏ",
        "tooltip-ca-addsection": "Anouba khaidokpadu houro",
        "tooltip-ca-viewsource": "ꯃꯁꯤꯒꯤ ꯂꯥꯃꯥꯏꯁꯤ ꯉꯥꯛꯊꯣꯛꯂꯦ \nꯅꯪꯅꯥ ꯂꯥꯃꯥꯏꯁꯤꯒꯤ ꯍꯧꯔꯛꯐꯝ ꯎꯒꯅꯤ",
        "tooltip-ca-history": "ꯍꯧꯈꯔꯕꯥ ꯂꯥꯃꯥꯏ ꯑꯃꯨꯛ ꯍꯟꯅꯥ ꯌꯦꯡꯕꯥ",
+       "tooltip-ca-move": "ꯃꯁꯤꯒꯤ ꯂꯥꯃꯥꯏꯁꯤ ꯂꯦꯡꯍꯟꯂꯨ",
        "tooltip-ca-watch": "ꯅꯪꯒꯤ ꯌꯦꯡꯅꯕꯥ ꯄꯥꯔꯦꯡꯗꯨꯗꯥ ꯍꯥꯞꯆꯏꯟꯂꯨ ꯃꯁꯤꯒꯤ ꯂꯥꯃꯥꯏꯁꯤ",
        "tooltip-search": "ꯊꯤꯔꯣ ꯃꯐꯝꯗꯨꯒꯤ ꯃꯃꯤꯡ",
        "tooltip-search-go": "Leiraga Chatlu madugi chapchaba Lamai Duda",
index f7cd82c..c3fc175 100644 (file)
        "userrights-editusergroup": "{{GENDER:$1|အသုံးပြုသူ}}အုပ်စုများကို တည်းဖြတ်ရန်",
        "saveusergroups": "{{GENDER:$1|အသုံးပြုသူ}}အုပ်စုများကို သိမ်းရန်",
        "userrights-groupsmember": "အဖွဲ့ဝင်",
+       "userrights-groups-help": "ဤအသုံးပြုသူ၏ အုပ်စုများကို အောက်ပါအတိုင်း သင်ပြောင်းလဲနိုင်သည်\n* အမှန်ခြစ်အကွက်သည် ထိုအသုံးပြုသူသည် ယင်းအုပ်စုတွင် ပါဝင်ကြောင်း ဆိုလိုသည်။\n* အမှန်ခြစ်မပါသော အကွက်သည် ထိုအသုံးပြုသူသည် ယင်းအုပ်စုတွင် မပါဝင်ကြောင်း ဆိုလိုသည်။\n* ခရေပွင့် * အမှတ်အသားသည် အုပ်စုတစ်ခုအတွင်းသို့ ထည့်သွင်းပြီးပါက ပြန်လည် ဖယ်ရှားမရနိုင်ကြောင်း (အပြန်အလှန်) ကို ဆိုလိုသည်။\n* သင်္ကေတ # အမှတ်အသားသည် ဤအုပ်စုအဖွဲ့ဝင် သက်တမ်းကို ပြန်လည်ထည့်သွင်းနိုင်ပြီး ရှေ့တိုးပေးရန် မဖြစ်နိုင်ကြောင်း ဖော်ပြသည်။",
        "userrights-reason": "အ​ကြောင်း​ပြ​ချက်:",
        "userrights-changeable-col": "သင်ပြောင်းလဲပေးနိုင်သောအုပ်စုများ",
        "userrights-unchangeable-col": "သင်ပြောင်းလဲမပေးနိုင်သောအုပ်စုများ",
+       "userrights-expiry-none": "သက်တမ်းကုန်ဆုံးခြင်း မရှိ",
        "group": "အုပ်စု -",
        "group-user": "အသုံးပြုသူများ",
        "group-autoconfirmed": "အလိုအလျောက် အတည်ပြုထားသော အသုံးပြုသူများ",
        "logentry-newusers-autocreate": "အသုံးပြုသူအကောင့် $1 ကို အလိုအလျောက် {{GENDER:$2|ဖန်တီးခဲ့သည်}}",
        "logentry-protect-protect": "$1 က  $3 ကို {{GENDER:$2|ကာကွယ်ခဲ့သည်}} $4",
        "logentry-protect-modify": "$3 အတွက် ကာကွယ်မှုအဆင့်ကို $1 {{GENDER:$2|က ပြောင်းလဲခဲ့သည်}} $4",
+       "logentry-rights-rights": "{{GENDER:$6|$3}} အတွက် အုပ်စုအဖွဲ့ဝင် $4 မှ $5 သို့ $1 က {{GENDER:$2|ပြောင်းလဲခဲ့သည်}}",
        "logentry-upload-upload": "$1 သည် $3 ကို {{GENDER:$2|upload တင်ခဲ့သည်}}",
        "logentry-upload-overwrite": "$3 ၏ ဗားရှင်းအသစ်ကို $1 {{GENDER:$2|upload တင်ခဲ့သည်}}",
        "rightsnone": "(ဘာမှမရှိ)",
index 3dba87c..55cdb15 100644 (file)
        "backend-fail-usable": "Nun se può lieggere o scrivere 'o file \"$1\" pecché mancano 'e permesse sufficiente o nun esiste 'a cartella/cuntenitore.",
        "filejournal-fail-dbconnect": "Nun se può fà connessione a l'archivio d' 'o database pe' puté astipà archivie 'n rezza \"$1\".",
        "filejournal-fail-dbquery": "Nun se può agghiurnà l'archivio d' 'o database pe' puté astipà l'archivie 'n rezza \"$1\".",
-       "lockmanager-notlocked": "Nun se può sbloccà \"$1\"; nun è bluccato.",
+       "lockmanager-notlocked": "Nun se può sbloccà \"$1\"; nun sta bluccato.",
        "lockmanager-fail-closelock": "Nun se può nchiure 'o file 'e blocco pe' \"$1\".",
        "lockmanager-fail-deletelock": "Nun se può scancellà 'o file 'e blocco pe' \"$1\".",
        "lockmanager-fail-acquirelock": "Nun se può piglià 'o blocco pe' \"$1\".",
        "sorbsreason": "L'indirizzo IP vuosto è elencato comm'a nu proxy araputo dint' 'a lista DNSBL ausata 'a {{SITENAME}}.",
        "sorbs_create_account_reason": "L'indirizzo IP d' 'o vuosto è elencato comm'a nu proxy araputo dint' 'a DNSBL ausata 'a {{SITENAME}}. Nun putite crià nu cunto.",
        "xffblockreason": "N'indirizzo IP prisente dint' 'e cap'e paggena X-Forwarded-For, o chillu d' 'o vuosto o chillu 'e n'atu server proxy ca stat'ausann, è stato bloccato. 'O mutivo origgenale 'e blocco era: $1",
-       "cant-see-hidden-user": "L'utente ca state a bluccà è stato già bluccato e annascunnuto. Si nun tenite 'o deritto ''hideuser'', nun putite veré stu blocco d'utente.",
+       "cant-see-hidden-user": "L'utente ca state fremmanno he sito bluccato e annascunnuto già. Si nun tenite 'o deritto ''hideuser'', nun putite veré stu blocco utente.",
        "ipbblocked": "Nun putite bloccà o sbluccà utente pecche vuje stesso site bluccato.",
        "ipbnounblockself": "Nun avite permesso a ve bluccà vuje stesso.",
        "lockdb": "Nzerra 'o database",
        "lockdbsuccesstext": "'O database è stato bloccato.<br />\nArricuordateve 'e [[Special:UnlockDB|luvà 'o blocco]] appriesso c' 'a manutenziona sarrà fernuta.",
        "unlockdbsuccesstext": "'O database è stato sbluccato.",
        "lockfilenotwritable": "Nun se può scrivere ncopp' 'o file 'e blocco d' 'o database.\nPe' bluccà o sbluccà 'o database abbesuogne 'e scrivere dint' 'o server web.",
-       "databaselocked": "'O database è bluccato già.",
-       "databasenotlocked": "'O database nun è bluccato.",
+       "databaselocked": "'O database sta stutato già.",
+       "databasenotlocked": "'O database nun sta stutato.",
        "lockedbyandtime": "(pe' {{GENDER:$1|$1}} 'o $2 a 'e $3)",
        "move-page": "Mòve $1",
        "move-page-legend": "Mòve paggena",
        "tags-deactivate": "stuta",
        "tags-hitcount": "$1 {{PLURAL:$1|cagnamiento|cagnamiente}}",
        "tags-manage-no-permission": "Nun tenite 'o permesso pe' cagnà 'e tag.",
-       "tags-manage-blocked": "Nun putite cagnà sti tag quanno site bluccato/a.",
+       "tags-manage-blocked": "Nun putite cagnà sti tag quanno state {{GENDER:$1|fremmato|freammata}}.",
        "tags-create-heading": "Crìa nu tag nuovo",
        "tags-create-explanation": "Comme predefinito, 'e tag criate nuove nuove se farranno disponibbele pe ll'ausà ll'utente e re bot",
        "tags-create-tag-name": "Nomme 'e ll'etichetta ('o tag):",
        "tags-apply-not-allowed-one": "'O tag \"$1\" nun è premmesso a se ffà manualmente apprecà.",
        "tags-apply-not-allowed-multi": "{{PLURAL:$2|'O tag ccà abbascio nun è|'E tag ccà abbascio nun songo}} premmesse 'e s'apprecà manualmente: $1",
        "tags-update-no-permission": "Nun tenite premmesse pe' putè azzeccà o luvà tag 'e cagnamiento 'a 'e verziune nnividuale o entrate 'o log.",
-       "tags-update-blocked": "Nun putite azzeccà o luvà tag quanno site bluccato/a.",
+       "tags-update-blocked": "Nun putite azzeccà o luvà tag quanno state {{GENDER:$1|bluccato|bluccata}}.",
        "tags-update-add-not-allowed-one": "'O tag \"$1\" nun è premmesso 'e s'azzeccà 'n manuale.",
        "tags-update-add-not-allowed-multi": "{{PLURAL:$2|'O tag ccà abbascio nun è|'E tag ccà abbascio nu so'}} premmesse 'e s'azzeccà manualmente: $1",
        "tags-update-remove-not-allowed-one": "'O tag \"$1\" nun è permesso d' 'o luvà.",
        "revdelete-uname-unhid": "nomme utente fatto avvedè",
        "revdelete-restricted": "restriziune apprecate a ll'ammenistrature",
        "revdelete-unrestricted": "restriziune luvate a ll'ammenistrature",
-       "logentry-block-block": "$1 {{GENDER:$2|ave bluccato}} {{GENDER:$4|$3}} cu na scadenza 'e $5 $6",
+       "logentry-block-block": "$1 {{GENDER:$2|ave fremmato}} {{GENDER:$4|$3}} cu na scadenza 'e $5 $6",
        "logentry-block-unblock": "$1 {{GENDER:$2|ave sbluccato}} {{GENDER:$4|$3}}",
        "logentry-block-reblock": "$1 {{GENDER:$2|ave cagnato}} 'e mpustaziune 'e blocco pe' {{GENDER:$4|$3}} cu na scadenza 'e $5 $6",
-       "logentry-suppress-block": "$1 {{GENDER:$2|ave bluccato}} {{GENDER:$4|$3}} cu na scadenza 'e $5 $6",
+       "logentry-suppress-block": "$1 {{GENDER:$2|ave fremmato}} {{GENDER:$4|$3}} cu na scadenza 'e $5 $6",
        "logentry-suppress-reblock": "$1 {{GENDER:$2|cagnaje}} 'e mpustaziune 'e blocco 'e {{GENDER:$4|$3}} ch' 'ammaturasse a nu $5 $6",
        "logentry-import-upload": "$1 {{GENDER:$2|ave mpurtato}} $3 pe' bbìa d' 'a carreca",
        "logentry-import-upload-details": "$1 {{GENDER:$2|mpurtaje}} $3 pe' carreca 'e file ($4 {{PLURAL:$4|verziona|verziune}})",
index bead019..ea57228 100644 (file)
        "rcfilters-activefilters": "Actieve filters",
        "rcfilters-activefilters-hide": "Verbergen",
        "rcfilters-activefilters-show": "Weergeven",
+       "rcfilters-activefilters-hide-tooltip": "Verberg actieve filters",
+       "rcfilters-activefilters-show-tooltip": "Toon active filters",
        "rcfilters-advancedfilters": "Geavanceerde filters",
        "rcfilters-limit-title": "Resultaten om te tonen",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|wijziging|wijzigingen}}, $2",
index d9b41c5..120b542 100644 (file)
        "converter-manual-rule-error": "Erro detectado na regra de conversão de língua manual",
        "undo-success": "A edição pôde ser desfeita. Por gentileza, verifique o comparativo a seguir para se certificar de que é isto que deseja fazer, salvando as alterações após ter terminado de revisá-las.",
        "undo-failure": "A edição não pôde ser desfeita devido a alterações intermediárias conflitantes.",
+       "undo-main-slot-only": "A edição não pode ser desfeita porque envolve conteúdo fora do espaço principal.",
        "undo-norev": "A edição não pôde ser desfeita porque não existe ou foi apagada.",
        "undo-nochange": "Parece que a edição já foi desfeita.",
        "undo-summary": "Desfeita a edição $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|Discussão]])",
index 2fc8ca4..db51aa6 100644 (file)
@@ -87,7 +87,7 @@
        "tog-hidecategorization": "Ocultar categorização de páginas",
        "tog-extendwatchlist": "Listagem expandida de todas as mudanças às páginas vigiadas, não apenas das mais recentes",
        "tog-usenewrc": "Agrupar alterações por página nas mudanças recentes e páginas vigiadas",
-       "tog-numberheadings": "Auto-numerar cabeçalhos",
+       "tog-numberheadings": "Numerar cabeçalhos automaticamente",
        "tog-showtoolbar": "Mostrar barra de edição",
        "tog-editondblclick": "Editar páginas quando houver um clique duplo",
        "tog-editsectiononrightclick": "Possibilitar a edição de secções por clique com o botão direito no título da secção",
        "protect_change": "alterar",
        "unprotect": "Alterar proteção",
        "newpage": "Página nova",
-       "talkpagelinktext": "Discussão",
+       "talkpagelinktext": "discussão",
        "specialpage": "Página especial",
        "personaltools": "Ferramentas pessoais",
        "talk": "Discussão",
        "viewhelppage": "Ver página de ajuda",
        "categorypage": "Ver página de categoria",
        "viewtalkpage": "Ver discussão",
-       "otherlanguages": "Noutros idiomas",
+       "otherlanguages": "Noutras línguas",
        "redirectedfrom": "(Redirecionado de $1)",
        "redirectpagesub": "Página de redirecionamento",
        "redirectto": "Redireciona para:",
-       "lastmodifiedat": "Esta página foi editada pela última vez à(s) $2 de $1.",
+       "lastmodifiedat": "Esta página foi editada pela última vez às $2 de $1.",
        "viewcount": "Esta página foi acedida {{PLURAL:$1|uma vez|$1 vezes}}.",
        "protectedpage": "Página protegida",
        "jumpto": "Ir para:",
        "undo-failure": "Não foi possível desfazer a edição por conflito com alterações intermédias.",
        "undo-norev": "Não foi possível desfazer a edição porque não existe ou foi apagada.",
        "undo-nochange": "A edição parece já ter sido desfeita.",
-       "undo-summary": "Desfez a edição $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|Discussão]])",
+       "undo-summary": "Desfez a edição $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|discussão]])",
        "undo-summary-username-hidden": "Desfez a edição $1 de um utilizador oculto",
        "cantcreateaccount-text": "A criação de contas a partir deste endereço IP (<strong>$1</strong>) foi bloqueada por [[User:$3|$3]].\n\nO motivo apresentado por $3 foi <em>$2</em>",
        "cantcreateaccount-range-text": "A criação de conta a partir dos endereços IP no intervalo <strong>$1</strong>, que inclui o seu endereço IP (<strong>$4</strong>), foi bloqueada por [[User:$3|$3]].\n\nO motivo apresentado por $3 foi <em>$2</em>",
        "gender-unknown": "Ao mencioná-lo, o software irá utilizar palavras de género neutro sempre que possível",
        "gender-male": "Ele é um utilizador",
        "gender-female": "Ela é uma utilizadora",
-       "prefs-help-gender": "Esta preferência é opcional.\nO software usa o seu valor para o endereçar e para o mencionar a outros usando o género gramatical apropriado.\nEsta informação será pública.",
+       "prefs-help-gender": "Esta preferência é opcional.\nO ''software'' usa o valor para se dirigir a si e para o mencionar a outros usando o género gramatical apropriado.\nEsta informação será pública.",
        "email": "Correio eletrónico",
        "prefs-help-realname": "O fornecimento do nome verdadeiro é opcional.\nSe optar por revelá-lo, será utilizado para atribuir-lhe crédito pelo seu trabalho.",
        "prefs-help-email": "Opcional: o endereço de correio eletrónico é opcional, mas será necessário para redefinir a palavra-passe caso esqueça a antiga.",
        "uploadnewversion-linktext": "Carregar uma nova versão deste ficheiro",
        "shared-repo-from": "de $1",
        "shared-repo": "um repositório partilhado",
+       "filepage.css": "/* Os estilos CSS colocados aqui serão incluídos na página de descrição do ficheiro, também incluída nas wikis clientes externas */",
        "upload-disallowed-here": "Não pode substituir este ficheiro.",
        "filerevert": "Reverter $1",
        "filerevert-legend": "Reverter ficheiro",
        "mywatchlist": "Páginas vigiadas",
        "watchlistfor2": "Para $1 $2",
        "nowatchlist": "A sua lista de páginas vigiadas está vazia.",
-       "watchlistanontext": "Por favor, inicie sessão para ver ou editar itens da sua lista de páginas vigiadas.",
+       "watchlistanontext": "Para ver ou editar entradas da sua lista de páginas vigiadas, inicie uma sessão, por favor.",
        "watchnologin": "Não está autenticado(a)",
        "addwatch": "Adicionar às páginas vigiadas",
-       "addedwatchtext": "\"[[:$1]]\" e a sua página de discussão foram adicionadas à sua [[Special:Watchlist|lista de páginas vigiadas]].",
-       "addedwatchtext-talk": "\"[[:$1]]\" e a sua página associada foram adicionadas à sua lista de [[Special:Watchlist|páginas vigiadas]].",
-       "addedwatchtext-short": "A página \"$1\" foi adicionada à sua lista de vigiadas.",
+       "addedwatchtext": "\"[[:$1]]\" e a respetiva página de discussão foram adicionadas à sua [[Special:Watchlist|lista de páginas vigiadas]].",
+       "addedwatchtext-talk": "\"[[:$1]]\" e a respetiva página associada foram adicionadas à sua lista de [[Special:Watchlist|páginas vigiadas]].",
+       "addedwatchtext-short": "A página \"$1\" foi adicionada às suas páginas vigiadas.",
        "removewatch": "Remover das páginas vigiadas",
-       "removedwatchtext": "\"[[:$1]]\" e a sua página de discussão foram removidas da sua lista de [[Special:Watchlist|páginas vigiadas]].",
-       "removedwatchtext-talk": "\"[[:$1]]\" e a sua página associada foram removidas da sua lista de [[Special:Watchlist|páginas vigiadas]].",
-       "removedwatchtext-short": "A página \"$1\" foi removida da sua lista de vigiadas.",
+       "removedwatchtext": "\"[[:$1]]\" e a respetiva página de discussão foram removidas da sua lista de [[Special:Watchlist|páginas vigiadas]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" e a respetiva página associada foram removidas da sua lista de [[Special:Watchlist|páginas vigiadas]].",
+       "removedwatchtext-short": "A página \"$1\" foi removida das suas páginas vigiadas.",
        "watch": "Vigiar",
        "watchthispage": "Vigiar esta página",
        "unwatch": "Desinteressar-se",
        "unwatchthispage": "Parar de vigiar esta página",
        "notanarticle": "Não é uma página de conteúdo",
-       "notvisiblerev": "Edição eliminada",
+       "notvisiblerev": "A última revisão feita por um utilizador diferente foi eliminada",
        "watchlist-details": "{{PLURAL:$1|Existe $1 página|Existem $1 páginas}} na sua lista de páginas vigiadas (mais as páginas de discussão).",
        "wlheader-enotif": "A notificação por correio eletrónico está ativa.",
        "wlheader-showupdated": "As páginas modificadas desde a última vez que as visitou aparecem destacadas a <strong>negrito</strong>.",
        "undelete-error-long": "Foram encontrados erros ao tentar restaurar o ficheiro:\n\n$1",
        "undelete-show-file-confirm": "Tem a certeza de que quer ver a revisão eliminada do ficheiro \"<nowiki>$1</nowiki>\" de $2 às $3?",
        "undelete-show-file-submit": "Sim",
-       "namespace": "Domínio:",
+       "namespace": "Espaço nominal:",
        "invert": "Inverter seleção",
        "tooltip-invert": "Marque esta caixa para esconder as alterações a páginas no domínio selecionado (e no domínio associado, se escolheu fazê-lo)",
        "tooltip-whatlinkshere-invert": "Marque esta caixa de seleção para ocultar ligações de páginas dentro do domínio selecionado.",
-       "namespace_association": "Domínio associado",
+       "namespace_association": "Espaço nominal associado",
        "tooltip-namespace_association": "Marque esta caixa para incluir também o domínio de conteúdo ou de discussão associado à sua seleção",
        "blanknamespace": "(Principal)",
        "contributions": "Contribuições {{GENDER:$1|do utilizador|da utilizadora}}",
        "interlanguage-link-title-nonlang": "$1 – $2",
        "common.css": "/* Código CSS colocado aqui será aplicado a todos os temas */",
        "print.css": "/* Código CSS colocado aqui afectará as impressões */",
-       "noscript.css": "/* Os estilos CSS colocados aqui afetarão os utilizadores que tenham o JavaScript desativado em seus navegadores */",
+       "noscript.css": "/* Os estilos CSS colocados aqui afetarão os utilizadores que tenham o JavaScript desativado */",
+       "group-autoconfirmed.css": "/* Os estilos CSS colocados aqui só afetarão os utilizadores autoconfirmados */",
+       "group-user.css": "/* Os estilos CSS colocados aqui só afetarão os utilizadores registados */",
+       "group-bot.css": "/* Os estilos CSS colocados aqui só afetarão robôs */",
+       "group-sysop.css": "/* Os estilos CSS colocados aqui só afetarão os administradores */",
+       "group-bureaucrat.css": "/* Os estilos CSS colocados aqui só afetarão os burocratas */",
        "common.json": "/* Qualquer JSON colocado aqui será carregado para todos os utilizadores em cada carregamento de página. */",
        "common.js": "/* Código Javascript colocado aqui será carregado para todos os utilizadores em cada carregamento de página */",
+       "group-autoconfirmed.js": "/* O código JavaScript colocado aqui só será carregado para utilizadores autoconfirmados */",
+       "group-user.js": "/* O código JavaScript colocado aqui só será carregado para utilizadores registados */",
+       "group-bot.js": "/* O código JavaScript colocado aqui só será carregado para robôs */",
+       "group-sysop.js": "/* O código JavaScript colocado aqui só será carregado para administradores */",
+       "group-bureaucrat.js": "/* O código JavaScript colocado aqui só será carregado para burocratas */",
        "anonymous": "{{PLURAL:$1|Utilizador anónimo|Utilizadores anónimos}} da wiki {{SITENAME}}",
        "siteuser": "$1 da wiki {{SITENAME}}",
        "anonuser": "utilizador anónimo $1 da wiki {{SITENAME}}",
        "exif-compression-2": "CCITT Grupo 3 1-D Codificação Unidimensional Huffman Modificado e Run Length Encoding",
        "exif-compression-3": "CCITT Grupo 3 codificação de fax",
        "exif-compression-4": "CCITT Grupo 4 codificação de fax",
+       "exif-compression-6": "JPEG (antigo)",
        "exif-copyrighted-true": "Direitos de autor reservados",
        "exif-copyrighted-false": "Estado dos direitos de autor indefinido",
-       "exif-photometricinterpretation-1": "Preto e branco (Preto é 0)",
+       "exif-photometricinterpretation-0": "Preto e branco (branco é 0)",
+       "exif-photometricinterpretation-1": "Preto e branco (preto é 0)",
+       "exif-photometricinterpretation-3": "Palete",
+       "exif-photometricinterpretation-4": "Máscara de transparência",
+       "exif-photometricinterpretation-5": "Separados (provavelmente CMYK)",
+       "exif-photometricinterpretation-9": "CIE L*a*b* (codificação ICC)",
+       "exif-photometricinterpretation-10": "CIE L*a*b* (codificação ITU)",
+       "exif-photometricinterpretation-32803": "Matriz de filtros de cores",
+       "exif-photometricinterpretation-34892": "Linear não processado",
        "exif-unknowndate": "Data desconhecida",
        "exif-orientation-1": "Normal",
        "exif-orientation-2": "Espelhamento horizontal",
        "exif-orientation-8": "Rodado 90° no sentido horário",
        "exif-planarconfiguration-1": "formato irregular",
        "exif-planarconfiguration-2": "formato plano",
+       "exif-xyresolution-i": "$1 ppp",
        "exif-xyresolution-c": "$1 pt/cm",
        "exif-colorspace-65535": "Cor não calibrada",
        "exif-componentsconfiguration-0": "não existe",
        "exif-meteringmode-1": "Média",
        "exif-meteringmode-2": "MédiaPonderadaAoCentro",
        "exif-meteringmode-3": "Ponto",
-       "exif-meteringmode-4": "MultiPonto",
+       "exif-meteringmode-4": "Multiponto",
        "exif-meteringmode-5": "Padrão",
        "exif-meteringmode-6": "Parcial",
        "exif-meteringmode-255": "Outro",
        "autosumm-changed-redirect-target": "Alteração do redirecionamento de [[$1]] para [[$2]]",
        "autosumm-new": "Criou a página com \"$1\"",
        "autosumm-newblank": "Página em branco criada",
-       "lag-warn-normal": "Alterações realizadas {{PLURAL:$1|no último segundo|nos últimos $1 segundos}} podem não constar desta lista.",
-       "lag-warn-high": "Devido a latência elevada no acesso ao servidor da base de dados, as alterações realizadas {{PLURAL:$1|no último segundo|nos últimos $1 segundos}} podem não constar desta lista.",
+       "size-pixel": "$1 {{PLURAL:$1|píxel|píxeis}}",
+       "lag-warn-normal": "As alterações realizadas {{PLURAL:$1|no último segundo|nos últimos $1 segundos}} podem não constar desta lista.",
+       "lag-warn-high": "Devido a uma latência elevada no acesso ao servidor da base de dados, as alterações realizadas {{PLURAL:$1|no último segundo|nos últimos $1 segundos}} podem não constar desta lista.",
        "watchlistedit-normal-title": "Editar lista de páginas vigiadas",
        "watchlistedit-normal-legend": "Remover páginas da lista de páginas vigiadas",
        "watchlistedit-normal-explain": "As suas páginas vigiadas são listadas abaixo.\nPara remover uma página, marque a caixa de seleção correspondente e clique o botão \"{{int:Watchlistedit-normal-submit}}\".\nTambém pode [[Special:EditWatchlist/raw|editar a lista de páginas vigiadas em forma de texto]].",
index 5994991..f4cfc79 100644 (file)
                        "Patrick Star",
                        "Happy13241",
                        "Vcohen",
-                       "AttemptToCallNil"
+                       "AttemptToCallNil",
+                       "Stjn"
                ]
        },
        "tog-underline": "Подчёркивание ссылок:",
        "converter-manual-rule-error": "Ошибка в ручном правиле преобразования языка",
        "undo-success": "Правка может быть отменена. Пожалуйста, просмотрите сравнение версий, чтобы убедиться, что это именно те изменения, которые вас интересуют, и нажмите «Записать страницу», чтобы изменения вступили в силу.",
        "undo-failure": "Правка не может быть отменена из-за несовместимости промежуточных изменений.",
+       "undo-main-slot-only": "Правка не может быть отменена, поскольку оно включает контент вне основного слота.",
        "undo-norev": "Правка не может быть отменена, так как её не существует или она была удалена.",
        "undo-nochange": "Правка, похоже, уже была отменена.",
        "undo-summary": "Отмена правки $1, сделанной [[Special:Contributions/$2|$2]] ([[User talk:$2|обсуждение]])",
        "rcfilters-activefilters": "Активные фильтры",
        "rcfilters-activefilters-hide": "Скрыть",
        "rcfilters-activefilters-show": "Показать",
+       "rcfilters-activefilters-hide-tooltip": "Скрыть область активных фильтров",
+       "rcfilters-activefilters-show-tooltip": "Показать область активных фильтров",
        "rcfilters-advancedfilters": "Расширенные фильтры",
        "rcfilters-limit-title": "Результаты для показа",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|изменение|изменения|изменений}}, $2",
index def5f17..2214def 100644 (file)
        "listfiles_size": "Кээмэйэ",
        "listfiles_description": "Быһаарыыта",
        "listfiles_count": "Барыллар",
-       "listfiles-show-all": "Ð\91илÑ\8d Ñ\8dÑ\80гÑ\8d Ñ\82оÑ\80Ñ\83мнаÑ\80Ñ\8bн Ñ\8dмиÑ\8d ÐºÐ¸Ð»Ð»Ñ\8dр",
+       "listfiles-show-all": "Ð\91илÑ\8d Ñ\85ойÑ\83ккÑ\83 Ñ\82оÑ\80Ñ\83мнаÑ\80Ñ\8bн Ñ\8dмиÑ\8d ÐºÓ©Ñ\80дөр",
        "listfiles-latestversion": "Билиҥҥи барыла",
        "listfiles-latestversion-yes": "Сөп",
        "listfiles-latestversion-no": "Суох",
index c575104..656f82f 100644 (file)
@@ -50,7 +50,7 @@
        "tog-usenewrc": "Групиши измене по страници у скорашњим изменама и списку надгледања",
        "tog-numberheadings": "Аутоматски нумериши поднаслове",
        "tog-showtoolbar": "Прикажи траку с алаткама за уређивање",
-       "tog-editondblclick": "Уређивање страница двоструким кликом",
+       "tog-editondblclick": "Уреди странице двоструким кликом",
        "tog-editsectiononrightclick": "Уређивање одељака десним кликом на њихове наслове",
        "tog-watchcreations": "Додај странице које направим и датотеке које отпремим у мој списак надгледања",
        "tog-watchdefault": "Додај странице и датотеке које изменим у мој списак надгледања",
@@ -66,7 +66,7 @@
        "tog-enotifminoredits": "Пошаљи ми имејл и код мањих измена страница и датотека",
        "tog-enotifrevealaddr": "Откриј моју имејл адресу у порукама обавештења",
        "tog-shownumberswatching": "Прикажи број корисника који надгледају",
-       "tog-oldsig": "Ваш тренутни потпис:",
+       "tog-oldsig": "Ваш постојећи потпис:",
        "tog-fancysig": "Сматрај потпис као викитекст (без самоповезивања)",
        "tog-uselivepreview": "Прикажи претпреглед без поновног учитавања странице",
        "tog-forceeditsummary": "Упозори ме када не унесем опис измене",
        "acct_creation_throttle_hit": "Посетиоци овог викија који користе вашу IP адресу су већ отворили {{PLURAL:$1|1=један налог|$1 налога}} претходни $2, што је највећи дозвољени број у том временском периоду.\nЗбог тога посетиоци с ове IP адресе тренутно не могу отворити више налога.",
        "emailauthenticated": "Ваша имејл адреса је потврђена на дан $2 у $3.",
        "emailnotauthenticated": "Ваша имејл адреса још увек није потврђена.\nИмејл неће бити послат ни у једном од следећих случајева.",
-       "noemailprefs": "УнеÑ\81иÑ\82е Ð¸Ð¼ÐµÑ\98л Ð°Ð´Ñ\80еÑ\81Ñ\83 ÐºÐ°ÐºÐ¾ Ð±Ð¸ Ð¾Ð²Ðµ Ð¼Ð¾Ð³Ñ\83Ñ\9bноÑ\81Ñ\82и Ñ\80адиле.",
+       "noemailprefs": "Ð\9dаведиÑ\82е Ð¸Ð¼ÐµÑ\98л Ð°Ð´Ñ\80еÑ\81Ñ\83 Ñ\83 Ñ\81воÑ\98им Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aима Ð·Ð° Ñ\80ад Ð¾Ð²Ð¸Ñ\85 Ð¼Ð¾Ð³Ñ\83Ñ\9bноÑ\81Ñ\82и.",
        "emailconfirmlink": "Потврдите своју имејл адресу",
        "invalidemailaddress": "Имејл адреса не може бити прихваћена јер је неисправног облика.\nУнесите исправну адресу или оставите празно поље.",
        "cannotchangeemail": "На овом викију не можете променити имејл адресу налога.",
        "prefs-watchlist-days": "Број дана у списку надгледања:",
        "prefs-watchlist-days-max": "Највише $1 {{PLURAL:$1|дан|дана|дана}}",
        "prefs-watchlist-edits": "Највећи број измена приказаних на списку надгледања:",
-       "prefs-watchlist-edits-max": "Ð\9dаÑ\98веÑ\9bа Ð²Ñ\80едноÑ\81Ñ\82 Ñ\98е Ñ\85иÑ\99адÑ\83",
+       "prefs-watchlist-edits-max": "Ð\9dаÑ\98веÑ\9bи Ð±Ñ\80оÑ\98: 1000",
        "prefs-watchlist-token": "Жетон списка надгледања:",
        "prefs-watchlist-managetokens": "Управљај жетонима",
        "prefs-misc": "Друга подешавања",
        "prefs-resetpass": "промени лозинку",
        "prefs-changeemail": "промени или уклони имејл адресу",
-       "prefs-setemail": "Ð\9fостави имејл адресу",
+       "prefs-setemail": "постави имејл адресу",
        "prefs-email": "Подешавања имејла",
        "prefs-rendering": "Изглед",
        "saveprefs": "Сачувај",
-       "restoreprefs": "Ð\92Ñ\80аÑ\82и Ñ\81ве Ð½Ð° Ð¿Ð¾Ð´Ñ\80азÑ\83мевано (у свим одељцима)",
+       "restoreprefs": "Ð\92Ñ\80аÑ\82и Ñ\81ва Ð¿Ð¾Ð´Ñ\80азÑ\83мевана Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа (у свим одељцима)",
        "prefs-editing": "Уређивање",
        "searchresultshead": "Претрага",
        "stub-threshold": "Праг за обликовање везе као клице ($1):",
        "recentchangesdays": "Број дана у скорашњим изменама:",
        "recentchangesdays-max": "Највише $1 {{PLURAL:$1|дан|дана}}",
        "recentchangescount": "Подразумевани број измена за приказ у скорашњим изменама, историјама страница и дневницима:",
-       "prefs-help-recentchangescount": "Ð\9dаÑ\98веÑ\9bа Ð²Ñ\80едноÑ\81Ñ\82: 1000",
-       "prefs-help-watchlist-token2": "Ово је тајни кључ за веб-довод Вашег списка надгледања. \nСвако ко зна овај кључ биће у могућности да види Ваш списак надгледања, зато кључ немојте одавати никоме. \nАко је потребно, кључ [[Special:ResetTokens|можете ресетовати]].",
+       "prefs-help-recentchangescount": "Ð\9dаÑ\98веÑ\9bа Ð±Ñ\80оÑ\98: 1000",
+       "prefs-help-watchlist-token2": "Ово је тајни кључ за веб-довод Вашег списка надгледања. \nСвако ко зна овај кључ биће у могућности да чита Ваш списак надгледања, зато га немојте делити. \nАко је потребно, [[Special:ResetTokens|можете га обновити]].",
        "savedprefs": "Ваша подешавања су сачувана.",
        "savedrights": "Корисничке групе за {{GENDER:$1|$1}} су сачуване.",
        "timezonelegend": "Временска зона:",
        "timezoneregion-europe": "Европа",
        "timezoneregion-indian": "Индијски океан",
        "timezoneregion-pacific": "Тихи океан",
-       "allowemail": "Ð\9eмогÑ\83Ñ\9bи примање имејлова од других корисника",
-       "email-allow-new-users-label": "Ð\9eмогÑ\83Ñ\9bи примање имејлова од новајлија",
-       "email-blacklist-label": "Забрани следећим корисницима да ми шаљу имејлове:",
+       "allowemail": "Ð\94озволи примање имејлова од других корисника",
+       "email-allow-new-users-label": "Ð\94озволи примање имејлова од новајлија",
+       "email-blacklist-label": "Забрани примање имејлова од следећих корисника:",
        "prefs-searchoptions": "Претрага",
        "prefs-namespaces": "Именски простори",
        "default": "подразумевана",
        "prefs-emailconfirm-label": "Потврда имејла:",
        "youremail": "Имејл:",
        "username": "{{GENDER:$1|Корисничко име}}:",
-       "prefs-memberingroups": "{{PLURAL:$1|Група|Групе}}:",
+       "prefs-memberingroups": "{{GENDER:$2|Члан|Чланица}} {{PLURAL:$1|групе|групâ}}:",
        "prefs-memberingroups-type": "$1",
        "group-membership-link-with-expiry": "$1 (до $2)",
        "prefs-registration": "Време регистрације:",
        "yourvariant": "Варијанта језика:",
        "prefs-help-variant": "Жељена варијанта или правопис за приказ страница са садржајем овог викија.",
        "yournick": "Нови потпис:",
-       "prefs-help-signature": "Коментари на страницама за разговор би требали бити потписани с „<nowiki>~~~~</nowiki>“ што ће бити претворено у Ваш потпис и време.",
+       "prefs-help-signature": "Коментари на страницама за разговор требају бити потписани са „<nowiki>~~~~</nowiki>“ које ће бити претворено у Ваш потпис и време.",
        "badsig": "Потпис је неисправан.\nПроверите ознаке HTML.",
        "badsiglength": "Ваш потпис је предугачак.\nНе сме бити дужи од $1 {{PLURAL:$1|знака|знака|знакова}}.",
        "yourgender": "Како желите да се представите?",
-       "gender-unknown": "Ð\9dе Ð¶ÐµÐ»Ð¸Ð¼ Ð´Ð° Ñ\81е Ð¿Ñ\80едÑ\81Ñ\82авим",
+       "gender-unknown": "Ð\9aад Ð\92аÑ\81 Ñ\81помиÑ\9aе, Ñ\81оÑ\84Ñ\82веÑ\80 Ñ\9bе ÐºÐ¾Ñ\80иÑ\81Ñ\82иÑ\82и Ñ\80одно Ð½ÐµÑ\83Ñ\82Ñ\80алне Ñ\80еÑ\87и ÐºÐ°Ð´ Ð³Ð¾Ð´ Ñ\98е Ñ\82о Ð¼Ð¾Ð³Ñ\83Ñ\9bе",
        "gender-male": "Он уређује вики странице",
        "gender-female": "Она уређује вики странице",
-       "prefs-help-gender": "Ð\9dеобавезно: ÐºÐ¾Ñ\80иÑ\81Ñ\82и Ñ\81е Ð·Ð° Ð¸Ñ\81пÑ\80авно Ð¾Ð±Ñ\80аÑ\9bаÑ\9aе Ñ\81оÑ\84Ñ\82веÑ\80а ÐºÐ¾Ñ\80иÑ\81ниÑ\86има, Ð·Ð°Ð²Ð¸Ñ\81но Ð¾Ð´ Ñ\9aиÑ\85овог Ð¿Ð¾Ð»Ð°.\nÐ\9eваÑ\98 Ð¿Ð¾Ð´Ð°Ñ\82ак Ñ\9bе Ð±Ð¸Ñ\82и Ñ\98аван.",
+       "prefs-help-gender": "Ð\9fоÑ\81Ñ\82авÑ\99аÑ\9aе Ð¾Ð²Ð¾Ð³ Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа Ñ\98е Ð½ÐµÐ¾Ð±Ð°Ð²ÐµÐ·Ð½Ð¾.\nСоÑ\84Ñ\82веÑ\80 ÐºÐ¾Ñ\80иÑ\81Ñ\82и Ð´Ð°Ñ\82Ñ\83 Ð²Ñ\80едноÑ\81Ñ\82 Ð´Ð° Ð±Ð¸ Ð\92ам Ñ\81е Ð¾Ð±Ñ\80аÑ\82ио Ð¸ Ñ\81поменÑ\83о Ð\92аÑ\81 Ð´Ñ\80Ñ\83гима ÐºÐ¾Ñ\80иÑ\81Ñ\82еÑ\9bи Ð¾Ð´Ð³Ð¾Ð²Ð°Ñ\80аÑ\98Ñ\83Ñ\9bи Ð³Ñ\80амаÑ\82иÑ\87ки Ñ\80од.\nÐ\9eва Ð¸Ð½Ñ\84оÑ\80маÑ\86иÑ\98а Ñ\9bе Ð±Ð¸Ñ\82и Ñ\98авна.",
        "email": "Имејл",
        "prefs-help-realname": "Право име није обавезно.\nАко изаберете да га унесете, оно ће бити коришћено за приписивање вашег рада.",
-       "prefs-help-email": "Имејл адреса није обавезна, али је потребна у случају да заборавите лозинку.",
+       "prefs-help-email": "Имејл адреса није обавезна, али је потребна за обнављање лозинке, ако је заборавите.",
        "prefs-help-email-others": "Можете је користити и да омогућите другима да вас контактирају преко корисничке странице или странице за разговор, без откривања свог идентитета.",
        "prefs-help-email-required": "Потребна је имејл адреса.",
-       "prefs-info": "Ð\9eÑ\81новни Ð¿Ð¾Ð´Ð°Ñ\86и",
+       "prefs-info": "Ð\9eÑ\81новне Ð¸Ð½Ñ\84оÑ\80маÑ\86иÑ\98е",
        "prefs-i18n": "Интернационализација",
        "prefs-signature": "Потпис",
        "prefs-dateformat": "Формат датума",
        "prefs-developertools": "Програмерске алатке",
        "prefs-editor": "Уређивач",
        "prefs-preview": "Претпреглед",
-       "prefs-advancedrc": "Ð\9dапÑ\80една Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа",
+       "prefs-advancedrc": "Ð\9dапÑ\80едне Ð¾Ð¿Ñ\86иÑ\98е",
        "prefs-opt-out": "Онемогућавање побољшања",
-       "prefs-advancedrendering": "Ð\9dапÑ\80една Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа",
+       "prefs-advancedrendering": "Ð\9dапÑ\80едне Ð¾Ð¿Ñ\86иÑ\98е",
        "prefs-advancedsearchoptions": "Напредне опције",
-       "prefs-advancedwatchlist": "Ð\9dапÑ\80една Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа",
+       "prefs-advancedwatchlist": "Ð\9dапÑ\80едне Ð¾Ð¿Ñ\86иÑ\98е",
        "prefs-displayrc": "Подешавања приказа",
        "prefs-displaywatchlist": "Подешавања приказа",
        "prefs-tokenwatchlist": "Жетон",
        "recentchanges-summary": "Пратите скорашње измене на овој страници.",
        "recentchanges-noresult": "Нема измена у задатом периоду који одговарају овим критеријумима.",
        "recentchanges-timeout": "Ова претрага је истекла. Можда желите да покушате другачије параметре претраге.",
-       "recentchanges-network": "Ð\97бог Ñ\82еÑ\85ниÑ\87ког Ð¿Ñ\80облема Ð½Ðµ Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ñ\83Ñ\87иÑ\82ам Ñ\80езÑ\83лÑ\82аÑ\82е. Ð\9fокÑ\83Ñ\88аÑ\98Ñ\82е Ð¿Ð¾Ð½Ð¾Ð²Ð½Ð¾ Ð´Ð° Ñ\83Ñ\87иÑ\82ате страницу.",
+       "recentchanges-network": "Ð\97бог Ñ\82еÑ\85ниÑ\87ког Ð¿Ñ\80облема Ð½Ðµ Ð¼Ð¾Ð³Ñ\83 Ð´Ð° Ñ\83Ñ\87иÑ\82ам Ñ\80езÑ\83лÑ\82аÑ\82е. Ð\9fокÑ\83Ñ\88аÑ\98Ñ\82е Ð´Ð° Ð¾Ñ\81вежите страницу.",
        "recentchanges-notargetpage": "Унесите назив странице како бисте видели сродне измене.",
        "recentchanges-feed-description": "Пратите скорашње измене уз помоћ овог довода.",
        "recentchanges-label-newpage": "Нова страница",
        "recentchanges-legend-heading": "<strong>Легенда:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|списак нових страница]])",
        "recentchanges-submit": "Прикажи",
-       "rcfilters-tag-remove": "Уклоните филтер „$1”",
+       "rcfilters-tag-remove": "Уклони филтер „$1”",
        "rcfilters-legend-heading": "<strong>Списак скраћеница:</strong>",
        "rcfilters-other-review-tools": "Друге алатке за преглед",
        "rcfilters-group-results-by-page": "Групиши резултате по страницама",
        "rcfilters-advancedfilters": "Напредни филтери",
        "rcfilters-limit-title": "Број измена за приказ",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|измена|измене|измена}}, $2",
-       "rcfilters-date-popup-title": "Временски период",
+       "rcfilters-date-popup-title": "Временски период за претрагу",
        "rcfilters-days-title": "Скорашњи дани",
        "rcfilters-hours-title": "Скорашњи сати",
        "rcfilters-days-show-days": "$1 {{PLURAL:$1|дан|дана}}",
        "rcfilters-days-show-hours": "$1 {{PLURAL:$1|сат|сата}}",
        "rcfilters-highlighted-filters-list": "Истакнуто: $1",
        "rcfilters-quickfilters": "Сачувани филтери",
-       "rcfilters-quickfilters-placeholder-title": "Још увек нема сачуваних филтера",
-       "rcfilters-quickfilters-placeholder-description": "Да бисте сачували своја подешавања филтера и употребљавали их касније, кликните на икону за ознаку у подручју активних филтера, испод.",
+       "rcfilters-quickfilters-placeholder-title": "Још нема сачуваних филтера",
+       "rcfilters-quickfilters-placeholder-description": "Да бисте сачували своја подешавања филтера и поново их употребљавали касније, кликните на икону за обележавање у подручју активних филтера, испод.",
        "rcfilters-savedqueries-defaultlabel": "Сачувани филтери",
        "rcfilters-savedqueries-rename": "Преименуј",
        "rcfilters-savedqueries-setdefault": "Постави као подразумевано",
        "rcfilters-savedqueries-already-saved": "Ови филтери су већ сачувани. Измените Ваша подешавања како бисте направили нове сачуване филтере.",
        "rcfilters-restore-default-filters": "Врати подразумеване филтере",
        "rcfilters-clear-all-filters": "Уклони све филтере",
-       "rcfilters-show-new-changes": "Ð\9fогледаÑ\98 Ð½ајновије измене",
+       "rcfilters-show-new-changes": "Ð\9dајновије измене",
        "rcfilters-search-placeholder": "Филтрирај измене (користите мени или претрагу за име филтера)",
        "rcfilters-invalid-filter": "Неисправан филтер",
        "rcfilters-empty-filter": "Нема активних филтера. Сви доприноси су приказани.",
        "rcfilters-filterlist-whatsthis": "Како ово функционише?",
        "rcfilters-filterlist-feedbacklink": "Реците нам шта мислите о овим алаткама за филтрирање",
        "rcfilters-highlightbutton-title": "Истакни резултате",
-       "rcfilters-highlightmenu-title": "Ð\9eдабеÑ\80и боју",
+       "rcfilters-highlightmenu-title": "Ð\98забеÑ\80иÑ\82е боју",
        "rcfilters-highlightmenu-help": "Изаберите боју да бисте истакнули ово својство",
        "rcfilters-filterlist-noresults": "Нема пронађених филтера",
        "rcfilters-noresults-conflict": "Није пронађен ниједан резултат јер су критеријуми претраге сукобљени",
        "rcfilters-filter-user-experience-level-unregistered-label": "Нерегистровани",
        "rcfilters-filter-user-experience-level-unregistered-description": "Уредници који нису пријављени.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Новајлије",
-       "rcfilters-filter-user-experience-level-newcomer-description": "Регистровани уредници са мање од 10 измена и 4 дана активности.",
+       "rcfilters-filter-user-experience-level-newcomer-description": "Регистровани уредници који имају мање од 10 измена или 4 дана активности.",
        "rcfilters-filter-user-experience-level-learner-label": "Ученици",
-       "rcfilters-filter-user-experience-level-learner-description": "РегиÑ\81Ñ\82Ñ\80овани Ñ\83Ñ\80едниÑ\86и Ñ\81а Ð²Ð¸Ñ\88е Ð¸Ñ\81кÑ\83Ñ\81Ñ\82ва Ð¾Ð´ â\80\9eноваÑ\98лиÑ\98аâ\80\9d, Ð°Ð»Ð¸ Ð¼Ð°Ñ\9aе Ð¾Ð´ „искусних корисника”.",
+       "rcfilters-filter-user-experience-level-learner-description": "РегиÑ\81Ñ\82Ñ\80овани Ñ\83Ñ\80едниÑ\86и Ñ\87иÑ\98е Ñ\98е Ð¸Ñ\81кÑ\83Ñ\81Ñ\82во Ð¸Ð·Ð¼ÐµÑ\92Ñ\83 â\80\9eноваÑ\98лиÑ\98аâ\80\9d Ð¸ „искусних корисника”.",
        "rcfilters-filter-user-experience-level-experienced-label": "Искусни корисници",
        "rcfilters-filter-user-experience-level-experienced-description": "Регистровани уредници са више од 500 измена и 30 дана активности.",
        "rcfilters-filtergroup-automated": "Аутоматизовани доприноси",
        "rcfilters-filter-bots-label": "Бот",
-       "rcfilters-filter-bots-description": "Ð\98змене Ð½Ð°Ð¿Ñ\80авÑ\99ене Ð°Ñ\83Ñ\82омаÑ\82изованим Ð°Ð»Ð°Ñ\82има.",
+       "rcfilters-filter-bots-description": "Ð\98змене Ð½Ð°Ð¿Ñ\80авÑ\99ене Ð°Ñ\83Ñ\82омаÑ\82изованим Ð°Ð»Ð°Ñ\82кама.",
        "rcfilters-filter-humans-label": "Човек (није бот)",
        "rcfilters-filter-humans-description": "Измене које су направили људи-уредници.",
-       "rcfilters-filtergroup-reviewstatus": "Патролираност",
-       "rcfilters-filter-reviewstatus-unpatrolled-description": "Измене нису ручно или аутоматски означене патролираним.",
+       "rcfilters-filtergroup-reviewstatus": "Прегледаност",
+       "rcfilters-filter-reviewstatus-unpatrolled-description": "Ð\98змене ÐºÐ¾Ñ\98е Ð½Ð¸Ñ\81Ñ\83 Ñ\80Ñ\83Ñ\87но Ð¸Ð»Ð¸ Ð°Ñ\83Ñ\82омаÑ\82Ñ\81ки Ð¾Ð·Ð½Ð°Ñ\87ене Ð¿Ð°Ñ\82Ñ\80олиÑ\80аним.",
        "rcfilters-filter-reviewstatus-unpatrolled-label": "Непатролирано",
-       "rcfilters-filter-reviewstatus-manual-description": "Измене ручно означене патролираним.",
+       "rcfilters-filter-reviewstatus-manual-description": "Измене које су ручно означене патролираним.",
        "rcfilters-filter-reviewstatus-manual-label": "Ручно патролирано",
-       "rcfilters-filter-reviewstatus-auto-description": "Ð\98змене Ð¸Ñ\81кÑ\83Ñ\81ниÑ\85 Ñ\83Ñ\80едника чији је рад аутоматски означен патролираним.",
+       "rcfilters-filter-reviewstatus-auto-description": "Ð\98змене Ð½Ð°Ð¿Ñ\80едниÑ\85 ÐºÐ¾Ñ\80иÑ\81ника чији је рад аутоматски означен патролираним.",
        "rcfilters-filter-reviewstatus-auto-label": "Аутоматски патролирано",
        "rcfilters-filtergroup-significance": "Значај",
        "rcfilters-filter-minor-label": "Мање измене",
-       "rcfilters-filter-minor-description": "Ð\98змене ÐºÐ¾Ñ\98е Ñ\98е Ð°Ñ\83Ñ\82оÑ\80 Ð¾Ð·Ð½Ð°Ñ\87ио ÐºÐ°Ð¾ Ð¼Ð°Ñ\9aе.",
+       "rcfilters-filter-minor-description": "Ð\98змене ÐºÐ¾Ñ\98е Ñ\98е Ð°Ñ\83Ñ\82оÑ\80 Ð¾Ð·Ð½Ð°Ñ\87ио Ð¼Ð°Ñ\9aим.",
        "rcfilters-filter-major-label": "Не-мање измене",
-       "rcfilters-filter-major-description": "Ð\98змене ÐºÐ¾Ñ\98е Ð½Ð¸Ñ\81Ñ\83 Ð¾Ð·Ð½Ð°Ñ\87ене ÐºÐ°Ð¾ Ð¼Ð°Ñ\9aе.",
+       "rcfilters-filter-major-description": "Ð\98змене ÐºÐ¾Ñ\98е Ð½Ð¸Ñ\81Ñ\83 Ð¾Ð·Ð½Ð°Ñ\87ене Ð¼Ð°Ñ\9aим.",
        "rcfilters-filtergroup-watchlist": "Странице на списку надгледања",
        "rcfilters-filter-watchlist-watched-label": "На списку надгледања",
        "rcfilters-filter-watchlist-watched-description": "Измене страница на Вашем списку надгледања.",
        "rcfilters-filter-watchlistactivity-unseen-description": "Измене страница које нисте посетили од када су направљене измене.",
        "rcfilters-filter-watchlistactivity-seen-label": "Погледане измене",
        "rcfilters-filter-watchlistactivity-seen-description": "Измене страница које сте посетили од када су направљене измене.",
-       "rcfilters-filtergroup-changetype": "Тип измене",
+       "rcfilters-filtergroup-changetype": "Ð\92Ñ\80Ñ\81Ñ\82а измене",
        "rcfilters-filter-pageedits-label": "Измене страница",
        "rcfilters-filter-pageedits-description": "Измене вики садржаја, расправа, описа категорија…",
        "rcfilters-filter-newpages-label": "Прављење страница",
-       "rcfilters-filter-newpages-description": "Измене којима се стварају нове странице.",
+       "rcfilters-filter-newpages-description": "Измене којима се праве нове странице.",
        "rcfilters-filter-categorization-label": "Измене категорија",
        "rcfilters-filter-categorization-description": "Записи о страницама додатим или уклоњеним из категорија.",
-       "rcfilters-filter-logactions-label": "РадÑ\9aе Ð·Ð°Ð±ÐµÐ»ÐµÐ¶ÐµÐ½Ðµ Ñ\83 Ð´Ð½ÐµÐ²Ð½Ð¸Ñ\86има",
-       "rcfilters-filter-logactions-description": "Административне радње, стварање налога, брисање страница, отпремања…",
+       "rcfilters-filter-logactions-label": "Ð\97абележене Ñ\80адÑ\9aе",
+       "rcfilters-filter-logactions-description": "Административне радње, прављење налога, брисање страница, отпремања…",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Филтер за „мање” измене је у сукобу са једним или више филтера типа измена, зато што одређени типови измена не могу да се означе као „мање”. Сукобљени филтери су означени у подручју Активни филтери, изнад.",
        "rcfilters-hideminor-conflicts-typeofchange": "Одређени типови измена не могу да се означе као „мање”, тако да је овај филтер у сукобу са следећим филтерима типа измена: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Овај филтер типа измене је у сукобу са филтером за „мање” измене. Одређени типови измена не могу да се означе као „мање”.",
        "rcfilters-exclude-button-off": "Изостави означено",
        "rcfilters-exclude-button-on": "Изостави одабрано",
        "rcfilters-view-tags": "Означене измене",
-       "rcfilters-view-namespaces-tooltip": "Филтрирајте резултате према именском простору",
-       "rcfilters-view-tags-tooltip": "Филтрирајте резултате према ознаци измене",
+       "rcfilters-view-namespaces-tooltip": "Филтрирај резултате према именском простору",
+       "rcfilters-view-tags-tooltip": "Филтрирај резултате према ознаци измене",
        "rcfilters-view-return-to-default-tooltip": "Повратак на главни мени",
        "rcfilters-view-tags-help-icon-tooltip": "Сазнајте више о означеним изменама",
        "rcfilters-liveupdates-button": "Ажурирај уживо",
-       "rcfilters-liveupdates-button-title-on": "Искључите ажурирања уживо",
-       "rcfilters-liveupdates-button-title-off": "Ð\9fÑ\80иказ Ð½Ð¾Ð²Ð¸Ñ\85 Ð¸Ð·Ð¼ÐµÐ½Ð° уживо",
+       "rcfilters-liveupdates-button-title-on": "Искључи ажурирања уживо",
+       "rcfilters-liveupdates-button-title-off": "Ð\9fÑ\80икажи Ð½Ð¾Ð²Ðµ Ð¸Ð·Ð¼ÐµÐ½Ðµ уживо",
        "rcfilters-watchlist-markseen-button": "Означи све измене као погледане",
        "rcfilters-watchlist-edit-watchlist-button": "Промени списак надгледаних страница",
        "rcfilters-watchlist-showupdated": "Измене на страницама које нисте посетили од када је измена извршена су <strong>подебљане</strong>, са испуњеним ознакама.",
        "tooltip-ca-talk": "Разговор о страници са садржајем",
        "tooltip-ca-edit": "Уредите ову страницу",
        "tooltip-ca-addsection": "Започните нови одељак",
-       "tooltip-ca-viewsource": "Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð·Ð°ÐºÑ\99Ñ\83Ñ\87ана. \nÐ\9cожеÑ\82е Ð¿Ð¾Ð³Ð»ÐµÐ´Ð°Ñ\82и Ð¸Ð·Ð²Ð¾Ñ\80ни Ñ\82екÑ\81Ñ\82.",
+       "tooltip-ca-viewsource": "Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\98е Ð·Ð°ÐºÑ\99Ñ\83Ñ\87ана. \nÐ\9cожеÑ\82е Ð´Ð° Ð¿Ð¾Ð³Ð»ÐµÐ´Ð°Ñ\82е Ñ\9aен Ð¸Ð·Ð²Ð¾Ñ\80ни ÐºÃ´Ð´",
        "tooltip-ca-history": "Претходне измене ове странице",
        "tooltip-ca-protect": "Заштитите ову страницу",
        "tooltip-ca-unprotect": "Промени заштиту ове странице",
        "tooltip-ca-nstab-template": "Погледајте шаблон",
        "tooltip-ca-nstab-help": "Погледајте страницу за помоћ",
        "tooltip-ca-nstab-category": "Погледајте страницу категорија",
-       "tooltip-minoredit": "Ð\9eзнаÑ\87иÑ\82е Ð¾Ð²Ñ\83 Ð¸Ð·Ð¼ÐµÐ½Ñ\83 ÐºÐ°Ð¾ Ð¼Ð°Ñ\9aу",
+       "tooltip-minoredit": "Ð\9eзнаÑ\87иÑ\82е ÐºÐ°Ð¾ Ð¼Ð°Ñ\9aÑ\83 Ð¸Ð·Ð¼ÐµÐ½у",
        "tooltip-save": "Сачувајте своје измене",
        "tooltip-publish": "Објавите своје измене",
        "tooltip-preview": "Прегледајте своје измене. Користите ово дугме пре чувања.",
        "tag-mw-replace-description": "Измене које уклањају више од 90% садржаја странице",
        "tag-mw-rollback": "враћање",
        "tag-mw-rollback-description": "Измене које враћају страницу на претходне измене",
-       "tag-mw-undo": "поништена ранија измена",
+       "tag-mw-undo": "поништење",
        "tag-mw-undo-description": "Измене које поништавају претходне измене",
        "tags-title": "Ознаке",
        "tags-intro": "На овој страници је наведен списак ознака с којима програм може да означи измене и његово значење.",
        "mw-widgets-dateinput-no-date": "Датум није изабран",
        "mw-widgets-dateinput-placeholder-day": "ГГГГ-ММ-ДД",
        "mw-widgets-dateinput-placeholder-month": "ГГГГ-ММ",
-       "mw-widgets-mediasearch-input-placeholder": "Ð\9fÑ\80еÑ\82Ñ\80ажи Ð´Ð°Ñ\82оÑ\82еке",
+       "mw-widgets-mediasearch-input-placeholder": "Ð\9fÑ\80еÑ\82Ñ\80ага Ð´Ð°Ñ\82оÑ\82ека",
        "mw-widgets-mediasearch-noresults": "Нема резултата.",
        "mw-widgets-titleinput-description-new-page": "страница још увек не постоји",
        "mw-widgets-titleinput-description-redirect": "преусмерава на $1",
index e12ee8f..b1c1bc3 100644 (file)
@@ -30,7 +30,8 @@
                        "Prevodim",
                        "Bugoslav",
                        "Acamicamacaraca",
-                       "Fitoschido"
+                       "Fitoschido",
+                       "BadDog"
                ]
        },
        "tog-underline": "Podvlačenje veza:",
        "tooltip-ca-talk": "Razgovor o stranici sa sadržajem",
        "tooltip-ca-edit": "Uredi ovu stranicu",
        "tooltip-ca-addsection": "Započnite novi odeljak",
-       "tooltip-ca-viewsource": "Ова страница је закључана. \nМожете погледати изворни текст.",
+       "tooltip-ca-viewsource": "Ova stranica je zaključana. \nMožete da pogledate njen izvorni kôd",
        "tooltip-ca-history": "Prethodne verzije ove stranice",
        "tooltip-ca-protect": "Zaštitite ovu stranicu",
        "tooltip-ca-unprotect": "Promeni zaštitu ove stranice",
index fa87948..5f5df18 100644 (file)
        "rcfilters-filter-humans-description": "רעדאקטירונגען געמאכט פון מענטשן רעדאקטארן.",
        "rcfilters-filtergroup-reviewstatus": "רעצענזירונג־סטאטוס",
        "rcfilters-filter-reviewstatus-unpatrolled-label": "אומפאטראלירט",
+       "rcfilters-filter-reviewstatus-auto-label": "אויטאפאַטראלירט",
        "rcfilters-filtergroup-significance": "באדייטונג",
        "rcfilters-filter-minor-label": "מינערדיקע רעדאַקטירונגען",
+       "rcfilters-filter-minor-description": "רעדאקטירונגען וואס דער שרייבער האט מארקירט פֿארמינערט.",
        "rcfilters-filter-watchlist-watched-label": "אויף דער אויפֿפאַסונג ליסטע",
        "rcfilters-filter-watchlist-notwatched-label": "נישט אויף דער אויפֿפאַסונג ליסטע",
        "rcfilters-filtergroup-changetype": "טיפ ענדערונג",
        "rcfilters-filter-previousrevision-label": "נישט די לעצטע ווערסיעס",
        "rcfilters-filter-excluded": "אויסגעשלאסן",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:נישט</strong> $1",
+       "rcfilters-exclude-button-off": "אויסשליסן געוויילטע",
        "rcfilters-view-tags": "מאַרקירטע רעדאַקטירונגען",
        "rcfilters-liveupdates-button": "לעבעדיקע דערהיינטיקונגען",
        "rcfilters-target-page-placeholder": "אײַנגעבן א בלאטנאמען (אדער קאטעגאריע)",
        "apisandbox-retry": "פרובירן נאכאמאל",
        "apisandbox-helpurls": "הילף לינקען",
        "apisandbox-examples": "ביישפילן",
+       "apisandbox-dynamic-parameters-add-label": "צולייגן פאראמעטער:",
+       "apisandbox-dynamic-parameters-add-placeholder": "פאראמעטער נאמען",
+       "apisandbox-dynamic-error-exists": "ס׳איז שוין פֿאראן א פאראמעטער מיטן נאמען \"$1.",
+       "apisandbox-deprecated-parameters": "פֿארעלטערטע פאראמעטערס",
+       "apisandbox-add-multi": "צולייגן",
+       "apisandbox-submit-invalid-fields-title": "טייל פֿעלדער זענען אומגילטיק",
        "apisandbox-results": "רעזולטאטן",
+       "apisandbox-continue": "פֿארזעצן",
+       "apisandbox-continue-clear": "רייניקן",
+       "apisandbox-multivalue-all-namespaces": "$1 (אלע נאמענטיילן)",
+       "apisandbox-multivalue-all-values": "$1 (אלע ווערטן)",
        "booksources": "דרויסנדיגע ליטעראַטור ISBN",
        "booksources-search-legend": "זוכן פאר דרויסנדע ביכער מקורות",
        "booksources-search": "זוכן",
        "logempty": "נישטא קיין פאַסנדיקע זאכן אין לאג.",
        "log-title-wildcard": "זוכן טיטלען וואס הייבן אָן מיט דעם טעקסט",
        "showhideselectedlogentries": "ווײַזן/באַהאַלטן געקליבענע לאגבוך אקציעס",
+       "checkbox-select": "אויסוויילן: $1",
        "checkbox-all": "אַלע",
        "checkbox-none": "קיינע",
        "checkbox-invert": "אומקערן",
        "unblocked-id": "בלאק $1 איז געווארן אַראָפגענומען.",
        "unblocked-ip": "[[Special:Contributions/$1|$1]] איז געווארן אויפבלאקירט.",
        "blocklist": "בלאקירטע באַניצער",
+       "autoblocklist-submit": "זוכן",
        "ipblocklist": "בלאקירטע באַניצער",
        "ipblocklist-legend": "געפֿינען א בלאקירטן באניצער",
        "blocklist-userblocks": "באהאלטן קאנטע בלאקן",
        "unlockdbsuccesssub": "דאטנבאזע שלאס אראפגענומען",
        "lockdbsuccesstext": "די דאטנבאזע איז געשלאסן .<br />\nגעדענקט [[Special:UnlockDB|אוועקנעמען דעם שלאס ]] ווען אייער אויפהאלטונד איז געענדיקט.",
        "unlockdbsuccesstext": "די דאַטנבאַזע איז געווארן אויפֿגעשלאסן",
+       "databaselocked": "די דאַטנבאַזע איז שוין פֿאַרשלאסן.",
        "databasenotlocked": "די דאַטנבאַזע איז נישט פֿאַרשלאסן.",
        "lockedbyandtime": "(דורך $1 אום $2 בײַ $3)",
        "move-page": "באַוועגן $1",
        "cant-move-to-user-page": "איר זענט נישט דערלויבט צו באַוועגן א בלאַט צו א באַניצער בלאַט (אַחוץ צו א באַניצער אונטערבלאַט).",
        "cant-move-category-page": "איר זענט נישט דערלויבט צו באוועגן קאטעגאריע בלעטער.",
        "cant-move-to-category-page": "איר זענט נישט ערלויבט צו באוועגן א בלאט צו קאטעגאריע־בלאט.",
+       "cant-move-subpages": "איר זענט נישט דערלויבט צו באוועגן אונטערבלעטער.",
+       "namespace-nosubpages": "נאמענטייל \"$1\" ערלויבט נישט קיין אונטערבלעטער.",
        "newtitle": "נייע קעפל:",
        "move-watch": "אויפֿפאַסן אויף דעם בלאַט",
        "movepagebtn": "באַוועגן בלאַט",
        "pageinfo-language": "בלאט אינהאלט שפראך",
        "pageinfo-language-change": "ענדערן",
        "pageinfo-content-model": "בלאט אינהאלט מאדעל",
+       "pageinfo-content-model-change": "טוישן",
        "pageinfo-robot-policy": "אינדעקסירן דורך ראבאטן",
        "pageinfo-robot-index": "דערלויבט",
        "pageinfo-robot-noindex": "נישט דערלויבט",
        "markedaspatrollednotify": "די ענדערונג צו $1 איז געווארן מארקירט ווי קאנטראלירט.",
        "markedaspatrollederrornotify": "מארקירן ווי קאנטראלירט דורכגעפאלן.",
        "patrol-log-page": "פאטראלירן לאג-בוך",
-       "patrol-log-header": "דאס איז א לאג-בוך פון פאַטראליטע רעוויזיעס.",
+       "patrol-log-header": "×\93×\90ס ×\90×\99×\96 ×\90 ×\9c×\90×\92\91×\95×\9a ×¤×\95×\9f ×¤×\90Ö·×\98ר×\90×\9c×\99ר×\98×¢ ×¨×¢×\95×\95×\99×\96×\99עס.",
        "log-show-hide-patrol": "$1 פאַטראלירן לאג-בוך",
        "log-show-hide-tag": "$1 טאג־לאגבוך",
+       "confirm-markpatrolled-button": "יאָ",
        "confirm-markpatrolled-top": "מארקירן $3 פון $2 ווי קאנטראלירט?",
        "deletedrevision": "אויסגעמעקט אלטע ווערסיע $1.",
        "filedeleteerror-short": "גרייז ביים אויסמעקן טעקע: $1",
        "newimages-legend": "פֿילטער",
        "newimages-label": "טעקע נאָמען (אדער אַ טײל דערפֿון):",
        "newimages-showbots": "ווײַזן ארויפלאדן פון באטן",
+       "newimages-mediatype": "מעדיע־טיפ:",
        "noimages": "נישטא קיין בילדער.",
        "ilsubmit": "זוכן",
        "bydate": "לויטן דאטום",
index 6b3d33f..997f73d 100644 (file)
        "filedelete-submit": "ⴽⴽⵙ",
        "download": "ⴰⴳⵎ",
        "randompage": "ⵜⴰⵙⵏⴰ ⵜⴰⴷⵀⵎⴰⵙⵜ",
+       "randomincategory-submit": "ⴷⴷⵓ",
        "statistics": "ⴰⵙⵏⵎⴽⵜⴰ",
        "statistics-pages": "ⵜⴰⵙⵏⵉⵡⵉⵏ",
+       "pageswithprop-submit": "ⴷⴷⵓ",
        "brokenredirects-edit": "ⵙⵏⴼⵍ",
        "brokenredirects-delete": "ⴽⴽⵙ",
        "withoutinterwiki-legend": "ⴰⵣⵡⵉⵔ",
        "whatlinkshere-hidelinks": "$1 ⵉⵙⵖⵓⵏⴻⵏ",
        "whatlinkshere-hideimages": "$1 ⵉⵣⴷⴰⵢⵏ ⵖⵔ ⵓⴼⵉⵍⵢⵓ",
        "whatlinkshere-filters": "ⵜⵉⵙⵜⵜⴰⵢⵉⵏ",
+       "whatlinkshere-submit": "ⴷⴷⵓ",
        "ipbreason": "ⵜⴰⵎⵏⵜⵉⵍⵜ:",
        "ipboptions": "2 ⵜⵙⵔⴰⴳⵉⵏ:2 ⵜⵙⵔⴰⴳⵉⵏ,1 ⵡⴰⵙⵙ:1 ⵡⴰⵙⵙ,3 ⵡⵓⵙⵙⴰⵏ:3 ⵡⵓⵙⵙⴰⵏ,1 ⵉⵎⴰⵍⴰⵙⵙ:1 ⵉⵎⴰⵍⴰⵙⵙ,2 ⵉⵎⴰⵍⴰⵙⵙⵏ:2 ⵉⵎⴰⵍⴰⵙⵙⵏ,1 ⵡⴰⵢⵢⵓⵔ:1 ⵡⴰⵢⵢⵓⵔ,3 ⵉⵢⵢⵉⵔⵏ:3 ⵉⵢⵢⵉⵔⵏ,6 ⵉⵢⵢⵉⵔⵏ:6 ⵉⵢⵢⵉⵔⵏ,1 ⵓⵙⴳⴳⴰⵙ:1 ⵓⵙⴳⴳⴰⵙ,ⴰⵔⵓⵙⵎⵉⵍ:ⴰⵔⵓⵙⵎⵉⵍ",
        "blocklist-reason": "ⵜⴰⵎⵏⵜⵉⵍⵜ",
        "imgmultigo": "ⴷⴷⵓ!",
        "imgmultigoto": "ⴷⴷⵓ ⵖⵔ ⵜⴰⵙⵏⴰ ⴰⴷ $1",
        "img-lang-default": "(ⵜⵓⵜⵍⴰⵢⵜ ⵙ ⵓⵡⵏⵓⵍ)",
+       "img-lang-go": "ⴷⴷⵓ",
+       "table_pager_limit_submit": "ⴷⴷⵓ",
        "watchlistedit-clear-explain": "ⵎⴰⵕⵕⴰ",
        "watchlisttools-clear": "ⵙⴼⴹ ⵜⴰⵍⴳⴰⵎⵜ ⵏ ⵓⴹⴼⴼⵓⵔ",
        "watchlisttools-view": "ⵙⴽⵏ ⵉⵙⵏⵉⴼⵉⵍⵏ ⴷ ⵢⵓⵙⴰⵏ",
index 05d9b4a..54296b1 100644 (file)
        "thu": "四",
        "fri": "五",
        "sat": "六",
-       "january": "月",
-       "february": "月",
-       "march": "月",
-       "april": "月",
-       "may_long": "月",
-       "june": "月",
-       "july": "月",
-       "august": "月",
-       "september": "月",
-       "october": "月",
-       "november": "十一月",
-       "december": "十二月",
+       "january": "1月",
+       "february": "2月",
+       "march": "3月",
+       "april": "4月",
+       "may_long": "5月",
+       "june": "6月",
+       "july": "7月",
+       "august": "8月",
+       "september": "9月",
+       "october": "10月",
+       "november": "11月",
+       "december": "12月",
        "january-gen": "一月",
        "february-gen": "二月",
        "march-gen": "三月",
        "helppage-top-gethelp": "說明",
        "mainpage": "首頁",
        "mainpage-description": "首頁",
-       "policy-url": "Project:Policy",
+       "policy-url": "Project:方針",
        "portal": "社群入口",
        "portal-url": "Project:社群入口",
        "privacy": "隱私政策",
        "revdelete-text-file": "已刪除的檔案版本仍會出現於檔案歷史中,但內容將不開放存取。",
        "logdelete-text": "已刪除的日誌活動仍會出現於日誌中,但其部分內容將不會向公眾開放存取。",
        "revdelete-text-others": "若未設定額外條件,其他管理員仍有權限檢視與取消刪除隱藏的內容。",
-       "revdelete-confirm": "è«\8b確èª\8dæ\82¨æ\98¯å\90¦æ\98\8eç\99½æ­¤å\8b\95ä½\9cæ\9c\83é\80 æ\88\90ç\9a\84å¾\8cæ\9e\9cï¼\8c以å\8f\8aæ\82¨æ\89\80å\81\9aç\9a\84å\8b\95ä½\9cæ\98¯å\90¦ç¬¦å\90\88[[{{MediaWiki:Policy-url}}|æ\94¿ç­\96]]規範。",
+       "revdelete-confirm": "è«\8b確èª\8dæ\82¨æ\98¯å\90¦æ\98\8eç\99½æ­¤å\8b\95ä½\9cæ\9c\83é\80 æ\88\90ç\9a\84å¾\8cæ\9e\9cï¼\8c以å\8f\8aæ\82¨æ\89\80å\81\9aç\9a\84å\8b\95ä½\9cæ\98¯å\90¦ç¬¦å\90\88[[{{MediaWiki:Policy-url}}|æ\96¹é\87\9d]]規範。",
        "revdelete-suppress-text": "禁止顯示應<strong>只有</strong>在下述情形時使用:\n* 潛在誹謗的資訊\n* 不恰當的個人資料\n*: <em>住家地址、電話號碼、身分證號碼等。</em>",
        "revdelete-legend": "設定顯示限制",
        "revdelete-hide-text": "修訂文字",
index 3b32c00..b2e976c 100644 (file)
@@ -137,7 +137,8 @@ class PopulateChangeTagDef extends Maintenance {
                        'change_tag_def',
                        [ 'ctd_name', 'ctd_id' ],
                        [],
-                       __METHOD__
+                       __METHOD__,
+                       [ 'ORDER BY' => 'ctd_id' ]
                );
 
                foreach ( $changeTagDefs as $row ) {
@@ -150,6 +151,7 @@ class PopulateChangeTagDef extends Maintenance {
                $dbw = $this->lbFactory->getMainLB()->getConnection( DB_MASTER );
                $sleep = (int)$this->getOption( 'sleep', 10 );
                $lastId = 0;
+               $this->output( "Starting to add ct_tag_id = {$tagId} for ct_tag = {$tagName}" );
                while ( true ) {
                        // Given that indexes might not be there, it's better to use replica
                        $ids = $dbr->selectFieldValues(
@@ -157,7 +159,7 @@ class PopulateChangeTagDef extends Maintenance {
                                'ct_id',
                                [ 'ct_tag' => $tagName, 'ct_tag_id' => null, 'ct_id > ' . $lastId ],
                                __METHOD__,
-                               [ 'LIMIT' => $this->getBatchSize() ]
+                               [ 'LIMIT' => $this->getBatchSize(), 'ORDER BY' => 'ct_id' ]
                        );
 
                        if ( !$ids ) {
@@ -170,6 +172,8 @@ class PopulateChangeTagDef extends Maintenance {
                                        "These ids will be changed to have \"{$tagId}\" as tag id: " . implode( ', ', $ids ) . "\n"
                                );
                                continue;
+                       } else {
+                               $this->output( "Updating ct_tag_id = {$tagId} up to row ct_id = {$lastId}" );
                        }
 
                        $dbw->update(
@@ -184,6 +188,8 @@ class PopulateChangeTagDef extends Maintenance {
                                sleep( $sleep );
                        }
                }
+
+               $this->output( "Finished adding ct_tag_id = {$tagId} for ct_tag = {$tagName}" );
        }
 
 }
diff --git a/maintenance/populateContentTables.php b/maintenance/populateContentTables.php
new file mode 100644 (file)
index 0000000..eee534f
--- /dev/null
@@ -0,0 +1,330 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\NameTableStore;
+use MediaWiki\Storage\SqlBlobStore;
+use Wikimedia\Assert\Assert;
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\ResultWrapper;
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Populate the content and slot tables.
+ * @since 1.32
+ */
+class PopulateContentTables extends Maintenance {
+
+       /** @var IDatabase */
+       private $dbw;
+
+       /** @var NameTableStore */
+       private $contentModelStore;
+
+       /** @var int */
+       private $mainRoleId;
+
+       /** @var array|null Map "{$modelId}:{$address}" to content_id */
+       private $contentRowMap = null;
+
+       private $count = 0, $totalCount = 0;
+
+       public function __construct() {
+               parent::__construct();
+
+               $this->addDescription( 'Populate content and slot tables' );
+               $this->addOption( 'table', 'revision or archive table, or `all` to populate both', false,
+                       true );
+               $this->addOption( 'reuse-content',
+                       'Reuse content table rows when the address and model are the same. '
+                       . 'This will increase the script\'s time and memory usage, perhaps significantly.',
+                       false, false );
+               $this->setBatchSize( 500 );
+       }
+
+       private function initServices() {
+               $this->dbw = $this->getDB( DB_MASTER );
+               $this->contentModelStore = MediaWikiServices::getInstance()->getContentModelStore();
+               $this->mainRoleId = MediaWikiServices::getInstance()->getSlotRoleStore()->acquireId( 'main' );
+       }
+
+       public function execute() {
+               global $wgMultiContentRevisionSchemaMigrationStage;
+
+               $t0 = microtime( true );
+
+               if ( $wgMultiContentRevisionSchemaMigrationStage < MIGRATION_WRITE_BOTH ) {
+                       $this->writeln(
+                               "...cannot update while \$wgMultiContentRevisionSchemaMigrationStage < MIGRATION_WRITE_BOTH"
+                       );
+                       return false;
+               }
+
+               $this->initServices();
+
+               if ( $this->getOption( 'reuse-content', false ) ) {
+                       $this->loadContentMap();
+               }
+
+               foreach ( $this->getTables() as $table ) {
+                       $this->populateTable( $table );
+               }
+
+               $elapsed = microtime( true ) - $t0;
+               $this->writeln( "Done. Processed $this->totalCount rows in $elapsed seconds" );
+       }
+
+       /**
+        * @return string[]
+        */
+       private function getTables() {
+               $table = $this->getOption( 'table', 'all' );
+               $validTableOptions = [ 'all', 'revision', 'archive' ];
+
+               if ( !in_array( $table, $validTableOptions ) ) {
+                       $this->fatalError( 'Invalid table. Must be either `revision` or `archive` or `all`' );
+               }
+
+               if ( $table === 'all' ) {
+                       $tables = [ 'revision', 'archive' ];
+               } else {
+                       $tables = [ $table ];
+               }
+
+               return $tables;
+       }
+
+       private function loadContentMap() {
+               $t0 = microtime( true );
+               $this->writeln( "Loading existing content table rows..." );
+               $this->contentRowMap = [];
+               $dbr = $this->getDB( DB_REPLICA );
+               $from = false;
+               while ( true ) {
+                       $res = $dbr->select(
+                               'content',
+                               [ 'content_id', 'content_address', 'content_model' ],
+                               $from ? "content_id > $from" : '',
+                               __METHOD__,
+                               [ 'ORDER BY' => 'content_id', 'LIMIT' => $this->getBatchSize() ]
+                       );
+                       if ( !$res || !$res->numRows() ) {
+                               break;
+                       }
+                       foreach ( $res as $row ) {
+                               $from = $row->content_id;
+                               $this->contentRowMap["{$row->content_model}:{$row->content_address}"] = $row->content_id;
+                       }
+               }
+               $elapsed = microtime( true ) - $t0;
+               $this->writeln( "Loaded " . count( $this->contentRowMap ) . " rows in $elapsed seconds" );
+       }
+
+       /**
+        * @param string $table
+        */
+       private function populateTable( $table ) {
+               $t0 = microtime( true );
+               $this->count = 0;
+               $this->writeln( "Populating $table..." );
+
+               if ( $table === 'revision' ) {
+                       $idField = 'rev_id';
+                       $tables = [ 'revision', 'slots', 'page' ];
+                       $fields = [
+                               'rev_id',
+                               'len' => 'rev_len',
+                               'sha1' => 'rev_sha1',
+                               'text_id' => 'rev_text_id',
+                               'content_model' => 'rev_content_model',
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                       ];
+                       $joins = [
+                               'slots' => [ 'LEFT JOIN', 'rev_id=slot_revision_id' ],
+                               'page' => [ 'LEFT JOIN', 'rev_page=page_id' ],
+                       ];
+               } else {
+                       $idField = 'ar_rev_id';
+                       $tables = [ 'archive', 'slots' ];
+                       $fields = [
+                               'rev_id' => 'ar_rev_id',
+                               'len' => 'ar_len',
+                               'sha1' => 'ar_sha1',
+                               'text_id' => 'ar_text_id',
+                               'content_model' => 'ar_content_model',
+                               'namespace' => 'ar_namespace',
+                               'title' => 'ar_title',
+                       ];
+                       $joins = [
+                               'slots' => [ 'LEFT JOIN', 'ar_rev_id=slot_revision_id' ],
+                       ];
+               }
+
+               $minmax = $this->dbw->selectRow(
+                       $table,
+                       [ 'min' => "MIN( $idField )", 'max' => "MAX( $idField )" ],
+                       '',
+                       __METHOD__
+               );
+               $batchSize = $this->getBatchSize();
+
+               for ( $startId = $minmax->min; $startId <= $minmax->max; $startId += $batchSize ) {
+                       $endId = min( $startId + $batchSize - 1, $minmax->max );
+                       $rows = $this->dbw->select(
+                               $tables,
+                               $fields,
+                               [
+                                       "$idField >= $startId",
+                                       "$idField <= $endId",
+                                       'slot_revision_id IS NULL',
+                               ],
+                               __METHOD__,
+                               [ 'ORDER BY' => 'rev_id' ],
+                               $joins
+                       );
+                       if ( $rows->numRows() !== 0 ) {
+                               $this->populateContentTablesForRowBatch( $rows, $startId, $table );
+                       }
+
+                       $elapsed = microtime( true ) - $t0;
+                       $this->writeln(
+                               "... $table processed up to revision id $endId of {$minmax->max}"
+                               . " ($this->count rows in $elapsed seconds)"
+                       );
+               }
+
+               $elapsed = microtime( true ) - $t0;
+               $this->writeln( "Done populating $table table. Processed $this->count rows in $elapsed seconds" );
+       }
+
+       /**
+        * @param ResultWrapper $rows
+        * @param int $startId
+        * @param string $table
+        * @return int|null
+        */
+       private function populateContentTablesForRowBatch( ResultWrapper $rows, $startId, $table ) {
+               $this->beginTransaction( $this->dbw, __METHOD__ );
+
+               if ( $this->contentRowMap === null ) {
+                       $map = [];
+               } else {
+                       $map = &$this->contentRowMap;
+               }
+               $contentKeys = [];
+
+               try {
+                       // Step 1: Figure out content rows needing insertion.
+                       $contentRows = [];
+                       foreach ( $rows as $row ) {
+                               $revisionId = $row->rev_id;
+
+                               Assert::invariant( $revisionId !== null, 'rev_id must not be null' );
+
+                               $modelId = $this->contentModelStore->acquireId( $this->getContentModel( $row ) );
+                               $address = SqlBlobStore::makeAddressFromTextId( $row->text_id );
+
+                               $key = "{$modelId}:{$address}";
+                               $contentKeys[$revisionId] = $key;
+
+                               if ( !isset( $map[$key] ) ) {
+                                       $map[$key] = false;
+                                       $contentRows[] = [
+                                               'content_size' => (int)$row->len,
+                                               'content_sha1' => $row->sha1,
+                                               'content_model' => $modelId,
+                                               'content_address' => $address,
+                                       ];
+                               }
+                       }
+
+                       // Step 2: Insert them, then read them back in for use in the next step.
+                       if ( $contentRows ) {
+                               $id = $this->dbw->selectField( 'content', 'MAX(content_id)', '', __METHOD__ );
+                               $this->dbw->insert( 'content', $contentRows, __METHOD__ );
+                               $res = $this->dbw->select(
+                                       'content',
+                                       [ 'content_id', 'content_model', 'content_address' ],
+                                       'content_id > ' . (int)$id,
+                                       __METHOD__
+                               );
+                               foreach ( $res as $row ) {
+                                       $key = $row->content_model . ':' . $row->content_address;
+                                       $map[$key] = $row->content_id;
+                               }
+                       }
+
+                       // Step 3: Insert the slot rows.
+                       $slotRows = [];
+                       foreach ( $rows as $row ) {
+                               $revisionId = $row->rev_id;
+                               $contentId = $map[$contentKeys[$revisionId]] ?? false;
+                               if ( $contentId === false ) {
+                                       throw new \RuntimeException( "Content row for $revisionId not found after content insert" );
+                               }
+                               $slotRows[] = [
+                                       'slot_revision_id' => $revisionId,
+                                       'slot_role_id' => $this->mainRoleId,
+                                       'slot_content_id' => $contentId,
+                                       // There's no way to really know the previous revision, so assume no inheriting.
+                                       // rev_parent_id can get changed on undeletions, and deletions can screw up
+                                       // rev_timestamp ordering.
+                                       'slot_origin' => $revisionId,
+                               ];
+                       }
+                       $this->dbw->insert( 'slots', $slotRows, __METHOD__ );
+                       $this->count += count( $slotRows );
+                       $this->totalCount += count( $slotRows );
+               } catch ( \Exception $e ) {
+                       $this->rollbackTransaction( $this->dbw, __METHOD__ );
+                       $this->fatalError( "Failed to populate content table $table row batch starting at $startId "
+                               . "due to exception: " . $e->__toString() );
+               }
+
+               $this->commitTransaction( $this->dbw, __METHOD__ );
+       }
+
+       /**
+        * @param \stdClass $row
+        * @return string
+        */
+       private function getContentModel( $row ) {
+               if ( isset( $row->content_model ) ) {
+                       return $row->content_model;
+               }
+
+               $title = Title::makeTitle( $row->namespace, $row->title );
+
+               return ContentHandler::getDefaultModelFor( $title );
+       }
+
+       /**
+        * @param string $msg
+        */
+       private function writeln( $msg ) {
+               $this->output( "$msg\n" );
+       }
+}
+
+$maintClass = 'PopulateContentTables';
+require_once RUN_MAINTENANCE_IF_MAIN;
index 44b028d..b4b921f 100644 (file)
@@ -1835,6 +1835,7 @@ return [
                        'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.SaveFiltersPopupButtonWidget.js',
                        'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js',
                        'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterItemHighlightButton.js',
+                       'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.HighlightPopupWidget.js',
                        'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.HighlightColorPickerWidget.js',
                        'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.LiveUpdateButtonWidget.js',
                        'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MarkSeenButtonWidget.js',
@@ -2643,7 +2644,7 @@ return [
        ],
        'mediawiki.widgets.CategoryMultiselectWidget' => [
                'scripts' => [
-                       'resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js',
+                       'resources/src/mediawiki.widgets/mw.widgets.CategoryTagItemWidget.js',
                        'resources/src/mediawiki.widgets/mw.widgets.CategoryMultiselectWidget.js',
                ],
                'dependencies' => [
index ed24af3..1c3dde6 100644 (file)
         */
        mw.inspect = function () {
                var args = arguments;
+               // Lazy-load
                mw.loader.using( 'mediawiki.inspect', function () {
                        mw.inspect.runReports.apply( mw.inspect, args );
                } );
index 6478fd9..e2030c9 100644 (file)
@@ -1,5 +1,5 @@
 /*!
- * Tools for inspecting page composition and performance.
+ * The mediawiki.inspect module.
  *
  * @author Ori Livneh
  * @since 1.22
@@ -9,7 +9,19 @@
 
 ( function ( mw, $ ) {
 
-       var inspect,
+       // mw.inspect is a singleton class with static methods
+       // that itself can also be invoked as a function (mediawiki.base/mw#inspect).
+       // In JavaScript, that is implemented by starting with a function,
+       // and subsequently setting additional properties on the function object.
+
+       /**
+        * Tools for inspecting page composition and performance.
+        *
+        * @class mw.inspect
+        * @singleton
+        */
+
+       var inspect = mw.inspect,
                byteLength = require( 'mediawiki.String' ).byteLength,
                hasOwn = Object.prototype.hasOwnProperty;
 
        }
 
        /**
-        * @class mw.inspect
-        * @singleton
+        * Return a map of all dependency relationships between loaded modules.
+        *
+        * @return {Object} Maps module names to objects. Each sub-object has
+        *  two properties, 'requires' and 'requiredBy'.
         */
-       inspect = {
+       inspect.getDependencyGraph = function () {
+               var modules = inspect.getLoadedModules(),
+                       graph = {};
 
-               /**
-                * Return a map of all dependency relationships between loaded modules.
-                *
-                * @return {Object} Maps module names to objects. Each sub-object has
-                *  two properties, 'requires' and 'requiredBy'.
-                */
-               getDependencyGraph: function () {
-                       var modules = inspect.getLoadedModules(),
-                               graph = {};
+               modules.forEach( function ( moduleName ) {
+                       var dependencies = mw.loader.moduleRegistry[ moduleName ].dependencies || [];
 
-                       modules.forEach( function ( moduleName ) {
-                               var dependencies = mw.loader.moduleRegistry[ moduleName ].dependencies || [];
+                       if ( !hasOwn.call( graph, moduleName ) ) {
+                               graph[ moduleName ] = { requiredBy: [] };
+                       }
+                       graph[ moduleName ].requires = dependencies;
 
-                               if ( !hasOwn.call( graph, moduleName ) ) {
-                                       graph[ moduleName ] = { requiredBy: [] };
+                       dependencies.forEach( function ( depName ) {
+                               if ( !hasOwn.call( graph, depName ) ) {
+                                       graph[ depName ] = { requiredBy: [] };
                                }
-                               graph[ moduleName ].requires = dependencies;
-
-                               dependencies.forEach( function ( depName ) {
-                                       if ( !hasOwn.call( graph, depName ) ) {
-                                               graph[ depName ] = { requiredBy: [] };
-                                       }
-                                       graph[ depName ].requiredBy.push( moduleName );
-                               } );
+                               graph[ depName ].requiredBy.push( moduleName );
                        } );
-                       return graph;
-               },
+               } );
+               return graph;
+       };
 
-               /**
-                * Calculate the byte size of a ResourceLoader module.
-                *
-                * @param {string} moduleName The name of the module
-                * @return {number|null} Module size in bytes or null
-                */
-               getModuleSize: function ( moduleName ) {
-                       var module = mw.loader.moduleRegistry[ moduleName ],
-                               args, i, size;
+       /**
+        * Calculate the byte size of a ResourceLoader module.
+        *
+        * @param {string} moduleName The name of the module
+        * @return {number|null} Module size in bytes or null
+        */
+       inspect.getModuleSize = function ( moduleName ) {
+               var module = mw.loader.moduleRegistry[ moduleName ],
+                       args, i, size;
 
-                       if ( module.state !== 'ready' ) {
-                               return null;
-                       }
+               if ( module.state !== 'ready' ) {
+                       return null;
+               }
+
+               if ( !module.style && !module.script ) {
+                       return 0;
+               }
 
-                       if ( !module.style && !module.script ) {
-                               return 0;
+               function getFunctionBody( func ) {
+                       return String( func )
+                               // To ensure a deterministic result, replace the start of the function
+                               // declaration with a fixed string. For example, in Chrome 55, it seems
+                               // V8 seemingly-at-random decides to sometimes put a line break between
+                               // the opening brace and first statement of the function body. T159751.
+                               .replace( /^\s*function\s*\([^)]*\)\s*{\s*/, 'function(){' )
+                               .replace( /\s*}\s*$/, '}' );
+               }
+
+               // Based on the load.php response for this module.
+               // For example: `mw.loader.implement("example", function(){}, {"css":[".x{color:red}"]});`
+               // @see mw.loader.store.set().
+               args = [
+                       moduleName,
+                       module.script,
+                       module.style,
+                       module.messages,
+                       module.templates
+               ];
+               // Trim trailing null or empty object, as load.php would have done.
+               // @see ResourceLoader::makeLoaderImplementScript and ResourceLoader::trimArray.
+               i = args.length;
+               while ( i-- ) {
+                       if ( args[ i ] === null || ( $.isPlainObject( args[ i ] ) && $.isEmptyObject( args[ i ] ) ) ) {
+                               args.splice( i, 1 );
+                       } else {
+                               break;
                        }
+               }
 
-                       function getFunctionBody( func ) {
-                               return String( func )
-                                       // To ensure a deterministic result, replace the start of the function
-                                       // declaration with a fixed string. For example, in Chrome 55, it seems
-                                       // V8 seemingly-at-random decides to sometimes put a line break between
-                                       // the opening brace and first statement of the function body. T159751.
-                                       .replace( /^\s*function\s*\([^)]*\)\s*{\s*/, 'function(){' )
-                                       .replace( /\s*}\s*$/, '}' );
+               size = 0;
+               for ( i = 0; i < args.length; i++ ) {
+                       if ( typeof args[ i ] === 'function' ) {
+                               size += byteLength( getFunctionBody( args[ i ] ) );
+                       } else {
+                               size += byteLength( JSON.stringify( args[ i ] ) );
                        }
+               }
 
-                       // Based on the load.php response for this module.
-                       // For example: `mw.loader.implement("example", function(){}, {"css":[".x{color:red}"]});`
-                       // @see mw.loader.store.set().
-                       args = [
-                               moduleName,
-                               module.script,
-                               module.style,
-                               module.messages,
-                               module.templates
-                       ];
-                       // Trim trailing null or empty object, as load.php would have done.
-                       // @see ResourceLoader::makeLoaderImplementScript and ResourceLoader::trimArray.
-                       i = args.length;
-                       while ( i-- ) {
-                               if ( args[ i ] === null || ( $.isPlainObject( args[ i ] ) && $.isEmptyObject( args[ i ] ) ) ) {
-                                       args.splice( i, 1 );
-                               } else {
-                                       break;
+               return size;
+       };
+
+       /**
+        * Given CSS source, count both the total number of selectors it
+        * contains and the number which match some element in the current
+        * document.
+        *
+        * @param {string} css CSS source
+        * @return {Object} Selector counts
+        * @return {number} return.selectors Total number of selectors
+        * @return {number} return.matched Number of matched selectors
+        */
+       inspect.auditSelectors = function ( css ) {
+               var selectors = { total: 0, matched: 0 },
+                       style = document.createElement( 'style' );
+
+               style.textContent = css;
+               document.body.appendChild( style );
+               $.each( style.sheet.cssRules, function ( index, rule ) {
+                       selectors.total++;
+                       // document.querySelector() on prefixed pseudo-elements can throw exceptions
+                       // in Firefox and Safari. Ignore these exceptions.
+                       // https://bugs.webkit.org/show_bug.cgi?id=149160
+                       // https://bugzilla.mozilla.org/show_bug.cgi?id=1204880
+                       try {
+                               if ( document.querySelector( rule.selectorText ) !== null ) {
+                                       selectors.matched++;
                                }
+                       } catch ( e ) {}
+               } );
+               document.body.removeChild( style );
+               return selectors;
+       };
+
+       /**
+        * Get a list of all loaded ResourceLoader modules.
+        *
+        * @return {Array} List of module names
+        */
+       inspect.getLoadedModules = function () {
+               return mw.loader.getModuleNames().filter( function ( module ) {
+                       return mw.loader.getState( module ) === 'ready';
+               } );
+       };
+
+       /**
+        * Print tabular data to the console, using console.table, console.log,
+        * or mw.log (in declining order of preference).
+        *
+        * @param {Array} data Tabular data represented as an array of objects
+        *  with common properties.
+        */
+       inspect.dumpTable = function ( data ) {
+               try {
+                       // Bartosz made me put this here.
+                       if ( window.opera ) { throw window.opera; }
+                       // Use Function.prototype#call to force an exception on Firefox,
+                       // which doesn't define console#table but doesn't complain if you
+                       // try to invoke it.
+                       // eslint-disable-next-line no-useless-call
+                       console.table.call( console, data );
+                       return;
+               } catch ( e ) {}
+               try {
+                       console.log( JSON.stringify( data, null, 2 ) );
+                       return;
+               } catch ( e ) {}
+               mw.log( data );
+       };
+
+       /**
+        * Generate and print reports.
+        *
+        * When invoked without arguments, prints all available reports.
+        *
+        * @param {...string} [reports] One or more of "size", "css", or "store".
+        */
+       inspect.runReports = function () {
+               var reports = arguments.length > 0 ?
+                       Array.prototype.slice.call( arguments ) :
+                       Object.keys( inspect.reports );
+
+               reports.forEach( function ( name ) {
+                       inspect.dumpTable( inspect.reports[ name ]() );
+               } );
+       };
+
+       /**
+        * Perform a string search across the JavaScript and CSS source code
+        * of all loaded modules and return an array of the names of the
+        * modules that matched.
+        *
+        * @param {string|RegExp} pattern String or regexp to match.
+        * @return {Array} Array of the names of modules that matched.
+        */
+       inspect.grep = function ( pattern ) {
+               if ( typeof pattern.test !== 'function' ) {
+                       pattern = new RegExp( mw.RegExp.escape( pattern ), 'g' );
+               }
+
+               return inspect.getLoadedModules().filter( function ( moduleName ) {
+                       var module = mw.loader.moduleRegistry[ moduleName ];
+
+                       // Grep module's JavaScript
+                       if ( $.isFunction( module.script ) && pattern.test( module.script.toString() ) ) {
+                               return true;
                        }
 
-                       size = 0;
-                       for ( i = 0; i < args.length; i++ ) {
-                               if ( typeof args[ i ] === 'function' ) {
-                                       size += byteLength( getFunctionBody( args[ i ] ) );
-                               } else {
-                                       size += byteLength( JSON.stringify( args[ i ] ) );
-                               }
+                       // Grep module's CSS
+                       if (
+                               $.isPlainObject( module.style ) && Array.isArray( module.style.css ) &&
+                               pattern.test( module.style.css.join( '' ) )
+                       ) {
+                               // Module's CSS source matches
+                               return true;
                        }
 
-                       return size;
-               },
+                       return false;
+               } );
+       };
 
+       /**
+        * @class mw.inspect.reports
+        * @singleton
+        */
+       inspect.reports = {
                /**
-                * Given CSS source, count both the total number of selectors it
-                * contains and the number which match some element in the current
-                * document.
+                * Generate a breakdown of all loaded modules and their size in
+                * kilobytes. Modules are ordered from largest to smallest.
                 *
-                * @param {string} css CSS source
-                * @return {Object} Selector counts
-                * @return {number} return.selectors Total number of selectors
-                * @return {number} return.matched Number of matched selectors
+                * @return {Object[]} Size reports
                 */
-               auditSelectors: function ( css ) {
-                       var selectors = { total: 0, matched: 0 },
-                               style = document.createElement( 'style' );
-
-                       style.textContent = css;
-                       document.body.appendChild( style );
-                       $.each( style.sheet.cssRules, function ( index, rule ) {
-                               selectors.total++;
-                               // document.querySelector() on prefixed pseudo-elements can throw exceptions
-                               // in Firefox and Safari. Ignore these exceptions.
-                               // https://bugs.webkit.org/show_bug.cgi?id=149160
-                               // https://bugzilla.mozilla.org/show_bug.cgi?id=1204880
-                               try {
-                                       if ( document.querySelector( rule.selectorText ) !== null ) {
-                                               selectors.matched++;
-                                       }
-                               } catch ( e ) {}
+               size: function () {
+                       // Map each module to a descriptor object.
+                       var modules = inspect.getLoadedModules().map( function ( module ) {
+                               return {
+                                       name: module,
+                                       size: inspect.getModuleSize( module )
+                               };
                        } );
-                       document.body.removeChild( style );
-                       return selectors;
-               },
 
-               /**
-                * Get a list of all loaded ResourceLoader modules.
-                *
-                * @return {Array} List of module names
-                */
-               getLoadedModules: function () {
-                       return mw.loader.getModuleNames().filter( function ( module ) {
-                               return mw.loader.getState( module ) === 'ready';
+                       // Sort module descriptors by size, largest first.
+                       sortByProperty( modules, 'size', true );
+
+                       // Convert size to human-readable string.
+                       modules.forEach( function ( module ) {
+                               module.sizeInBytes = module.size;
+                               module.size = humanSize( module.size );
                        } );
-               },
 
-               /**
-                * Print tabular data to the console, using console.table, console.log,
-                * or mw.log (in declining order of preference).
-                *
-                * @param {Array} data Tabular data represented as an array of objects
-                *  with common properties.
-                */
-               dumpTable: function ( data ) {
-                       try {
-                               // Bartosz made me put this here.
-                               if ( window.opera ) { throw window.opera; }
-                               // Use Function.prototype#call to force an exception on Firefox,
-                               // which doesn't define console#table but doesn't complain if you
-                               // try to invoke it.
-                               // eslint-disable-next-line no-useless-call
-                               console.table.call( console, data );
-                               return;
-                       } catch ( e ) {}
-                       try {
-                               console.log( JSON.stringify( data, null, 2 ) );
-                               return;
-                       } catch ( e ) {}
-                       mw.log( data );
+                       return modules;
                },
 
                /**
-                * Generate and print one more reports. When invoked with no arguments,
-                * print all reports.
+                * For each module with styles, count the number of selectors, and
+                * count how many match against some element currently in the DOM.
                 *
-                * @param {...string} [reports] Report names to run, or unset to print
-                *  all available reports.
+                * @return {Object[]} CSS reports
                 */
-               runReports: function () {
-                       var reports = arguments.length > 0 ?
-                               Array.prototype.slice.call( arguments ) :
-                               $.map( inspect.reports, function ( v, k ) { return k; } );
+               css: function () {
+                       var modules = [];
 
-                       reports.forEach( function ( name ) {
-                               inspect.dumpTable( inspect.reports[ name ]() );
-                       } );
-               },
+                       inspect.getLoadedModules().forEach( function ( name ) {
+                               var css, stats, module = mw.loader.moduleRegistry[ name ];
 
-               /**
-                * @class mw.inspect.reports
-                * @singleton
-                */
-               reports: {
-                       /**
-                        * Generate a breakdown of all loaded modules and their size in
-                        * kilobytes. Modules are ordered from largest to smallest.
-                        *
-                        * @return {Object[]} Size reports
-                        */
-                       size: function () {
-                               // Map each module to a descriptor object.
-                               var modules = inspect.getLoadedModules().map( function ( module ) {
-                                       return {
-                                               name: module,
-                                               size: inspect.getModuleSize( module )
-                                       };
-                               } );
-
-                               // Sort module descriptors by size, largest first.
-                               sortByProperty( modules, 'size', true );
-
-                               // Convert size to human-readable string.
-                               modules.forEach( function ( module ) {
-                                       module.sizeInBytes = module.size;
-                                       module.size = humanSize( module.size );
-                               } );
-
-                               return modules;
-                       },
-
-                       /**
-                        * For each module with styles, count the number of selectors, and
-                        * count how many match against some element currently in the DOM.
-                        *
-                        * @return {Object[]} CSS reports
-                        */
-                       css: function () {
-                               var modules = [];
-
-                               inspect.getLoadedModules().forEach( function ( name ) {
-                                       var css, stats, module = mw.loader.moduleRegistry[ name ];
-
-                                       try {
-                                               css = module.style.css.join();
-                                       } catch ( e ) { return; } // skip
-
-                                       stats = inspect.auditSelectors( css );
-                                       modules.push( {
-                                               module: name,
-                                               allSelectors: stats.total,
-                                               matchedSelectors: stats.matched,
-                                               percentMatched: stats.total !== 0 ?
-                                                       ( stats.matched / stats.total * 100 ).toFixed( 2 ) + '%' : null
-                                       } );
+                               try {
+                                       css = module.style.css.join();
+                               } catch ( e ) { return; } // skip
+
+                               stats = inspect.auditSelectors( css );
+                               modules.push( {
+                                       module: name,
+                                       allSelectors: stats.total,
+                                       matchedSelectors: stats.matched,
+                                       percentMatched: stats.total !== 0 ?
+                                               ( stats.matched / stats.total * 100 ).toFixed( 2 ) + '%' : null
                                } );
-                               sortByProperty( modules, 'allSelectors', true );
-                               return modules;
-                       },
-
-                       /**
-                        * Report stats on mw.loader.store: the number of localStorage
-                        * cache hits and misses, the number of items purged from the
-                        * cache, and the total size of the module blob in localStorage.
-                        *
-                        * @return {Object[]} Store stats
-                        */
-                       store: function () {
-                               var raw, stats = { enabled: mw.loader.store.enabled };
-                               if ( stats.enabled ) {
-                                       $.extend( stats, mw.loader.store.stats );
-                                       try {
-                                               raw = localStorage.getItem( mw.loader.store.getStoreKey() );
-                                               stats.totalSizeInBytes = byteLength( raw );
-                                               stats.totalSize = humanSize( byteLength( raw ) );
-                                       } catch ( e ) {}
-                               }
-                               return [ stats ];
-                       }
+                       } );
+                       sortByProperty( modules, 'allSelectors', true );
+                       return modules;
                },
 
                /**
-                * Perform a string search across the JavaScript and CSS source code
-                * of all loaded modules and return an array of the names of the
-                * modules that matched.
+                * Report stats on mw.loader.store: the number of localStorage
+                * cache hits and misses, the number of items purged from the
+                * cache, and the total size of the module blob in localStorage.
                 *
-                * @param {string|RegExp} pattern String or regexp to match.
-                * @return {Array} Array of the names of modules that matched.
+                * @return {Object[]} Store stats
                 */
-               grep: function ( pattern ) {
-                       if ( typeof pattern.test !== 'function' ) {
-                               pattern = new RegExp( mw.RegExp.escape( pattern ), 'g' );
+               store: function () {
+                       var raw, stats = { enabled: mw.loader.store.enabled };
+                       if ( stats.enabled ) {
+                               $.extend( stats, mw.loader.store.stats );
+                               try {
+                                       raw = localStorage.getItem( mw.loader.store.getStoreKey() );
+                                       stats.totalSizeInBytes = byteLength( raw );
+                                       stats.totalSize = humanSize( byteLength( raw ) );
+                               } catch ( e ) {}
                        }
-
-                       return inspect.getLoadedModules().filter( function ( moduleName ) {
-                               var module = mw.loader.moduleRegistry[ moduleName ];
-
-                               // Grep module's JavaScript
-                               if ( $.isFunction( module.script ) && pattern.test( module.script.toString() ) ) {
-                                       return true;
-                               }
-
-                               // Grep module's CSS
-                               if (
-                                       $.isPlainObject( module.style ) && Array.isArray( module.style.css ) &&
-                                       pattern.test( module.style.css.join( '' ) )
-                               ) {
-                                       // Module's CSS source matches
-                                       return true;
-                               }
-
-                               return false;
-                       } );
+                       return [ stats ];
                }
        };
 
                mw.log( 'mw.inspect: reports are not available in debug mode.' );
        }
 
-       mw.inspect = inspect;
-
 }( mediaWiki, jQuery ) );
index 940d665..fad409b 100644 (file)
        body:not( .mw-rcfilters-ui-initialized ) .rcfilters-spinner {
                display: block;
                // When initializing, display the spinner on top of the area where the UI will appear
-               margin-top: -( @rcfilters-head-min-height + @rcfilters-head-margin-bottom ) / 2;
+               margin-top: -( @rcfilters-head-min-height + @rcfilters-head-margin-bottom ) / 1.5;
        }
        body.mw-rcfilters-ui-loading .rcfilters-spinner {
                display: block;
                // When loading new results, display the spinner on top of the results area
-               margin-top: 2em;
+               margin-top: -( @rcfilters-head-min-height + @rcfilters-head-margin-bottom ) / 8;
        }
 
        #contentSub,
index 790e015..daa7a91 100644 (file)
 // so it is before the rest of the rule; we need the li& to be in
 // between the wrapper scope and the color-cX class, which doesn't
 // work if the rules are inside the above widget LESS scope
-.highlight-changesListWrapperWidget( @bgcolor ) {
+.highlight-results( @bgcolor ) {
        .mw-rcfilters-ui-changesListWrapperWidget li&,
        .mw-rcfilters-ui-changesListWrapperWidget & tr:first-child,
-       .mw-rcfilters-ui-changesListWrapperWidget tr&.mw-rcfilters-ui-changesListWrapperWidget-enhanced-toplevel:not( .mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey ) td:not( :nth-child( -n+2 ) ),
-       .mw-rcfilters-ui-changesListWrapperWidget tr&.mw-rcfilters-ui-changesListWrapperWidget-enhanced-nested:not( .mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey ) td:not( :nth-child( -n+4 ) ) {
+       .mw-rcfilters-ui-changesListWrapperWidget tr&.mw-rcfilters-ui-highlights-enhanced-toplevel:not( .mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey ) td:not( :nth-child( -n+2 ) ),
+       .mw-rcfilters-ui-changesListWrapperWidget tr&.mw-rcfilters-ui-highlights-enhanced-nested:not( .mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey ) td:not( :nth-child( -n+4 ) ) {
                background-color: @bgcolor;
        }
 }
 
        // Two colors
        @{highlight-color-class-var} when ( @color3 = false ) and ( @color4 = false ) and not ( @color1 = false ), ( @color2 = false ) {
-               .highlight-changesListWrapperWidget( tint( average( @@c1var, @@c2var ), 50% ) );
+               .highlight-results( tint( average( @@c1var, @@c2var ), 50% ) );
        }
        // Three colors
        @{highlight-color-class-var}.mw-rcfilters-highlight-color-@{color3} when ( @color4 = false ) and not ( @color3 = false ) {
                @c3var: ~'highlight-@{color3}';
-               .highlight-changesListWrapperWidget( tint( mix( @@c1var, average( @@c2var, @@c3var ), 33% ), 30% ) );
+               .highlight-results( tint( mix( @@c1var, average( @@c2var, @@c3var ), 33% ), 30% ) );
        }
 
        // Four colors
        @{highlight-color-class-var}.mw-rcfilters-highlight-color-@{color3}.mw-rcfilters-highlight-color-@{color4} when not ( @color4 = false ) {
                @c3var: ~'highlight-@{color3}';
                @c4var: ~'highlight-@{color4}';
-               .highlight-changesListWrapperWidget( tint( mix( @@c1var, mix( @@c2var, average( @@c3var, @@c4var ), 25% ), 25% ), 25% ) );
+               .highlight-results( tint( mix( @@c1var, mix( @@c2var, average( @@c3var, @@c4var ), 25% ), 25% ), 25% ) );
        }
 }
index e9e331b..e0c3c8b 100644 (file)
                        width: 100%;
                }
        }
+}
 
-       &-highlights {
-               display: none;
-               padding: 0 @result-circle-general-margin 0 0;
-               text-align: right;
-               // The width is 5 circles times their diameter + individual margin
-               // and then plus the general margin
-               width: ~'calc( ( @{result-circle-diameter} + @{result-circle-margin} ) * 5 )';
-               // And we want to shift the entire block to the left of the li
-               position: relative;
-               // Negative left margin of width + padding
-               margin-left: ~'calc( ( @{result-circle-diameter} + @{result-circle-margin} ) * -5 - @{result-circle-general-margin} )';
-
-               .mw-rcfilters-ui-changesListWrapperWidget-highlighted & {
-                       display: inline-block;
-               }
+.mw-rcfilters-ui-highlights {
+       display: none;
+       padding: 0 @result-circle-general-margin 0 0;
+       // The width is 5 circles times their diameter + individual margin
+       // and then plus the general margin
+       width: ~'calc( ( @{result-circle-diameter} + @{result-circle-margin} ) * 5 )';
+       // And we want to shift the entire block to the left of the li
+       position: relative;
+       // Negative left margin of width + padding
+       margin-left: ~'calc( ( @{result-circle-diameter} + @{result-circle-margin} ) * -5 - @{result-circle-general-margin} )';
 
-               // This needs to be very specific, since these are
-               // position rules that should apply to all overrides
-               .mw-rcfilters-ui-changesListWrapperWidget .mw-rcfilters-ui-changesListWrapperWidget-highlights > div&-circle {
-                       .box-sizing( border-box );
-                       margin-right: @result-circle-margin;
-                       vertical-align: middle;
-                       // This is to make the dots appear at the center of the
-                       // text itself; it's a horrendous hack and blame JamesF for it.
-                       margin-top: -2px;
-               }
+       .mw-rcfilters-ui-changesListWrapperWidget-highlighted & {
+               display: inline-block;
+       }
 
-               &-color {
+       > div {
+               .box-sizing( border-box );
+               margin-right: @result-circle-margin;
+               vertical-align: middle;
+               // This is to make the dots appear at the center of the
+               // text itself; it's a horrendous hack and blame JamesF for it.
+               margin-top: -2px;
+               float: right;
+       }
 
-                       &-none {
-                               .mw-rcfilters-mixin-circle( @highlight-none, @result-circle-diameter, 0, true );
-                               display: inline-block;
+       &-color {
+               &-none {
+                       .mw-rcfilters-mixin-circle( @highlight-none, @result-circle-diameter, 0, true );
+                       display: inline-block;
 
-                               .mw-rcfilters-highlight-color-c1 &,
-                               .mw-rcfilters-highlight-color-c2 &,
-                               .mw-rcfilters-highlight-color-c3 &,
-                               .mw-rcfilters-highlight-color-c4 &,
-                               .mw-rcfilters-highlight-color-c5 & {
-                                       display: none;
-                               }
+                       .mw-rcfilters-highlight-color-c1 &,
+                       .mw-rcfilters-highlight-color-c2 &,
+                       .mw-rcfilters-highlight-color-c3 &,
+                       .mw-rcfilters-highlight-color-c4 &,
+                       .mw-rcfilters-highlight-color-c5 & {
+                               display: none;
                        }
-                       .result-circle( c1 );
-                       .result-circle( c2 );
-                       .result-circle( c3 );
-                       .result-circle( c4 );
-                       .result-circle( c5 );
                }
+               .result-circle( c1 );
+               .result-circle( c2 );
+               .result-circle( c3 );
+               .result-circle( c4 );
+               .result-circle( c5 );
        }
 }
 
 // One color
 .mw-rcfilters-highlight-color-c1 {
-       .highlight-changesListWrapperWidget( tint( @highlight-c1, 70% ); );
+       .highlight-results( tint( @highlight-c1, 70% ); );
 }
 
 .mw-rcfilters-highlight-color-c2 {
-       .highlight-changesListWrapperWidget( tint( @highlight-c2, 70% ); );
+       .highlight-results( tint( @highlight-c2, 70% ); );
 }
 
 .mw-rcfilters-highlight-color-c3 {
-       .highlight-changesListWrapperWidget( tint( @highlight-c3, 70% ); );
+       .highlight-results( tint( @highlight-c3, 70% ); );
 }
 
 .mw-rcfilters-highlight-color-c4 {
-       .highlight-changesListWrapperWidget( tint( @highlight-c4, 70% ); );
+       .highlight-results( tint( @highlight-c4, 70% ); );
 }
 
 .mw-rcfilters-highlight-color-c5 {
-       .highlight-changesListWrapperWidget( tint( @highlight-c5, 70% ); );
+       .highlight-results( tint( @highlight-c5, 70% ); );
 }
 
 // Two colors
 // a custom color rather than the computed tint
 // see https://phabricator.wikimedia.org/T161267
 .mw-rcfilters-highlight-color-c1.mw-rcfilters-highlight-color-c3 {
-       .highlight-changesListWrapperWidget( @light-green );
+       .highlight-results( @light-green );
 }
 .highlight-color-mix( c1, c4 );
 .highlight-color-mix( c1, c5 );
 
 // Five colors:
 .mw-rcfilters-highlight-color-c1.mw-rcfilters-highlight-color-c2.mw-rcfilters-highlight-color-c3.mw-rcfilters-highlight-color-c4.mw-rcfilters-highlight-color-c5 {
-       .highlight-changesListWrapperWidget( tint( mix( @highlight-c1, mix( @highlight-c2, mix( @highlight-c3, average( @highlight-c4, @highlight-c5 ), 20% ), 20% ), 20% ), 15% ) );
+       .highlight-results( tint( mix( @highlight-c1, mix( @highlight-c2, mix( @highlight-c3, average( @highlight-c4, @highlight-c5 ), 20% ), 20% ), 20% ), 15% ) );
 }
index b49a1cb..ec3fe31 100644 (file)
         * @param {jQuery|string} $content The content of the updated changes list
         */
        mw.rcfilters.ui.ChangesListWrapperWidget.prototype.setupHighlightContainers = function ( $content ) {
-               var $enhancedTopPageCell, $enhancedNestedPagesCell,
-                       widget = this,
-                       highlightClass = 'mw-rcfilters-ui-changesListWrapperWidget-highlights',
-                       $highlights = $( '<div>' )
-                               .addClass( highlightClass )
-                               .append(
-                                       $( '<div>' )
-                                               .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlights-circle' )
-                                               .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlights-color-none' )
-                                               .prop( 'data-color', 'none' )
-                               );
-
-               if ( $( '.mw-rcfilters-ui-changesListWrapperWidget-highlights' ).length ) {
-                       // Already set up
-                       return;
-               }
-
-               mw.rcfilters.HighlightColors.forEach( function ( color ) {
-                       $highlights.append(
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlights-color-' + color )
-                                       .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlights-circle' )
-                                       .prop( 'data-color', color )
-                       );
-               } );
+               var $enhancedTopPageCell,
+                       widget = this;
 
                if ( this.inEnhancedMode() ) {
                        $enhancedTopPageCell = $content.find( 'table.mw-enhanced-rc.mw-collapsible' );
-                       $enhancedNestedPagesCell = $content.find( 'td.mw-enhanced-rc-nested' );
-
-                       // Enhanced RC highlight containers
-                       $content.find( 'table.mw-enhanced-rc tr:first-child' )
-                               .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhanced-toplevel' )
-                               .prepend(
-                                       $( '<td>' )
-                                               .append( $highlights.clone() )
-                               );
-
-                       // We are adding and changing cells in a table that, despite having nested rows,
-                       // is actually all one big table. To prevent the highlights cell in the "nested"
-                       // rows from stretching out the cell with the flags and timestamp in the top row,
-                       // we give the latter colspan=2. Then to make things line up again, we add
-                       // an empty <td> to the "nested" rows.
-
-                       // Set colspan=2 on cell with flags and timestamp in top row
-                       $content.find( 'table.mw-enhanced-rc tr:first-child td.mw-enhanced-rc' )
-                               .prop( 'colspan', '2' );
-                       // Add empty <td> to nested rows to compensate
-                       $enhancedNestedPagesCell.parent().prepend( $( '<td>' ) );
-                       // Add highlights cell to nested rows
-                       $enhancedNestedPagesCell
-                               .before(
-                                       $( '<td>' )
-                                               .append( $highlights.clone().addClass( 'mw-enhanced-rc-nested' ) )
-                               );
-
-                       // We need to target the nested rows differently than the top rows so that the
-                       // LESS rules applies correctly. In top rows, the rule should highlight all but
-                       // the first 2 cells td:not( :nth-child( -n+2 ) and the nested rows, the rule
-                       // should highlight all but the first 4 cells td:not( :nth-child( -n+4 )
-                       $enhancedNestedPagesCell
-                               .closest( 'tr' )
-                               .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhanced-nested' );
-
                        // Go over pages that have sub results
                        // HACK: We really only can collect those by targetting the collapsible class
                        $enhancedTopPageCell.each( function () {
                                $table.find( 'tr:first-child' )
                                        .addClass( collectedClasses.join( ' ' ) );
                        } );
-
-                       $content.addClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhancedView' );
-               } else {
-                       // Regular RC
-                       $content.find( 'ul.special li' )
-                               .prepend( $highlights.clone() );
-
-                       $content.removeClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhancedView' );
                }
        };
 
index c840d7c..e3de55e 100644 (file)
@@ -7,34 +7,24 @@
         * @constructor
         * @param {mw.rcfilters.Controller} controller RCFilters controller
         * @param {mw.rcfilters.dm.FilterItem} model Filter item model
+        * @param {mw.rcfilters.ui.HighlightPopupWidget} highlightPopup Shared highlight color picker
         * @param {Object} [config] Configuration object
         */
-       mw.rcfilters.ui.FilterItemHighlightButton = function MwRcfiltersUiFilterItemHighlightButton( controller, model, config ) {
+       mw.rcfilters.ui.FilterItemHighlightButton = function MwRcfiltersUiFilterItemHighlightButton( controller, model, highlightPopup, config ) {
                config = config || {};
 
-               this.colorPickerWidget = new mw.rcfilters.ui.HighlightColorPickerWidget( controller, model );
-
                // Parent
                mw.rcfilters.ui.FilterItemHighlightButton.parent.call( this, $.extend( true, {}, config, {
                        icon: 'highlight',
-                       indicator: 'down',
-                       popup: {
-                               anchor: false,
-                               padded: true,
-                               align: 'backwards',
-                               horizontalPosition: 'end',
-                               $floatableContainer: this.$element,
-                               width: 290,
-                               $content: this.colorPickerWidget.$element
-                       }
+                       indicator: 'down'
                } ) );
 
                this.controller = controller;
                this.model = model;
+               this.popup = highlightPopup;
 
                // Event
                this.model.connect( this, { update: 'updateUiBasedOnModel' } );
-               this.colorPickerWidget.connect( this, { chooseColor: 'onChooseColor' } );
                // This lives inside a MenuOptionWidget, which intercepts mousedown
                // to select the item. We want to prevent that when we click the highlight
                // button
 
        /* Methods */
 
+       mw.rcfilters.ui.FilterItemHighlightButton.prototype.onAction = function () {
+               this.popup.setAssociatedButton( this );
+               this.popup.setFilterItem( this.model );
+
+               // Parent method
+               mw.rcfilters.ui.FilterItemHighlightButton.parent.prototype.onAction.call( this );
+       };
+
        /**
         * Respond to item model update event
         */
@@ -79,8 +77,4 @@
                                );
                } );
        };
-
-       mw.rcfilters.ui.FilterItemHighlightButton.prototype.onChooseColor = function () {
-               this.popup.toggle( false );
-       };
 }( mediaWiki, jQuery ) );
index 926502d..65b4420 100644 (file)
@@ -9,10 +9,11 @@
         * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel
         * @param {mw.rcfilters.dm.FilterItem} invertModel
         * @param {mw.rcfilters.dm.FilterItem} itemModel Filter item model
+        * @param {mw.rcfilters.ui.HighlightPopupWidget} highlightPopup Shared highlight color picker popup
         * @param {Object} config Configuration object
         */
        mw.rcfilters.ui.FilterMenuOptionWidget = function MwRcfiltersUiFilterMenuOptionWidget(
-               controller, filtersViewModel, invertModel, itemModel, config
+               controller, filtersViewModel, invertModel, itemModel, highlightPopup, config
        ) {
                config = config || {};
 
@@ -21,7 +22,7 @@
                this.model = itemModel;
 
                // Parent
-               mw.rcfilters.ui.FilterMenuOptionWidget.parent.call( this, controller, filtersViewModel, this.invertModel, itemModel, config );
+               mw.rcfilters.ui.FilterMenuOptionWidget.parent.call( this, controller, filtersViewModel, this.invertModel, itemModel, highlightPopup, config );
 
                // Event
                this.model.getGroupModel().connect( this, { update: 'onGroupModelUpdate' } );
index d59fdfb..907c535 100644 (file)
                        ) {
                                this.addTag( item.getName(), item.getLabel() );
                        } else {
-                               this.removeTagByData( item.getName() );
+                               // Only attempt to remove the tag if we can find an item for it (T198140, T198231)
+                               if ( this.findItemFromData( item.getName() ) !== null ) {
+                                       this.removeTagByData( item.getName() );
+                               }
                        }
                }
 
                        // Remove capsule widgets if they're not selected
                        highlightedItems.forEach( function ( filterItem ) {
                                if ( !filterItem.isSelected() ) {
-                                       this.removeTagByData( filterItem.getName() );
+                                       // Only attempt to remove the tag if we can find an item for it (T198140, T198231)
+                                       if ( this.findItemFromData( filterItem.getName() ) !== null ) {
+                                               this.removeTagByData( filterItem.getName() );
+                                       }
                                }
                        }.bind( this ) );
                }
index 64a7fcf..fda0772 100644 (file)
@@ -7,10 +7,9 @@
         *
         * @constructor
         * @param {mw.rcfilters.Controller} controller RCFilters controller
-        * @param {mw.rcfilters.dm.FilterItem} model Filter item model
         * @param {Object} [config] Configuration object
         */
-       mw.rcfilters.ui.HighlightColorPickerWidget = function MwRcfiltersUiHighlightColorPickerWidget( controller, model, config ) {
+       mw.rcfilters.ui.HighlightColorPickerWidget = function MwRcfiltersUiHighlightColorPickerWidget( controller, config ) {
                var colors = [ 'none' ].concat( mw.rcfilters.HighlightColors );
                config = config || {};
 
@@ -22,7 +21,6 @@
                } ) );
 
                this.controller = controller;
-               this.model = model;
 
                this.currentSelection = 'none';
                this.buttonSelect = new OO.ui.ButtonSelectWidget( {
                } );
 
                // Event
-               this.model.connect( this, { update: 'updateUiBasedOnModel' } );
                this.buttonSelect.connect( this, { choose: 'onChooseColor' } );
 
-               this.updateUiBasedOnModel();
-
                this.$element
                        .addClass( 'mw-rcfilters-ui-highlightColorPickerWidget' )
                        .append(
 
        /* Methods */
 
+       /**
+        * Bind the color picker to an item
+        * @param {mw.rcfilters.dm.FilterItem} filterItem
+        */
+       mw.rcfilters.ui.HighlightColorPickerWidget.prototype.setFilterItem = function ( filterItem ) {
+               if ( this.filterItem ) {
+                       this.filterItem.disconnect( this );
+               }
+
+               this.filterItem = filterItem;
+               this.filterItem.connect( this, { update: 'updateUiBasedOnModel' } );
+               this.updateUiBasedOnModel();
+       };
+
        /**
         * Respond to item model update event
         */
        mw.rcfilters.ui.HighlightColorPickerWidget.prototype.updateUiBasedOnModel = function () {
-               this.selectColor( this.model.getHighlightColor() || 'none' );
+               this.selectColor( this.filterItem.getHighlightColor() || 'none' );
        };
 
        /**
        mw.rcfilters.ui.HighlightColorPickerWidget.prototype.onChooseColor = function ( button ) {
                var color = button.data;
                if ( color === 'none' ) {
-                       this.controller.clearHighlightColor( this.model.getName() );
+                       this.controller.clearHighlightColor( this.filterItem.getName() );
                } else {
-                       this.controller.setHighlightColor( this.model.getName(), color );
+                       this.controller.setHighlightColor( this.filterItem.getName(), color );
                }
                this.emit( 'chooseColor', color );
        };
diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.HighlightPopupWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.HighlightPopupWidget.js
new file mode 100644 (file)
index 0000000..aedecc4
--- /dev/null
@@ -0,0 +1,63 @@
+( function ( mw, $ ) {
+       /**
+        * A popup containing a color picker, for setting highlight colors.
+        *
+        * @extends OO.ui.PopupWidget
+        *
+        * @constructor
+        * @param {mw.rcfilters.Controller} controller RCFilters controller
+        * @param {Object} [config] Configuration object
+        */
+       mw.rcfilters.ui.HighlightPopupWidget = function MwRcfiltersUiHighlightPopupWidget( controller, config ) {
+               config = config || {};
+
+               // Parent
+               mw.rcfilters.ui.HighlightPopupWidget.parent.call( this, $.extend( {
+                       autoClose: true,
+                       anchor: false,
+                       padded: true,
+                       align: 'backwards',
+                       horizontalPosition: 'end',
+                       width: 290
+               }, config ) );
+
+               this.colorPicker = new mw.rcfilters.ui.HighlightColorPickerWidget( controller );
+
+               this.colorPicker.connect( this, { chooseColor: 'onChooseColor' } );
+
+               this.$body.append( this.colorPicker.$element );
+       };
+
+       /* Initialization */
+
+       OO.inheritClass( mw.rcfilters.ui.HighlightPopupWidget, OO.ui.PopupWidget );
+
+       /* Methods */
+
+       /**
+        * Set the button (or other widget) that this popup should hang off.
+        *
+        * @param {OO.ui.Widget} widget Widget the popup should orient itself to
+        */
+       mw.rcfilters.ui.HighlightPopupWidget.prototype.setAssociatedButton = function ( widget ) {
+               this.setFloatableContainer( widget.$element );
+               this.$autoCloseIgnore = widget.$element;
+       };
+
+       /**
+        * Set the filter item that this popup should control the highlight color for.
+        *
+        * @param {mw.rcfilters.dm.FilterItem} item
+        */
+       mw.rcfilters.ui.HighlightPopupWidget.prototype.setFilterItem = function ( item ) {
+               this.colorPicker.setFilterItem( item );
+       };
+
+       /**
+        * When the user chooses a color in the color picker, close the popup.
+        */
+       mw.rcfilters.ui.HighlightPopupWidget.prototype.onChooseColor = function () {
+               this.toggle( false );
+       };
+
+}( mediaWiki, jQuery ) );
index 8c349e5..83d510b 100644 (file)
@@ -9,10 +9,11 @@
         * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel
         * @param {mw.rcfilters.dm.ItemModel} invertModel
         * @param {mw.rcfilters.dm.ItemModel} itemModel Item model
+        * @param {mw.rcfilters.ui.HighlightPopupWidget} highlightPopup Shared highlight color picker
         * @param {Object} config Configuration object
         */
        mw.rcfilters.ui.ItemMenuOptionWidget = function MwRcfiltersUiItemMenuOptionWidget(
-               controller, filtersViewModel, invertModel, itemModel, config
+               controller, filtersViewModel, invertModel, itemModel, highlightPopup, config
        ) {
                var layout,
                        classes = [],
@@ -55,6 +56,7 @@
                this.highlightButton = new mw.rcfilters.ui.FilterItemHighlightButton(
                        this.controller,
                        this.itemModel,
+                       highlightPopup,
                        {
                                $overlay: config.$overlay || this.$element,
                                title: mw.msg( 'rcfilters-highlightmenu-help' )
index d968f0c..04b7709 100644 (file)
 
                this.menuInitialized = true;
 
+               // Create shared popup for highlight buttons
+               this.highlightPopup = new mw.rcfilters.ui.HighlightPopupWidget( this.controller );
+               this.$overlay.append( this.highlightPopup.$element );
+
                // Count groups per view
                $.each( groups, function ( groupName, groupModel ) {
                        if ( !groupModel.isHidden() ) {
                                                        widget.model,
                                                        widget.model.getInvertModel(),
                                                        filterItem,
+                                                       widget.highlightPopup,
                                                        {
                                                                $overlay: widget.$overlay
                                                        }
index 0c13daf..a1646a8 100644 (file)
 }
 
 // We use the `:not` selector to cancel out styling on IE 8 and below
-// We also disable this styling on JavaScript disabled devices. This fixes the issue with
-// Opera Mini where checking/unchecking doesn't apply styling but potentially leaves other
-// more capable browsers with unstyled checkboxes.
-.client-js .mw-ui-checkbox:not( #noop ) {
+// Note: This may be broken on older Opera Mini devices.
+.mw-ui-checkbox:not( #noop ) {
        display: table;
        // Position relatively so we can make use of absolute pseudo elements
        position: relative;
diff --git a/resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js b/resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js
deleted file mode 100644 (file)
index 17da7d8..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*!
- * MediaWiki Widgets - CategoryCapsuleItemWidget class.
- *
- * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
- * @license The MIT License (MIT); see LICENSE.txt
- */
-( function ( $, mw ) {
-
-       var hasOwn = Object.prototype.hasOwnProperty;
-
-       /**
-        * @class mw.widgets.PageExistenceCache
-        * @private
-        * @param {mw.Api} [api]
-        */
-       function PageExistenceCache( api ) {
-               this.api = api || new mw.Api();
-               this.processExistenceCheckQueueDebounced = OO.ui.debounce( this.processExistenceCheckQueue );
-               this.currentRequest = null;
-               this.existenceCache = {};
-               this.existenceCheckQueue = {};
-       }
-
-       /**
-        * Check for existence of pages in the queue.
-        *
-        * @private
-        */
-       PageExistenceCache.prototype.processExistenceCheckQueue = function () {
-               var queue, titles,
-                       cache = this;
-               if ( this.currentRequest ) {
-                       // Don't fire off a million requests at the same time
-                       this.currentRequest.always( function () {
-                               cache.currentRequest = null;
-                               cache.processExistenceCheckQueueDebounced();
-                       } );
-                       return;
-               }
-               queue = this.existenceCheckQueue;
-               this.existenceCheckQueue = {};
-               titles = Object.keys( queue ).filter( function ( title ) {
-                       if ( hasOwn.call( cache.existenceCache, title ) ) {
-                               queue[ title ].resolve( cache.existenceCache[ title ] );
-                       }
-                       return !hasOwn.call( cache.existenceCache, title );
-               } );
-               if ( !titles.length ) {
-                       return;
-               }
-               this.currentRequest = this.api.get( {
-                       formatversion: 2,
-                       action: 'query',
-                       prop: [ 'info' ],
-                       titles: titles
-               } ).done( function ( response ) {
-                       var
-                               normalized = {},
-                               pages = {};
-                       $.each( response.query.normalized || [], function ( index, data ) {
-                               normalized[ data.fromencoded ? decodeURIComponent( data.from ) : data.from ] = data.to;
-                       } );
-                       $.each( response.query.pages, function ( index, page ) {
-                               pages[ page.title ] = !page.missing;
-                       } );
-                       titles.forEach( function ( title ) {
-                               var normalizedTitle = title;
-                               while ( hasOwn.call( normalized, normalizedTitle ) ) {
-                                       normalizedTitle = normalized[ normalizedTitle ];
-                               }
-                               cache.existenceCache[ title ] = pages[ normalizedTitle ];
-                               queue[ title ].resolve( cache.existenceCache[ title ] );
-                       } );
-               } );
-       };
-
-       /**
-        * Register a request to check whether a page exists.
-        *
-        * @private
-        * @param {mw.Title} title
-        * @return {jQuery.Promise} Promise resolved with true if the page exists or false otherwise
-        */
-       PageExistenceCache.prototype.checkPageExistence = function ( title ) {
-               var key = title.getPrefixedText();
-               if ( !hasOwn.call( this.existenceCheckQueue, key ) ) {
-                       this.existenceCheckQueue[ key ] = $.Deferred();
-               }
-               this.processExistenceCheckQueueDebounced();
-               return this.existenceCheckQueue[ key ].promise();
-       };
-
-       /**
-        * @class mw.widgets.ForeignTitle
-        * @private
-        * @extends mw.Title
-        *
-        * @constructor
-        * @param {string} title
-        * @param {number} [namespace]
-        */
-       function ForeignTitle( title, namespace ) {
-               // We only need to handle categories here... but we don't know the target language.
-               // So assume that any namespace-like prefix is the 'Category' namespace...
-               title = title.replace( /^(.+?)_*:_*(.*)$/, 'Category:$2' ); // HACK
-               ForeignTitle.parent.call( this, title, namespace );
-       }
-       OO.inheritClass( ForeignTitle, mw.Title );
-       ForeignTitle.prototype.getNamespacePrefix = function () {
-               // We only need to handle categories here...
-               return 'Category:'; // HACK
-       };
-
-       /**
-        * Category selector capsule item widget. Extends OO.ui.CapsuleItemWidget with the ability to link
-        * to the given page, and to show its existence status (i.e., whether it is a redlink).
-        *
-        * @class mw.widgets.CategoryCapsuleItemWidget
-        * @uses mw.Api
-        * @extends OO.ui.CapsuleItemWidget
-        *
-        * @constructor
-        * @param {Object} config Configuration options
-        * @cfg {mw.Title} title Page title to use (required)
-        * @cfg {string} [apiUrl] API URL, if not the current wiki's API
-        */
-       mw.widgets.CategoryCapsuleItemWidget = function MWWCategoryCapsuleItemWidget( config ) {
-               var widget = this;
-               // Parent constructor
-               mw.widgets.CategoryCapsuleItemWidget.parent.call( this, $.extend( {
-                       data: config.title.getMainText(),
-                       label: config.title.getMainText()
-               }, config ) );
-
-               // Properties
-               this.title = config.title;
-               this.apiUrl = config.apiUrl || '';
-               this.$link = $( '<a>' )
-                       .text( this.label )
-                       .attr( 'target', '_blank' )
-                       .on( 'click', function ( e ) {
-                               // CapsuleMultiselectWidget really wants to prevent you from clicking the link, don't let it
-                               e.stopPropagation();
-                       } );
-
-               // Initialize
-               this.setMissing( false );
-               this.$label.replaceWith( this.$link );
-               this.setLabelElement( this.$link );
-
-               if ( !this.constructor.static.pageExistenceCaches[ this.apiUrl ] ) {
-                       this.constructor.static.pageExistenceCaches[ this.apiUrl ] =
-                               new PageExistenceCache( new mw.ForeignApi( this.apiUrl ) );
-               }
-               this.constructor.static.pageExistenceCaches[ this.apiUrl ]
-                       .checkPageExistence( new ForeignTitle( this.title.getPrefixedText() ) )
-                       .done( function ( exists ) {
-                               widget.setMissing( !exists );
-                       } );
-       };
-
-       /* Setup */
-
-       OO.inheritClass( mw.widgets.CategoryCapsuleItemWidget, OO.ui.CapsuleItemWidget );
-
-       /* Static Properties */
-
-       /**
-        * Map of API URLs to PageExistenceCache objects.
-        *
-        * @static
-        * @inheritable
-        * @property {Object}
-        */
-       mw.widgets.CategoryCapsuleItemWidget.static.pageExistenceCaches = {
-               '': new PageExistenceCache()
-       };
-
-       /* Methods */
-
-       /**
-        * Update label link href and CSS classes to reflect page existence status.
-        *
-        * @private
-        * @param {boolean} missing Whether the page is missing (does not exist)
-        */
-       mw.widgets.CategoryCapsuleItemWidget.prototype.setMissing = function ( missing ) {
-               var
-                       title = new ForeignTitle( this.title.getPrefixedText() ), // HACK
-                       prefix = this.apiUrl.replace( '/w/api.php', '' ); // HACK
-
-               this.missing = missing;
-
-               if ( !missing ) {
-                       this.$link
-                               .attr( 'href', prefix + title.getUrl() )
-                               .attr( 'title', title.getPrefixedText() )
-                               .removeClass( 'new' );
-               } else {
-                       this.$link
-                               .attr( 'href', prefix + title.getUrl( { action: 'edit', redlink: 1 } ) )
-                               .attr( 'title', mw.msg( 'red-link-title', title.getPrefixedText() ) )
-                               .addClass( 'new' );
-               }
-       };
-
-}( jQuery, mediaWiki ) );
index 354fcd9..c506379 100644 (file)
@@ -9,7 +9,7 @@
                NS_CATEGORY = mw.config.get( 'wgNamespaceIds' ).category;
 
        /**
-        * Category selector widget. Displays an OO.ui.CapsuleMultiselectWidget
+        * Category selector widget. Displays an OO.ui.MenuTagMultiselectWidget
         * and autocompletes with available categories.
         *
         *     mw.loader.using( 'mediawiki.widgets.CategoryMultiselectWidget', function () {
@@ -27,7 +27,7 @@
         *
         * @class mw.widgets.CategoryMultiselectWidget
         * @uses mw.Api
-        * @extends OO.ui.CapsuleMultiselectWidget
+        * @extends OO.ui.MenuTagMultiselectWidget
         * @mixins OO.ui.mixin.PendingElement
         *
         * @constructor
@@ -62,7 +62,7 @@
                OO.ui.mixin.PendingElement.call( this, $.extend( {}, config, { $pending: this.$handle } ) );
 
                // Event handler to call the autocomplete methods
-               this.$input.on( 'change input cut paste', OO.ui.debounce( this.updateMenuItems.bind( this ), 100 ) );
+               this.input.$input.on( 'change input cut paste', OO.ui.debounce( this.updateMenuItems.bind( this ), 100 ) );
 
                // Initialize
                this.api = config.api || new mw.Api();
@@ -71,7 +71,7 @@
 
        /* Setup */
 
-       OO.inheritClass( mw.widgets.CategoryMultiselectWidget, OO.ui.CapsuleMultiselectWidget );
+       OO.inheritClass( mw.widgets.CategoryMultiselectWidget, OO.ui.MenuTagMultiselectWidget );
        OO.mixinClass( mw.widgets.CategoryMultiselectWidget, OO.ui.mixin.PendingElement );
 
        /* Methods */
         */
        mw.widgets.CategoryMultiselectWidget.prototype.updateMenuItems = function () {
                this.getMenu().clearItems();
-               this.getNewMenuItems( this.$input.val() ).then( function ( items ) {
+               this.getNewMenuItems( this.input.$input.val() ).then( function ( items ) {
                        var existingItems, filteredItems,
                                menu = this.getMenu();
 
                        // Never show the menu if the input lost focus in the meantime
-                       if ( !this.$input.is( ':focus' ) ) {
+                       if ( !this.input.$input.is( ':focus' ) ) {
                                return;
                        }
 
        /**
         * @inheritdoc
         */
-       mw.widgets.CategoryMultiselectWidget.prototype.createItemWidget = function ( data ) {
+       mw.widgets.CategoryMultiselectWidget.prototype.createTagItemWidget = function ( data ) {
                var title = mw.Title.makeTitle( NS_CATEGORY, data );
-               if ( !title ) {
-                       return null;
-               }
-               return new mw.widgets.CategoryCapsuleItemWidget( {
+
+               return new mw.widgets.CategoryTagItemWidget( {
                        apiUrl: this.api.apiUrl || undefined,
                        title: title
                } );
         */
        mw.widgets.CategoryMultiselectWidget.prototype.findItemFromData = function ( data ) {
                // This is a bit of a hack... We have to canonicalize the data in the same way that
-               // #createItemWidget and CategoryCapsuleItemWidget will do, otherwise we won't find duplicates.
+               // #createItemWidget and CategoryTagItemWidget will do, otherwise we won't find duplicates.
                var title = mw.Title.makeTitle( NS_CATEGORY, data );
                if ( !title ) {
                        return null;
diff --git a/resources/src/mediawiki.widgets/mw.widgets.CategoryTagItemWidget.js b/resources/src/mediawiki.widgets/mw.widgets.CategoryTagItemWidget.js
new file mode 100644 (file)
index 0000000..f0b2d44
--- /dev/null
@@ -0,0 +1,209 @@
+/*!
+ * MediaWiki Widgets - CategoryTagItemWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+       var hasOwn = Object.prototype.hasOwnProperty;
+
+       /**
+        * @class mw.widgets.PageExistenceCache
+        * @private
+        * @param {mw.Api} [api]
+        */
+       function PageExistenceCache( api ) {
+               this.api = api || new mw.Api();
+               this.processExistenceCheckQueueDebounced = OO.ui.debounce( this.processExistenceCheckQueue );
+               this.currentRequest = null;
+               this.existenceCache = {};
+               this.existenceCheckQueue = {};
+       }
+
+       /**
+        * Check for existence of pages in the queue.
+        *
+        * @private
+        */
+       PageExistenceCache.prototype.processExistenceCheckQueue = function () {
+               var queue, titles,
+                       cache = this;
+               if ( this.currentRequest ) {
+                       // Don't fire off a million requests at the same time
+                       this.currentRequest.always( function () {
+                               cache.currentRequest = null;
+                               cache.processExistenceCheckQueueDebounced();
+                       } );
+                       return;
+               }
+               queue = this.existenceCheckQueue;
+               this.existenceCheckQueue = {};
+               titles = Object.keys( queue ).filter( function ( title ) {
+                       if ( hasOwn.call( cache.existenceCache, title ) ) {
+                               queue[ title ].resolve( cache.existenceCache[ title ] );
+                       }
+                       return !hasOwn.call( cache.existenceCache, title );
+               } );
+               if ( !titles.length ) {
+                       return;
+               }
+               this.currentRequest = this.api.get( {
+                       formatversion: 2,
+                       action: 'query',
+                       prop: [ 'info' ],
+                       titles: titles
+               } ).done( function ( response ) {
+                       var
+                               normalized = {},
+                               pages = {};
+                       $.each( response.query.normalized || [], function ( index, data ) {
+                               normalized[ data.fromencoded ? decodeURIComponent( data.from ) : data.from ] = data.to;
+                       } );
+                       $.each( response.query.pages, function ( index, page ) {
+                               pages[ page.title ] = !page.missing;
+                       } );
+                       titles.forEach( function ( title ) {
+                               var normalizedTitle = title;
+                               while ( hasOwn.call( normalized, normalizedTitle ) ) {
+                                       normalizedTitle = normalized[ normalizedTitle ];
+                               }
+                               cache.existenceCache[ title ] = pages[ normalizedTitle ];
+                               queue[ title ].resolve( cache.existenceCache[ title ] );
+                       } );
+               } );
+       };
+
+       /**
+        * Register a request to check whether a page exists.
+        *
+        * @private
+        * @param {mw.Title} title
+        * @return {jQuery.Promise} Promise resolved with true if the page exists or false otherwise
+        */
+       PageExistenceCache.prototype.checkPageExistence = function ( title ) {
+               var key = title.getPrefixedText();
+               if ( !hasOwn.call( this.existenceCheckQueue, key ) ) {
+                       this.existenceCheckQueue[ key ] = $.Deferred();
+               }
+               this.processExistenceCheckQueueDebounced();
+               return this.existenceCheckQueue[ key ].promise();
+       };
+
+       /**
+        * @class mw.widgets.ForeignTitle
+        * @private
+        * @extends mw.Title
+        *
+        * @constructor
+        * @param {string} title
+        * @param {number} [namespace]
+        */
+       function ForeignTitle( title, namespace ) {
+               // We only need to handle categories here... but we don't know the target language.
+               // So assume that any namespace-like prefix is the 'Category' namespace...
+               title = title.replace( /^(.+?)_*:_*(.*)$/, 'Category:$2' ); // HACK
+               ForeignTitle.parent.call( this, title, namespace );
+       }
+       OO.inheritClass( ForeignTitle, mw.Title );
+       ForeignTitle.prototype.getNamespacePrefix = function () {
+               // We only need to handle categories here...
+               return 'Category:'; // HACK
+       };
+
+       /**
+        * Category selector capsule item widget. Extends OO.ui.CapsuleItemWidget with the ability to link
+        * to the given page, and to show its existence status (i.e., whether it is a redlink).
+        *
+        * @class mw.widgets.CategoryTagItemWidget
+        * @uses mw.Api
+        * @extends OO.ui.TagItemWidget
+        *
+        * @constructor
+        * @param {Object} config Configuration options
+        * @cfg {mw.Title} title Page title to use (required)
+        * @cfg {string} [apiUrl] API URL, if not the current wiki's API
+        */
+       mw.widgets.CategoryTagItemWidget = function MWWCategoryTagItemWidget( config ) {
+               var widget = this;
+               // Parent constructor
+               mw.widgets.CategoryTagItemWidget.parent.call( this, $.extend( {
+                       data: config.title.getMainText(),
+                       label: config.title.getMainText()
+               }, config ) );
+
+               // Properties
+               this.title = config.title;
+               this.apiUrl = config.apiUrl || '';
+               this.$link = $( '<a>' )
+                       .text( this.label )
+                       .attr( 'target', '_blank' )
+                       .on( 'click', function ( e ) {
+                               // TagMultiselectWidget really wants to prevent you from clicking the link, don't let it
+                               e.stopPropagation();
+                       } );
+
+               // Initialize
+               this.setMissing( false );
+               this.$label.replaceWith( this.$link );
+               this.setLabelElement( this.$link );
+
+               if ( !this.constructor.static.pageExistenceCaches[ this.apiUrl ] ) {
+                       this.constructor.static.pageExistenceCaches[ this.apiUrl ] =
+                               new PageExistenceCache( new mw.ForeignApi( this.apiUrl ) );
+               }
+               this.constructor.static.pageExistenceCaches[ this.apiUrl ]
+                       .checkPageExistence( new ForeignTitle( this.title.getPrefixedText() ) )
+                       .done( function ( exists ) {
+                               widget.setMissing( !exists );
+                       } );
+       };
+
+       /* Setup */
+
+       OO.inheritClass( mw.widgets.CategoryTagItemWidget, OO.ui.TagItemWidget );
+
+       /* Static Properties */
+
+       /**
+        * Map of API URLs to PageExistenceCache objects.
+        *
+        * @static
+        * @inheritable
+        * @property {Object}
+        */
+       mw.widgets.CategoryTagItemWidget.static.pageExistenceCaches = {
+               '': new PageExistenceCache()
+       };
+
+       /* Methods */
+
+       /**
+        * Update label link href and CSS classes to reflect page existence status.
+        *
+        * @private
+        * @param {boolean} missing Whether the page is missing (does not exist)
+        */
+       mw.widgets.CategoryTagItemWidget.prototype.setMissing = function ( missing ) {
+               var
+                       title = new ForeignTitle( this.title.getPrefixedText() ), // HACK
+                       prefix = this.apiUrl.replace( '/w/api.php', '' ); // HACK
+
+               this.missing = missing;
+
+               if ( !missing ) {
+                       this.$link
+                               .attr( 'href', prefix + title.getUrl() )
+                               .attr( 'title', title.getPrefixedText() )
+                               .removeClass( 'new' );
+               } else {
+                       this.$link
+                               .attr( 'href', prefix + title.getUrl( { action: 'edit', redlink: 1 } ) )
+                               .attr( 'title', mw.msg( 'red-link-title', title.getPrefixedText() ) )
+                               .addClass( 'new' );
+               }
+       };
+
+       // For backwards compatibility. See T183299.
+       mw.widgets.CategoryCapsuleItemWidget = mw.widgets.CategoryTagItemWidget;
+}( jQuery, mediaWiki ) );
index f68f595..2089f64 100644 (file)
@@ -41,7 +41,8 @@ class DbTestRecorder extends TestRecorder {
                        || !$this->db->tableExists( 'testitem' )
                ) {
                        print "WARNING> `testrun` table not found in database. Trying to create table.\n";
-                       $this->db->sourceFile( $this->db->patchPath( 'patch-testrun.sql' ) );
+                       $updater = DatabaseUpdater::newForDB( $this->db );
+                       $this->db->sourceFile( $updater->patchPath( $this->db, 'patch-testrun.sql' ) );
                        echo "OK, resuming.\n";
                }
 
index afddd78..e06a732 100644 (file)
@@ -257,7 +257,7 @@ Weirdo titles!
 !!article
 Template:Bullet
 !!text
-* Bar
+*Bar
 !!endarticle
 
 !!article
@@ -327,23 +327,31 @@ This is a simple paragraph.
 !! test
 Paragraphs with extra newline spacing
 !! wikitext
-foo
+a
 
-bar
+b (+2 nls)
 
 
-baz
+c (+3 nls)
+
+
+
+d (+4 nls)
+
 
 
 
-booz
+e (+5 nls)
 !! html
-<p>foo
-</p><p>bar
+<p>a
+</p><p>b (+2 nls)
 </p><p><br />
-baz
+c (+3 nls)
 </p><p><br />
-</p><p>booz
+</p><p>d (+4 nls)
+</p><p><br />
+</p><p><br />
+e (+5 nls)
 </p>
 !! end
 
@@ -515,7 +523,6 @@ Extra newlines followed by heading
 a
 
 
-
 =b=
 [[a]]
 
@@ -534,19 +541,89 @@ a
 !! end
 
 !! test
-Extra newlines between heading and content are swallowed
+Extra newlines between heading and content are swallowed (Parsoid does not)
 !! wikitext
 =b=
 
 
 
 [[a]]
-!! html
+!! html/php+tidy
 <h1><span class="mw-headline" id="b">b</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: b">edit</a><span class="mw-editsection-bracket">]</span></span></h1>
 <p><a href="/index.php?title=A&amp;action=edit&amp;redlink=1" class="new" title="A (page does not exist)">a</a>
 </p>
+!! html/parsoid
+<h1 id="b">b</h1>
+<p>
+<br></p>
+
+<p><a rel="mw:WikiLink" href="./A" title="A">a</a></p>
+!! end
+
+!! test
+Extra new lines before and after lists are preserved
+!! wikitext
+a
+
+
+*b
+
+
+c
+!! html/php+tidy
+<p>a
+</p><p><br />
+</p>
+<ul><li>b</li></ul>
+<p><br />
+c
+</p>
+!! html/parsoid
+<p>a</p>
+<p>
+<br></p>
+<ul><li>b</li></ul>
+<p>
+<br>
+c</p>
 !! end
 
+# Parsoid regression test
+!!test
+Multiple newlines after tables are converted to p-br-p tags
+!!options
+parsoid=wt2html,wt2wt
+!!wikitext
+{|
+|x
+|}
+
+
+
+
+=b=
+!!html/php+tidy
+<table>
+<tbody><tr>
+<td>x
+</td></tr></tbody></table>
+<p><br />
+</p><p><br />
+</p>
+<h1><span class="mw-headline" id="b">b</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: b">edit</a><span class="mw-editsection-bracket">]</span></span></h1>
+!!html/parsoid
+<table>
+<tbody>
+<tr>
+<td>x</td>
+</tr>
+</tbody>
+</table>
+<p><br/></p>
+<p><br/></p>
+<h1 id="b">b</h1>
+!!end
+
 !! test
 Heading with line break in nowiki
 !! options
@@ -2695,12 +2772,9 @@ parsoid=wt2html
 <pre>x</pre>
 &lt;pre <table></table>
 !! html/parsoid
-<pre about="#mwt1" typeof="mw:Transclusion mw:Extension/pre" data-parsoid='{"a":{"&lt;pre":null},"sa":{"&lt;pre":""},"stx":"html","pi":[[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&lt;pre &lt;pre>x&lt;/pre>"}},"i":0}}]}'>x</pre>
-
-
-<p>&lt;pre </p>
+<pre typeof="mw:Transclusion mw:Extension/pre" about="#mwt2" data-parsoid='{"stx":"html","a":{"&lt;pre":null},"sa":{"&lt;pre":""},"pi":[[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&lt;pre &lt;pre>x&lt;/pre>"}},"i":0}}]}'>x</pre>
 
-<table></table>
+<span data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true}'>&lt;pre </span><table data-parsoid='{"stx":"html"}'></table>
 !! end
 
 !! test
@@ -3311,6 +3385,57 @@ a
 
 !! end
 
+!! test
+2h. Indent pre in tables
+!! options
+parsoid=wt2html,html2html
+!! wikitext
+{|
+ !
+ foo
+ !
+ bar
+ |-
+ |
+ baz
+ {{!}}
+ bam
+ |}
+!! html/php
+<table>
+<tr>
+<th>
+<pre>foo
+</pre>
+</th>
+<th>
+<pre>bar
+</pre>
+</th></tr>
+<tr>
+<td>
+<pre>baz
+</pre>
+</td>
+<td>
+<pre>bam
+</pre>
+</td></tr></table>
+
+!! html/parsoid
+<table>
+ <tbody><tr><th>
+<pre>foo</pre>
+</th><th>
+<pre>bar</pre>
+</th></tr><tr>
+ <td>
+<pre>baz</pre>
+</td><td data-parsoid='{"startTagSrc":"{{!}}"}'>
+<pre>bam</pre>
+</td></tr></tbody></table>
+!! end
+
 !!test
 3a. Indent-Pre and block tags (single-line html)
 !! wikitext
 </pre>
 !! end
 
-!!test
+!! test
 3b. Indent-Pre and block tags (multi-line html)
 !! wikitext
  a <span>foo</span>
- b <div> foo </div>
-!! html
+<!-- comment --> b <div> foo </div>
+!! html/php
 <pre>a <span>foo</span>
 </pre>
  b <div> foo </div>
 
 !! html/parsoid
 <pre>a <span data-parsoid='{"stx":"html"}'>foo</span></pre>
- b <div data-parsoid='{"stx":"html"}'> foo </div>
+<!-- comment --> <p>b </p><div data-parsoid='{"stx":"html"}'> foo </div>
 !! html/php+tidy
 <pre>a <span>foo</span>
 </pre><p>
  b </p><div> foo </div>
-!!end
+!! end
 
 !!test
 3c. Indent-Pre and block tags (pre-content on separate line)
@@ -3802,7 +3927,7 @@ Definition list with bracketed URL link
 !! test
 Definition list with wikilink containing colon
 !! wikitext
-; [[Help:FAQ]]:The least-read page on Wikipedia
+;[[Help:FAQ]]:The least-read page on Wikipedia
 !! html
 <dl><dt><a href="/index.php?title=Help:FAQ&amp;action=edit&amp;redlink=1" class="new" title="Help:FAQ (page does not exist)">Help:FAQ</a></dt>
 <dd>The least-read page on Wikipedia</dd></dl>
@@ -3813,19 +3938,19 @@ Definition list with wikilink containing colon
 !! test
 Definition list with news link containing colon
 !! wikitext
-;news:alt.wikipedia.roxThis isn't even a real newsgroup!
+;news:alt.wikipedia.rox :This isn't even a real newsgroup!
 !! html/php
-<dl><dt><a rel="nofollow" class="external free" href="news:alt.wikipedia.rox">news:alt.wikipedia.rox</a></dt>
+<dl><dt><a rel="nofollow" class="external free" href="news:alt.wikipedia.rox">news:alt.wikipedia.rox</a>&#160;</dt>
 <dd>This isn't even a real newsgroup!</dd></dl>
 
 !! html/parsoid
-<dl><dt>  <a rel="mw:ExtLink" class="external free" href="news:alt.wikipedia.rox" data-parsoid='{"stx":"url"}'>news:alt.wikipedia.rox</a></dt><dd data-parsoid='{"stx":"row"}'>This isn't even a real newsgroup!</dd></dl>
+<dl><dt><a rel="mw:ExtLink" class="external free" href="news:alt.wikipedia.rox" data-parsoid='{"stx":"url"}'>news:alt.wikipedia.rox</a></dt><dd data-parsoid='{"stx":"row"}'>This isn't even a real newsgroup!</dd></dl>
 !! end
 
 !! test
 Malformed definition list with colon
 !! wikitext
-;  news:alt.wikipedia.rox -- don't crash or enter an infinite loop
+;news:alt.wikipedia.rox -- don't crash or enter an infinite loop
 !! html
 <dl><dt><a rel="nofollow" class="external free" href="news:alt.wikipedia.rox">news:alt.wikipedia.rox</a> -- don't crash or enter an infinite loop</dt></dl>
 
@@ -4057,6 +4182,8 @@ should be left alone</p>
 
 !! test
 Definition Lists: Hacky use to indent tables, with comment before table
+!!options
+parsoid=wt2html
 !! wikitext
 ::<!-- foo -->{|
 |foo
@@ -4072,7 +4199,7 @@ Definition Lists: Hacky use to indent tables, with comment before table
 !! test
 Definition Lists: Hacky use to indent tables (WS-insensitive)
 !! wikitext
-: {|
+:{|
 |a
 |} 
 !! html/php
@@ -4082,9 +4209,9 @@ Definition Lists: Hacky use to indent tables (WS-insensitive)
 </td></tr></table></dd></dl>
 
 !! html/parsoid
-<dl><dd> <table>
+<dl><dd><table>
 <tbody><tr><td>a</td></tr>
-</tbody></table> </dd></dl>
+</tbody></table></dd></dl>
 !! end
 
 ## The PHP parser treats : items (dd) without a corresponding ; item (dt)
@@ -5020,7 +5147,7 @@ URL in text: [http://example.com http://example.com]
 <p>URL in text: <a rel="nofollow" class="external text" href="http://example.com">http://example.com</a>
 </p>
 !! html/parsoid
-<p>URL in text: <a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a></p>
+<p>URL in text: <a rel="mw:ExtLink" class="external text" href="http://example.com">http://example.com</a></p>
 !! end
 
 !! test
@@ -5663,7 +5790,7 @@ Examples from RFC 2732, section 2:
 !! html/parsoid
 <p><a rel="mw:ExtLink" class="external free" href="http://[2404:130:0:1000::187:2]/index.php">http://[2404:130:0:1000::187:2]/index.php</a></p>
 
-<p>Examples from <a href="https://tools.ietf.org/html/rfc2373" rel="mw:ExtLink" class="external text">RFC 2373</a>, section 2.2:</p>
+<p>Examples from <a href="https://tools.ietf.org/html/rfc2373" rel="mw:ExtLink" class="external mw-magiclink">RFC 2373</a>, section 2.2:</p>
 <ul><li><a rel="mw:ExtLink" class="external free" href="http://[1080::8:800:200C:417A]/unicast">http://[1080::8:800:200C:417A]/unicast</a></li>
 <li><a rel="mw:ExtLink" class="external free" href="http://[FF01::101]/multicast">http://[FF01::101]/multicast</a></li>
 <li><a rel="mw:ExtLink" class="external free" href="http://[::1]/loopback">http://[::1]/loopback</a></li>
@@ -5671,7 +5798,7 @@ Examples from RFC 2732, section 2:
 <li><a rel="mw:ExtLink" class="external free" href="http://[::13.1.68.3]/ipv4compat">http://[::13.1.68.3]/ipv4compat</a></li>
 <li><a rel="mw:ExtLink" class="external free" href="http://[::FFFF:129.144.52.38]/ipv4compat">http://[::FFFF:129.144.52.38]/ipv4compat</a></li></ul>
 
-<p>Examples from <a href="https://tools.ietf.org/html/rfc2732" rel="mw:ExtLink" class="external text">RFC 2732</a>, section 2:</p>
+<p>Examples from <a href="https://tools.ietf.org/html/rfc2732" rel="mw:ExtLink" class="external mw-magiclink">RFC 2732</a>, section 2:</p>
 <ul><li><a rel="mw:ExtLink" class="external free" href="http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html">http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html</a></li>
 <li><a rel="mw:ExtLink" class="external free" href="http://[1080:0:0:0:8:800:200C:417A]/index.html">http://[1080:0:0:0:8:800:200C:417A]/index.html</a></li>
 <li><a rel="mw:ExtLink" class="external free" href="http://[3ffe:2a00:100:7031::1]">http://[3ffe:2a00:100:7031::1]</a></li>
@@ -5727,7 +5854,7 @@ Examples from RFC 2732, section 2:
 !! html/parsoid
 <p><a rel="mw:ExtLink" class="external text" href="http://[2404:130:0:1000::187:2]/index.php">test</a></p>
 
-<p>Examples from <a href="https://tools.ietf.org/html/rfc2373" rel="mw:ExtLink" class="external text">RFC 2373</a>, section 2.2:</p>
+<p>Examples from <a href="https://tools.ietf.org/html/rfc2373" rel="mw:ExtLink" class="external mw-magiclink">RFC 2373</a>, section 2.2:</p>
 <ul><li><a rel="mw:ExtLink" class="external text" href="http://[1080::8:800:200C:417A]">unicast</a></li>
 <li><a rel="mw:ExtLink" class="external text" href="http://[FF01::101]">multicast</a></li>
 <li><a rel="mw:ExtLink" class="external text" href="http://[::1]/">loopback</a></li>
@@ -5735,7 +5862,7 @@ Examples from RFC 2732, section 2:
 <li><a rel="mw:ExtLink" class="external text" href="http://[::13.1.68.3]">ipv4compat</a></li>
 <li><a rel="mw:ExtLink" class="external text" href="http://[::FFFF:129.144.52.38]">ipv4compat</a></li></ul>
 
-<p>Examples from <a href="https://tools.ietf.org/html/rfc2732" rel="mw:ExtLink" class="external text">RFC 2732</a>, section 2:</p>
+<p>Examples from <a href="https://tools.ietf.org/html/rfc2732" rel="mw:ExtLink" class="external mw-magiclink">RFC 2732</a>, section 2:</p>
 <ul><li><a rel="mw:ExtLink" class="external text" href="http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html">1</a></li>
 <li><a rel="mw:ExtLink" class="external text" href="http://[1080:0:0:0:8:800:200C:417A]/index.html">2</a></li>
 <li><a rel="mw:ExtLink" class="external text" href="http://[3ffe:2a00:100:7031::1]">3</a></li>
@@ -6085,7 +6212,7 @@ A table with nothing but a caption
 A table with caption with default-spaced attributes and a table row
 !! wikitext
 {|
-|+ style="color: red;" | caption1
+|+ style="color: red;" |caption1
 |-
 |foo
 |}
@@ -6369,8 +6496,8 @@ Accept "!!" in table data of mixed wikitext / html syntax
 Accept empty attributes in td/th cells (td/th cells starting with leading ||)
 !! wikitext
 {|
-!| h1
-|| a
+!|h1
+||a
 |}
 !! html
 <table>
@@ -6515,9 +6642,9 @@ Invalid attributes in table cell (T3830)
 Table cell attributes: Pipes protected by nowikis should be treated as a plain character
 !! wikitext
 {|
-| title="foo" |bar
-| title="foo<nowiki>|</nowiki>" |bar
-| title="foo<nowiki>|</nowiki>" bar
+|title="foo" |bar
+|title="foo<nowiki>|</nowiki>" |bar
+|title="foo<nowiki>|</nowiki>" bar
 |}
 !! html/php
 <table>
@@ -6589,7 +6716,7 @@ Element attributes with double ! should not be broken up by <th>
 !! html/php
 <table>
 <tr>
-<td><div style="color: red !important;" data-contrived="put this here &#124;&#124;">hi</div>
+<td><div style="color: red&#32;!important;" data-contrived="put this here &#124;&#124;">hi</div>
 </td></tr></table>
 
 !! html/parsoid
@@ -6610,7 +6737,7 @@ parsoid=wt2html
 !! html/php
 <table>
 <tr>
-<td>style="color: red !important;" data-contrived="put this here</td>
+<td>style="color: red&#160;!important;" data-contrived="put this here</td>
 <td>foo
 </td></tr></table>
 
@@ -6699,8 +6826,8 @@ parsoid={
 |}
 !! wikitext/edited
 {| <span>boo</span> style='border:1px solid black'
-|  <span>boo</span> style='color:blue'  |abc
-|<span>boo</span> style='color:blue'|xyz
+|  <span>boo</span> style='color:blue'  | abc
+|<span>boo</span> style='color:blue'| xyz
 |}
 !! end
 
@@ -6952,7 +7079,7 @@ b
 Table cell with a single comment
 !! wikitext
 {|
-| <!-- c1 -->
+|<!-- c1 -->
 |a
 |}
 !! html
@@ -7211,18 +7338,6 @@ parsoid=html2wt
 '''quux'''
 !! end
 
-!! test
-Parsoid: newline inducing block nodes don't suppress <nowiki>
-!! options
-parsoid=html2wt
-!! html/parsoid
- a<h1>foo</h1>
-!! wikitext
-<nowiki> </nowiki>a
-
-= foo =
-!! end
-
 !! test
 Parsoid: Row-syntax table headings followed by comment & table cells
 !! options
@@ -7244,8 +7359,8 @@ parsoid=wt2html,wt2wt
 
 !! html/parsoid
 <table>
-<tbody><tr><th> foo </th><th> bar
-<!-- foo -->  </th><td> baz </td><td> quux</td></tr>
+<tbody><tr><th>foo</th><th>bar
+<!-- foo --></th><td> baz </td><td>quux</td></tr>
 </tbody></table>
 !! end
 
@@ -7290,6 +7405,22 @@ parsoid=wt2html
 </tbody></table>
 !! end
 
+!! test
+Table with missing opening <tr> tag
+!! options
+parsoid=wt2html,wt2wt
+!! wikitext
+<table>
+<td>foo</td>
+</tr>
+</table>
+!! html+tidy
+<table>
+<tbody><tr><td>foo</td>
+</tr>
+</tbody></table>
+!! end
+
 # T137406: Whitespace in the HTML
 !! test
 1. Generate correct wikitext for tables with thead/tbody/tfoot
@@ -7377,97 +7508,6 @@ parsoid=html2wt
 |}
 !! end
 
-!! test
-Testing serialization after deletion in references
-!! options
-parsoid={
-  "modes": ["wt2wt"],
-  "changes": [
-    ["#x", "remove"]
-  ]
-}
-!! wikitext
-hi <ref><div id="x">ho</div></ref>
-
-<references />
-!! wikitext/edited
-hi <ref></ref>
-
-<references />
-!! end
-
-!!test
-Testing serialization after deletion of table cells
-!!options
-parsoid={
-  "modes": ["wt2wt", "selser"],
-  "changes": [
-    ["#x", "remove"]
-  ]
-}
-!!wikitext
-{|
-!h1 !!h2 !!h3
-| id="x" |c1 {{!}}{{!}}{{!}}c2 |||c3
-|}
-!! wikitext/edited
-{|
-!h1 !!h2 !!h3
-|c2 |||c3
-|}
-!!end
-
-!! test
-Testing selser after addition of new row before first row (T125419)
-!! options
-parsoid={
-  "modes": ["wt2wt", "selser"],
-  "changes": [
-    [ "tr", "before", "<tr><td>X</td></tr>" ]
-  ]
-}
-!! wikitext
-{|
-|a
-|}
-!! wikitext/edited
-{|
-|X
-|-
-|a
-|}
-!! end
-
-!! test
-Serialize new table rows in a HTML table using HTML tags
-!! options
-parsoid={
-  "modes": ["wt2wt", "selser"],
-  "changes": [
-    [ "tr", "before", "<tr><td>X</td></tr>" ]
-  ]
-}
-!! wikitext
-<table><tr><td>a</td></tr></table>
-!! wikitext/edited
-<table><tr><td>X</td></tr><tr><td>a</td></tr></table>
-!! end
-
-!! test
-Serialize new table cells in a HTML row using HTML tags
-!! options
-parsoid={
-  "modes": ["wt2wt", "selser"],
-  "changes": [
-    [ "td", "before", "<td>X</td>" ]
-  ]
-}
-!! wikitext
-<table><tr><td>a</td></tr></table>
-!! wikitext/edited
-<table><tr><td>X</td><td>a</td></tr></table>
-!! end
-
 !! test
 Wikitext tables can be nested inside HTML tables
 !! options
@@ -7490,63 +7530,13 @@ parsoid=html2wt
 </table>
 !! end
 
+###
+### Internal links
+###
 !! test
-Serialize wikitext list items as HTML list items when embedded in a HTML list
-!! options
-parsoid=html2wt
-!! html
-<ul data-parsoid='{"stx": "html"}'>
-<li data-parsoid='{}'>a</li>
-<li>b</li>
-</ul>
-!! wikitext
-<ul>
-<li>a</li>
-<li>b</li>
-</ul>
-!! end
-
-# SSS FIXME: Is this actually a good thing given the
-# odd nested list output that is generated by MW?
-# <ul><li>foo<ul>..</ul></li></ul> instead of
-# <ul><li>foo</li><ul>..</ul></ul>
-!! test
-Wikitext lists can be nested inside HTML lists
-!! options
-parsoid=html2wt
-!! html
-<ul data-parsoid='{"stx": "html"}'>
-<li data-parsoid='{"stx": "html"}'>a
-<ul><li>b</li></ul>
-</li>
-</ul>
-
-<ul data-parsoid='{"stx": "html"}'>
-<li>x
-<ul><li>y</li></ul>
-</li>
-</ul>
-!! wikitext
-<ul>
-<li>a
-* b
-</li>
-</ul>
-
-<ul>
-<li>x
-* y
-</li>
-</ul>
-!! end
-
-###
-### Internal links
-###
-!! test
-Plain link, capitalized
-!! wikitext
-[[Main Page]]
+Plain link, capitalized
+!! wikitext
+[[Main Page]]
 !! html
 <p><a href="/wiki/Main_Page" title="Main Page">Main Page</a>
 </p>
@@ -9050,6 +9040,14 @@ parsoid=wt2html,wt2wt
 <p><a rel="mw:WikiLink" href="./Constructor:foo" title="Constructor:foo" data-parsoid='{"stx":"simple","a":{"href":"./Constructor:foo"},"sa":{"href":"constructor:foo"}}'>constructor:foo</a></p>
 !! end
 
+!! test
+Template parameter named "constructor"
+!! wikitext
+{{echo|  constructor =  |hi}}
+!! html/parsoid
+<p about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"constructor","named":true,"spc":["  "," ","","  "]},{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi"},"constructor":{"wt":""}},"i":0}}]}'>hi</p>
+!! end
+
 !! article
 ko:
 !! text
@@ -9770,6 +9768,16 @@ parsoid
 
 !! end
 
+!! test
+Nested lists 10 (list and span siblings: wt2wt regression)
+!! wikitext
+*a <span>x</span>
+**b <span>y</span>
+!! html/parsoid
+<ul><li>a <span>x</span>
+<ul><li>b <span>y</span></li></ul></li></ul>
+!! end
+
 !! test
 2. Lists with start-of-line-transparent tokens before bullets: Template close
 !! wikitext
@@ -9973,7 +9981,7 @@ parsoid
 !! test
 Parsoid: Test of whitespace serialization with Templated bullets
 !! options
-parsoid
+parsoid=wt2html
 !! wikitext
 * {{bullet}}
 !! html/parsoid
@@ -10093,22 +10101,6 @@ parsoid=wt2html,wt2wt,html2html
 </ul>
 !!end
 
-!! test
-Table with missing opening <tr> tag
-!! options
-parsoid=wt2html,wt2wt
-!! wikitext
-<table>
-<td>foo</td>
-</tr>
-</table>
-!! html+tidy
-<table>
-<tbody><tr><td>foo</td>
-</tr>
-</tbody></table>
-!! end
-
 ###
 ### Magic Words
 ###
@@ -10962,7 +10954,7 @@ RFC 822
 <p><a class="external mw-magiclink-rfc" rel="nofollow" href="https://tools.ietf.org/html/rfc822">RFC 822</a>
 </p>
 !! html/parsoid
-<p><a href="https://tools.ietf.org/html/rfc822" rel="mw:ExtLink" class="external text">RFC 822</a></p>
+<p><a href="https://tools.ietf.org/html/rfc822" rel="mw:ExtLink" class="external mw-magiclink">RFC 822</a></p>
 !! end
 
 !! test
@@ -10973,7 +10965,7 @@ This is RFC 822 but thisRFC 822 is not RFC 822linked.
 <p>This is <a class="external mw-magiclink-rfc" rel="nofollow" href="https://tools.ietf.org/html/rfc822">RFC 822</a> but thisRFC 822 is not RFC 822linked.
 </p>
 !! html/parsoid
-<p>This is <a href="https://tools.ietf.org/html/rfc822" rel="mw:ExtLink" class="external text">RFC 822</a> but thisRFC 822 is not RFC 822linked.</p>
+<p>This is <a href="https://tools.ietf.org/html/rfc822" rel="mw:ExtLink" class="external mw-magiclink">RFC 822</a> but thisRFC 822 is not RFC 822linked.</p>
 !! end
 
 !! test
@@ -10988,7 +10980,7 @@ RFC
 822
 </p>
 !! html/parsoid
-<p><a href="https://tools.ietf.org/html/rfc822" rel="mw:ExtLink" class="external text">RFC <span typeof="mw:Entity" data-parsoid='{"src":"&amp;nbsp;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#160;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#0160;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#xA0;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#Xa0;","srcContent":" "}'> </span> 822</a>
+<p><a href="https://tools.ietf.org/html/rfc822" rel="mw:ExtLink" class="external mw-magiclink">RFC <span typeof="mw:Entity" data-parsoid='{"src":"&amp;nbsp;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#160;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#0160;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#xA0;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#Xa0;","srcContent":" "}'> </span> 822</a>
 RFC
 822</p>
 !! end
@@ -11046,7 +11038,7 @@ PMID 1234
 <p><a class="external mw-magiclink-pmid" rel="nofollow" href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract">PMID 1234</a>
 </p>
 !! html/parsoid
-<p><a href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract" rel="mw:ExtLink" class="external text">PMID 1234</a></p>
+<p><a href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract" rel="mw:ExtLink" class="external mw-magiclink">PMID 1234</a></p>
 !! end
 
 !! test
@@ -11057,7 +11049,7 @@ This is PMID 1234 but thisPMID 1234 is not PMID 1234linked.
 <p>This is <a class="external mw-magiclink-pmid" rel="nofollow" href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract">PMID 1234</a> but thisPMID 1234 is not PMID 1234linked.
 </p>
 !! html/parsoid
-<p>This is <a href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract" rel="mw:ExtLink" class="external text">PMID 1234</a> but thisPMID 1234 is not PMID 1234linked.</p>
+<p>This is <a href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract" rel="mw:ExtLink" class="external mw-magiclink">PMID 1234</a> but thisPMID 1234 is not PMID 1234linked.</p>
 !! end
 
 !! test
@@ -11072,7 +11064,7 @@ PMID
 1234
 </p>
 !! html/parsoid
-<p><a href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract" rel="mw:ExtLink" class="external text">PMID <span typeof="mw:Entity" data-parsoid='{"src":"&amp;nbsp;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#160;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#0160;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#xA0;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#Xa0;","srcContent":" "}'> </span> 1234</a>
+<p><a href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract" rel="mw:ExtLink" class="external mw-magiclink">PMID <span typeof="mw:Entity" data-parsoid='{"src":"&amp;nbsp;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#160;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#0160;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#xA0;","srcContent":" "}'> </span><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#Xa0;","srcContent":" "}'> </span> 1234</a>
 PMID
 1234</p>
 !! end
@@ -12984,6 +12976,24 @@ Templates: Support for templates generating attributes and content
 </tbody></table>
 !!end
 
+!! article
+Template:attribute_from_template
+!! text
+class="123"
+!! endarticle
+
+!! test
+Table cell with attribute before expanded attribute
+!! wikitext
+{|
+| align="center" {{attribute_from_template}} |456
+|}
+!! html/parsoid
+<table>
+<tbody><tr><td align="center" class="123" about="#mwt2" typeof="mw:ExpandedAttrs" data-mw='{"attribs":[[{"txt":"class","html":"&lt;span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=&apos;{\"pi\":[[]],\"dsr\":[20,47,null,null]}&apos; data-mw=&apos;{\"parts\":[{\"template\":{\"target\":{\"wt\":\"attribute_from_template\",\"href\":\"./Template:Attribute_from_template\"},\"params\":{},\"i\":0}}]}&apos;>class=\"123\"&lt;/span>"},{"html":""}]]}'>456</td></tr>
+</tbody></table>
+!! end
+
 !! test
 1. Entities and nowikis inside templated attributes should be handled correctly
 !! wikitext
@@ -13471,6 +13481,19 @@ Parser Functions: 2. Nested use (only outermost should be marked up)
 </p>
 !!end
 
+## Note that the templates inside the references are not wrapped
+!! test
+Template nested in extension tag in template
+!! wikitext
+{{echo|hi<ref>[[ho|{{echo|hi}}]]</ref>}}
+{{echo|hi<ref>[http://test.com?q={{echo|ho}}]</ref>}}
+<references />
+!! html/parsoid
+<p><span about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi&lt;ref>[[ho|{{echo|hi}}]]&lt;/ref>"}},"i":0}}]}'>hi</span><sup about="#mwt2" class="mw-ref" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="./Main_Page#cite_note-1" style="counter-reset: mw-Ref 1;"><span class="mw-reflink-text">[1]</span></a></sup>
+<span about="#mwt7" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi&lt;ref>[http://test.com?q={{echo|ho}}]&lt;/ref>"}},"i":0}}]}'>hi</span><sup about="#mwt7" class="mw-ref" id="cite_ref-2" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-2"},"attrs":{}}'><a href="./Main_Page#cite_note-2" style="counter-reset: mw-Ref 2;"><span class="mw-reflink-text">[2]</span></a></sup></p>
+<ol class="mw-references references" typeof="mw:Extension/references" about="#mwt10" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><a href="./Main_Page#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text"><a rel="mw:WikiLink" href="./Ho" title="Ho" data-parsoid='{"stx":"piped","a":{"href":"./Ho"},"sa":{"href":"ho"}}'>hi</a></span></li><li about="#cite_note-2" id="cite_note-2"><a href="./Main_Page#cite_ref-2" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-2" class="mw-reference-text"><a typeof="mw:ExpandedAttrs" about="#mwt11" rel="mw:ExtLink" class="external autonumber" href="http://test.com?q=ho" data-mw='{"attribs":[[{"txt":"href"},{"html":"http://test.com?q=ho"}]]}'></a></span></li></ol>
+!! end
+
 ###
 ### Pre-save transform tests
 ###
@@ -14816,6 +14839,25 @@ Image with nested tables in caption
 </figcaption></figure>
 !! end
 
+!! test
+Image with heading and horizontal rule in caption
+!! wikitext
+[[File:Foobar.jpg|thumb|
+===Testing===
+123
+--------------
+]]
+!! html/php
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div><h3><span class="mw-headline" id="Testing">Testing</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Testing">edit</a><span class="mw-editsection-bracket">]</span></span></h3> 123 <hr /></div></div></div>
+
+!! html/parsoid
+<figure class="mw-default-size" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"caption","ak":"\n=== Testing ===\n123\n--------------\n"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{"href":"File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption>
+<h3 id="Testing">Testing</h3>
+123
+<hr data-parsoid='{"extra_dashes":10}'/>
+</figcaption></figure>
+!! end
+
 ###################
 # Conflicting image format options.
 # First option specified should 'win'.
@@ -15127,7 +15169,7 @@ T3887: A RFC with a thumbnail
 <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>This is <a class="external mw-magiclink-rfc" rel="nofollow" href="https://tools.ietf.org/html/rfc12354">RFC 12354</a></div></div></div>
 
 !! html/parsoid
-<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>This is <a href="https://tools.ietf.org/html/rfc12354" rel="mw:ExtLink" class="external text">RFC 12354</a></figcaption></figure>
+<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>This is <a href="https://tools.ietf.org/html/rfc12354" rel="mw:ExtLink" class="external mw-magiclink">RFC 12354</a></figcaption></figure>
 !! end
 
 !! test
@@ -15464,8 +15506,7 @@ Parsoid-specific image handling - simple image with size and middle alignment
 !! end
 
 !! test
-Parsoid-specific image handling - simple image with size, middle alignment,
-non-standard namespace alias
+Parsoid-specific image handling - simple image with size, middle alignment, non-standard namespace alias
 !! options
 parsoid=wt2wt,wt2html,html2html
 !! wikitext
@@ -15475,8 +15516,7 @@ parsoid=wt2wt,wt2html,html2html
 !! end
 
 !! test
-Parsoid-specific image handling - simple image with size and middle alignment
-(existing content)
+Parsoid-specific image handling - simple image with size and middle alignment (existing content)
 !! wikitext
 [[File:Foobar.jpg|50px|middle]]
 !! html/parsoid
@@ -15484,8 +15524,7 @@ Parsoid-specific image handling - simple image with size and middle alignment
 !! end
 
 !! test
-Parsoid-specific image handling - simple image with size and middle alignment
-and non-standard namespace name
+Parsoid-specific image handling - simple image with size and middle alignment and non-standard namespace name
 !! options
 parsoid=wt2html,wt2wt,html2html
 !! wikitext
@@ -15512,41 +15551,46 @@ Parsoid-specific image handling - simple image with border and size spec
 
 !! test
 Parsoid-specific image handling - thumbnail with halign, valign, and caption
+!! options
+parsoid=wt2html,html2html
 !! wikitext
 [[File:Foobar.jpg|left|baseline|thumb|caption content]]
 !! html/parsoid
-<figure class="mw-default-size mw-halign-left mw-valign-baseline" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>caption content</figcaption></figure>
+<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>caption content</figcaption></figure>
 !! end
 
 !! test
-Parsoid-specific image handling - thumbnail with halign, valign, and caption
-(existing content)
+Parsoid-specific image handling - thumbnail with halign, valign, and caption (existing content)
+!! options
+parsoid=wt2html,html2html
 !! wikitext
 [[File:Foobar.jpg|thumb|left|baseline|caption content]]
 !! html/parsoid
-<figure class="mw-default-size mw-halign-left mw-valign-baseline" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"left","ak":"left"},{"ck":"baseline","ak":"baseline"},{"ck":"caption","ak":"caption content"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption>caption content</figcaption></figure>
+<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"left","ak":"left"},{"ck":"baseline","ak":"baseline"},{"ck":"caption","ak":"caption content"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption>caption content</figcaption></figure>
 !! end
 
 !! test
 Parsoid-specific image handling - thumbnail with specific size, halign, valign, and caption
+!! options
+parsoid=wt2html,html2html
 !! wikitext
 [[Image:Foobar.jpg|right|middle|thumb|50x50px|caption]]
 !! html/parsoid
-<figure class="mw-halign-right mw-valign-middle" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50"/></a><figcaption>caption</figcaption></figure>
+<figure class="mw-halign-right" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50"/></a><figcaption>caption</figcaption></figure>
 !! end
 
 !! test
-Parsoid-specific image handling - thumbnail with specific size, halign,
-valign, and caption (existing content)
+Parsoid-specific image handling - thumbnail with specific size, halign, valign, and caption (existing content)
+!! options
+parsoid=wt2html,html2html
 !! wikitext
 [[File:Foobar.jpg|thumb|50x50px|right|middle|caption]]
 !! html/parsoid
-<figure class="mw-halign-right mw-valign-middle" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"width","ak":"50x50px"},{"ck":"right","ak":"right"},{"ck":"middle","ak":"middle"},{"ck":"caption","ak":"caption"}],"size":"50x50"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"6","width":"50"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption>caption</figcaption></figure>
+<figure class="mw-halign-right" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"width","ak":"50x50px"},{"ck":"right","ak":"right"},{"ck":"middle","ak":"middle"},{"ck":"caption","ak":"caption"}],"size":"50x50"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"6","width":"50"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption>caption</figcaption></figure>
 !! end
 
 !! test
-Parsoid-specific image handling - framed image with specific size and caption
-(size is ignored)
+Parsoid-specific image handling - framed image with specific size and caption (size is ignored)
 !! options
 parsoid=wt2html,wt2wt,html2html
 !! wikitext
@@ -15556,14 +15600,13 @@ parsoid=wt2html,wt2wt,html2html
 !! end
 
 !! test
-Parsoid-specific image handling - framed image with specific size, halign, valign, and caption
-(size is ignored)
+Parsoid-specific image handling - framed image with specific size, halign, valign, and caption (size is ignored)
 !! options
-parsoid=wt2html,wt2wt,html2html
+parsoid=wt2html,html2html
 !! wikitext
 [[File:Foobar.jpg|left|baseline|frame|500x50px|caption]]
 !! html/parsoid
-<figure class="mw-halign-left mw-valign-baseline" typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>caption</figcaption></figure>
+<figure class="mw-halign-left" typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>caption</figcaption></figure>
 !! end
 
 !! test
@@ -16106,33 +16149,49 @@ parsoid=wt2html
 !! test
 3. Categories and newlines: newline suppression for last list item should RT properly
 !! wikitext
-* a
-* b 
+*a
+*b
    
 [[Category:Foo]]
    
 [[Category:Bar]]
 [[Category:Baz]]
+
+:c
+
+[[Category:C]]
+
+;d
+
+[[Category:D]]
 !! html/parsoid
-<ul><li> a</li>
-<li> b</li></ul> 
+<ul><li>a</li>
+<li>b</li></ul>
    
-<link rel="mw:PageProp/Category" href="./Category:Foo" data-parsoid='{"stx":"simple","a":{"href":"./Category:Foo"},"sa":{"href":"Category:Foo"}}'/>
+<link rel="mw:PageProp/Category" href="./Category:Foo"/>
    
-<link rel="mw:PageProp/Category" href="./Category:Bar" data-parsoid='{"stx":"simple","a":{"href":"./Category:Bar"},"sa":{"href":"Category:Bar"}}'/>
-<link rel="mw:PageProp/Category" href="./Category:Baz" data-parsoid='{"stx":"simple","a":{"href":"./Category:Baz"},"sa":{"href":"Category:Baz"}}'/>
+<link rel="mw:PageProp/Category" href="./Category:Bar"/>
+<link rel="mw:PageProp/Category" href="./Category:Baz"/>
+
+<dl><dd>c</dd></dl>
+
+<link rel="mw:PageProp/Category" href="./Category:C"/>
+
+<dl><dt>d</dt></dl>
+
+<link rel="mw:PageProp/Category" href="./Category:D"/>
 !! end
 
 !! test
 4. Categories and newlines: newline suppression for last list item should RT properly
 !! wikitext
-* a
-**** b
+*a
+****b
 
 [[Category:Foo]]
 !! html/parsoid
-<ul><li> a
-<ul><li><ul><li><ul><li> b</li></ul></li></ul></li></ul></li></ul>
+<ul><li>a
+<ul><li><ul><li><ul><li>b</li></ul></li></ul></li></ul></li></ul>
 
 <link rel="mw:PageProp/Category" href="./Category:Foo" data-parsoid='{"stx":"simple","a":{"href":"./Category:Foo"},"sa":{"href":"Category:Foo"}}'/>
 !! end
@@ -16143,18 +16202,18 @@ parsoid=wt2html
 !! options
 parsoid=wt2html
 !! wikitext
-* a
-** b
+*a
+**b
 [[Category:Foo]]
-* c
-** d
+*c
+**d
 [[Category:Foo]]
 !! html/parsoid
-<ul><li> a
-<ul><li> b
+<ul><li>a
+<ul><li>b
 <link rel="mw:PageProp/Category" href="./Category:Foo" data-parsoid='{"stx":"simple","a":{"href":"./Category:Foo"},"sa":{"href":"Category:Foo"}}'/></li></ul></li>
-<li> c
-<ul><li> d</li></ul></li></ul>
+<li>c
+<ul><li>d</li></ul></li></ul>
 <link rel="mw:PageProp/Category" href="./Category:Foo" data-parsoid='{"stx":"simple","a":{"href":"./Category:Foo"},"sa":{"href":"Category:Foo"}}'/>
 !! end
 
@@ -16167,9 +16226,9 @@ parsoid=wt2html
 !! options
 parsoid=wt2html
 !! wikitext
-* a [[Category:Foo]]
+*a [[Category:Foo]]
 !! html/parsoid
-<ul><li>a <link rel="mw:PageProp/Category" href="./Category:Foo" data-parsoid='{"stx":"simple","a":{"href":"./Category:Foo"},"sa":{"href":"Category:Foo"}}'/></li></ul>
+<ul><li>a<link rel="mw:PageProp/Category" href="./Category:Foo" data-parsoid='{"stx":"simple","a":{"href":"./Category:Foo"},"sa":{"href":"Category:Foo"}}'/></li></ul>
 !! end
 
 # This test also demonstrates because of newline+category tunneling
@@ -16178,23 +16237,23 @@ parsoid=wt2html
 !! test
 7. Categories and newlines: migrateTrailingCategories dom pass should leave template content alone
 !! wikitext
-* {{echo|a
+*{{echo|a
 [[Category:Foo]]}}
 !! html/parsoid
-<ul><li> <span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a\n[[Category:Foo]]"}},"i":0}}]}'>a
+<ul><li><span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a\n[[Category:Foo]]"}},"i":0}}]}'>a
 </span><link rel="mw:PageProp/Category" href="./Category:Foo" about="#mwt1" data-parsoid='{"stx":"simple","a":{"href":"./Category:Foo"},"sa":{"href":"Category:Foo"}}'/></li></ul>
 !! end
 
 !! test
 8. Categories and newlines: migrateTrailingCategories dom pass should not get tripped by intervening templates
 !! wikitext
-* a
+*a
 
 {{echo|[[Category:Foo]]
 [[Category:Bar]]}}
 [[Category:Baz]]
 !! html/parsoid
-<ul><li> a</li></ul>
+<ul><li>a</li></ul>
 
 <link rel="mw:PageProp/Category" href="./Category:Foo" about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"stx":"simple","a":{"href":"./Category:Foo"},"sa":{"href":"Category:Foo"},"pi":[[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[[Category:Foo]]\n[[Category:Bar]]"}},"i":0}}]}'/><span about="#mwt1">
 </span><link rel="mw:PageProp/Category" href="./Category:Bar" about="#mwt1" data-parsoid='{"stx":"simple","a":{"href":"./Category:Bar"},"sa":{"href":"Category:Bar"}}'/>
@@ -16202,7 +16261,21 @@ parsoid=wt2html
 !! end
 
 !! test
-9. Categories and newlines: should behave properly with linkprefix (T87753)
+Categories and newlines: migrateTrailingCategories dom pass should not get tripped by comments and whitespace
+!! wikitext
+*a
+
+[[Category:Bar]]<!--boo1--> <!--boo2-->
+[[Category:Baz]]<!--boo3--> <!--boo4-->
+!! html/parsoid
+<ul><li>a</li></ul>
+
+<link rel="mw:PageProp/Category" href="./Category:Bar"/><!--boo1--> <!--boo2-->
+<link rel="mw:PageProp/Category" href="./Category:Baz"/><!--boo3--> <!--boo4-->
+!! end
+
+!! test
+Categories and newlines: should behave properly with linkprefix (T87753)
 !! options
 language=ar
 !! wikitext
@@ -16222,7 +16295,7 @@ foo bar</p>
 !! end
 
 !! test
-10. No regressions on internal links following category (T174639)
+No regressions on internal links following category (T174639)
 !! options
 parsoid=wt2html,html2html
 !! wikitext
@@ -18685,7 +18758,7 @@ Punctuation: CSS !important (T13874)
 !! wikitext
 <div style="width:50% !important">important</div>
 !! html
-<div style="width:50% !important">important</div>
+<div style="width:50%&#32;!important">important</div>
 
 !!end
 
@@ -18694,7 +18767,7 @@ Punctuation: CSS ! important (T13874; with space after)
 !! wikitext
 <div style="width:50% ! important">important</div>
 !! html
-<div style="width:50% ! important">important</div>
+<div style="width:50%&#32;! important">important</div>
 
 !!end
 
@@ -21010,6 +21083,25 @@ File:Foobar.jpg
 </ul>
 !! end
 
+!! test
+Serialize gallery image captions on a line
+!! options
+parsoid={
+  "modes": ["html2wt"],
+  "nativeGallery": true
+}
+!! html/parsoid
+<ul class="gallery mw-gallery-traditional" typeof="mw:Extension/gallery" about="#mwt2" data-mw='{"name":"gallery","attrs":{},"body":{}}'>
+<li class="gallerybox" style="width: 155px;"><div class="thumb" style="width: 150px;"><figure-inline typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="14" width="120"/></a></figure-inline></div><div class="gallerytext"><p>hi</p><p>ho</p></div></li>
+<li class="gallerybox" style="width: 155px;"><div class="thumb" style="width: 150px;"><figure-inline typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="14" width="120"/></a></figure-inline></div><div class="gallerytext">hi<br />ho</div></li>
+</ul>
+!! wikitext
+<gallery>
+File:Foobar.jpg| hi  ho 
+File:Foobar.jpg|hi<br />ho
+</gallery>
+!! end
+
 !! test
 HTML Hex character encoding (spells the word "JavaScript")
 !! options
@@ -21169,18 +21261,22 @@ T24905: <abbr> followed by ISBN followed by </a>
 Double RFC
 !! wikitext
 RFC RFC 1234
-!! html
+!! html/php
 <p>RFC <a class="external mw-magiclink-rfc" rel="nofollow" href="https://tools.ietf.org/html/rfc1234">RFC 1234</a>
 </p>
+!! html/parsoid
+<p>RFC <a href="https://tools.ietf.org/html/rfc1234" rel="mw:ExtLink" class="external mw-magiclink">RFC 1234</a></p>
 !! end
 
 !! test
 Double RFC with a wiki link
 !! wikitext
 RFC [[RFC 1234]]
-!! html
+!! html/php
 <p>RFC <a href="/index.php?title=RFC_1234&amp;action=edit&amp;redlink=1" class="new" title="RFC 1234 (page does not exist)">RFC 1234</a>
 </p>
+!! html/parsoid
+<p>RFC <a rel="mw:WikiLink" href="./RFC_1234" title="RFC 1234">RFC 1234</a></p>
 !! end
 
 !! test
@@ -21191,7 +21287,7 @@ RFC   983&#x20;987
 <p><a class="external mw-magiclink-rfc" rel="nofollow" href="https://tools.ietf.org/html/rfc983">RFC 983</a>&#x20;987
 </p>
 !! html/parsoid
-<p><a href="https://tools.ietf.org/html/rfc983" rel="mw:ExtLink" class="external text" data-parsoid='{"stx":"magiclink"}'>RFC   983</a><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#x20;","srcContent":" "}'> </span>987</p>
+<p><a href="https://tools.ietf.org/html/rfc983" rel="mw:ExtLink" class="external mw-magiclink" data-parsoid='{"stx":"magiclink"}'>RFC   983</a><span typeof="mw:Entity" data-parsoid='{"src":"&amp;#x20;","srcContent":" "}'> </span>987</p>
 !! end
 
 !! test
@@ -21436,9 +21532,9 @@ parsoid=wt2html
 !! test
 Definition list code coverage
 !! wikitext
-;title   : def
-;title : def
-;title: def
+;title   :def
+;title :def
+;title:def
 !! html/php
 <dl><dt>title  &#160;</dt>
 <dd>def</dd>
@@ -21448,9 +21544,9 @@ Definition list code coverage
 <dd>def</dd></dl>
 
 !! html/parsoid
-<dl><dt>title  <span typeof="mw:Placeholder"> </span></dt><dd> def</dd>
-<dt>title<span typeof="mw:Placeholder"> </span></dt><dd> def</dd>
-<dt>title</dt><dd> def</dd></dl>
+<dl><dt>title  <span typeof="mw:Placeholder"> </span></dt><dd>def</dd>
+<dt>title<span typeof="mw:Placeholder"> </span></dt><dd>def</dd>
+<dt>title</dt><dd>def</dd></dl>
 !! end
 
 !! test
@@ -22698,8 +22794,8 @@ gopher://www.google.com
 !! html/parsoid
 <p><a rel="mw:ExtLink" class="external free" href="http://www.google.com">http://www.google.com</a>
 <a rel="mw:ExtLink" class="external free" href="gopher://www.google.com">gopher://www.google.com</a>
-<a rel="mw:ExtLink" class="external free" href="http://www.google.com">http://www.google.com</a>
-<a rel="mw:ExtLink" class="external free" href="gopher://www.google.com">gopher://www.google.com</a>
+<a rel="mw:ExtLink" class="external text" href="http://www.google.com">http://www.google.com</a>
+<a rel="mw:ExtLink" class="external text" href="gopher://www.google.com">gopher://www.google.com</a>
 <a rel="mw:ExtLink" class="external text" href="https://www.google.com">irc://www.google.com</a>
 <a rel="mw:ExtLink" class="external text" href="ftp://www.google.com">www.google.com/ftp://dir</a>
 <a rel="mw:ExtLink" class="external text" href="//www.google.com">www.google.com</a></p>
@@ -23954,10 +24050,10 @@ Play a bit with r67090 and T5158
 <div style="width:50%&#160;!important">&nbsp;</div>
 <div style="border : solid;">&nbsp;</div>
 !! html/php
-<div style="width:50% !important">&#160;</div>
+<div style="width:50%&#32;!important">&#160;</div>
 <div style="width:50% !important">&#160;</div>
 <div style="width:50% !important">&#160;</div>
-<div style="border&#160;: solid;">&#160;</div>
+<div style="border&#32;: solid;">&#160;</div>
 
 !! html/parsoid
 <div style="width:50% !important" data-parsoid='{"stx":"html"}'><span typeof="mw:Entity" data-parsoid='{"srcContent":" "}'> </span></div>
@@ -23967,6 +24063,15 @@ Play a bit with r67090 and T5158
 
 !! end
 
+!! test
+T5158: Test for French spaces in attributes
+!! wikitext
+<br style=" clear : both ; " />
+!! html/php
+<p><br style="clear&#32;: both&#32;;" />
+</p>
+!! end
+
 !! test
 HTML5 data attributes
 !! wikitext
@@ -24881,9 +24986,9 @@ Empty LI and TR nodes should be stripped from template content
 !! test
 Empty LI and TR nodes should not be stripped from top-level content
 !! wikitext
-* a
+*a
 *
-* b
+*b
 
 {|
 |-
@@ -24892,9 +24997,9 @@ Empty LI and TR nodes should not be stripped from top-level content
 |}
 !! html/parsoid
 <ul>
-<li> a</li>
+<li>a</li>
 <li class='mw-empty-elt'></li>
-<li> b</li>
+<li>b</li>
 </ul>
 <table>
 <tbody>
@@ -25811,6 +25916,65 @@ parsoid=html2wt
 
 !! end
 
+!! test
+Tables: 5. Empty table cells should get whitespace to avoid need for nowikis
+!! options
+parsoid=html2wt
+!! html/parsoid
+<table><tr><td></td><td align="center" data-parsoid='{"stx":"row"}'></td><td data-parsoid='{"stx":"row"}'></td></tr></table>
+
+<table><tr><td></td><td align="center"></td><td></td></tr></table>
+
+<table><tr><td></td><td align="center" data-parsoid='{"stx":"row", "startTagSrc":"{{!}}{{!}}"}'></td><td data-parsoid='{"stx":"row"}'></td></tr></table>
+
+<table><tr><th></th><th align="center" data-parsoid='{"stx":"row"}'></th><th data-parsoid='{"stx":"row"}'></th></tr></table>
+!! wikitext
+{|
+| || align="center" | ||
+|}
+
+{|
+|
+| align="center" |
+|
+|}
+
+{|
+| {{!}}{{!}} align="center" | ||
+|}
+
+{|
+! !! align="center" | !!
+|}
+!! html/php+tidy
+<table>
+<tbody><tr>
+<td></td>
+<td align="center"></td>
+<td>
+</td></tr></tbody></table>
+<table>
+<tbody><tr>
+<td>
+</td>
+<td align="center">
+</td>
+<td>
+</td></tr></tbody></table>
+<table>
+<tbody><tr>
+<td></td>
+<td align="center"></td>
+<td>
+</td></tr></tbody></table>
+<table>
+<tbody><tr>
+<th></th>
+<th align="center"></th>
+<th>
+</th></tr></tbody></table>
+!! end
+
 !! test
 T97430: Don't emit empty nowiki pairs around marker meta tags
 !! options
@@ -26340,8 +26504,6 @@ bar <span><nowiki>[[foo]]</nowiki></span>
 !!end
 
 #### ----------------------- PRE --------------------------
-#### 1. Leading whitespace in SOL context should be escaped
-#### ------------------------------------------------------
 !! test
 1. Leading whitespace in SOL context should be escaped
 !! options
@@ -26454,7 +26616,7 @@ parsoid=html2wt
  ==foo==
 !! end
 
-!!test
+!! test
 T95794: nowiki escaping should account for leading space at start-of-line in an indent-pre block
 !! options
 parsoid=html2wt
@@ -26468,21 +26630,66 @@ parsoid=html2wt
  * bar
 !! end
 
-#### --------------- Behavior Switches --------------------
-
 !! test
-1. Valid behavior switches should be escaped
+Whitespace scrubbing in SOL position should account for SOL-sensitive wikitext markup
 !! options
-parsoid=html2wt
+parsoid = {
+  "modes": ["html2wt"],
+  "scrubWikitext": true
+}
 !! html/parsoid
-__TOC__
-<i>__TOC__</i>
+<p> foo</p>
+<p> %foo</p>
+<p> *foo</p>
+<p> #foo</p>
+<p> =foo=</p>
+<p><link rel="mw:PageProp/Category" href="./Category:Foo" data-parsoid="{}"> *foo</p>
+<p> <link rel="mw:PageProp/Category" href="./Category:Foo" data-parsoid="{}">*foo</p>
+<p> <!--boo-->*foo</p>
+<p><!--boo--> *foo</p>
+<p><!--a--> <!--b--> <!--c--> <!--d--> <!--e--> foo</p>
+<p><!--a--> <!--b--> <!--c--> <!--d--> <!--e--> *foo</p>
 !! wikitext
-<nowiki>__TOC__</nowiki>
-''<nowiki>__TOC__</nowiki>''
-!! end
+foo
 
-!! test
+%foo
+
+<nowiki/>*foo
+
+<nowiki/>#foo
+
+<nowiki/>=foo=
+
+[[Category:Foo]]
+<nowiki/>*foo
+
+ [[Category:Foo]]
+<nowiki>*</nowiki>foo
+
+<nowiki/><!--boo-->*foo
+
+<!--boo--><nowiki/>*foo
+
+<!--a--><!--b--><!--c--><!--d--><!--e-->foo
+
+<!--a--><nowiki/><!--b--><!--c--><!--d--><!--e-->*foo
+!! end
+
+#### --------------- Behavior Switches --------------------
+
+!! test
+1. Valid behavior switches should be escaped
+!! options
+parsoid=html2wt
+!! html/parsoid
+__TOC__
+<i>__TOC__</i>
+!! wikitext
+<nowiki>__TOC__</nowiki>
+''<nowiki>__TOC__</nowiki>''
+!! end
+
+!! test
 2. Invalid behavior switches should not be escaped
 !! options
 parsoid=html2wt
@@ -26583,6 +26790,18 @@ parsoid=html2wt
 baz<nowiki></ref></nowiki>
 !! end
 
+!! test
+Parsoid: newline inducing block nodes don't suppress <nowiki>
+!! options
+parsoid=html2wt
+!! html/parsoid
+ a<h1>foo</h1>
+!! wikitext
+<nowiki> </nowiki>a
+
+= foo =
+!! end
+
 #### --------------- Others ---------------
 !! test
 Escaping nowikis
@@ -27034,13 +27253,13 @@ Encapsulate protected attributes from wt
 <div typeof="mw:placeholder stuff" data-mw="whoo" data-parsoid="weird" data-parsoid-other="no" about="time" rel="mw:true">foo</div>
 
 {| typeof="mw:placeholder stuff" data-mw="whoo" data-parsoid="weird" data-parsoid-other="no" about="time" rel="mw:true"
-| ok
+|ok
 |}
 !! html/parsoid
 <div data-x-typeof="mw:placeholder stuff" data-x-data-mw="whoo" data-x-data-parsoid="weird" data-x-data-parsoid-other="no" data-x-about="time" data-x-rel="mw:true">foo</div>
 
 <table data-x-typeof="mw:placeholder stuff" data-x-data-mw="whoo" data-x-data-parsoid="weird" data-x-data-parsoid-other="no" data-x-about="time" data-x-rel="mw:true">
-<tbody><tr><td data-parsoid='{"autoInsertedEnd":true}'> ok</td></tr>
+<tbody><tr><td data-parsoid='{"autoInsertedEnd":true}'>ok</td></tr>
 </tbody></table>
 !!end
 
@@ -27057,64 +27276,64 @@ plain text</pre>
 plain text
 !!end
 
-!!test
+!! test
 1. Ensure fostered text content is wrapped in element nodes
-!!options
+!! options
 parsoid=wt2html
 !! wikitext
 <table>hi</table><table>ho</table>
+!! html/php+tidy
+hi<table></table>ho<table></table>
 !! html/parsoid
-<p>hi</p>
-<table></table>
-<p>ho</p>
-<table></table>
-!!end
+<span data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true}'>hi</span><table data-parsoid='{"stx":"html"}'></table><span data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true}'>ho</span><table data-parsoid='{"stx":"html"}'></table>
+!! end
 
-!!test
+!! test
 2. Ensure fostered text content is wrapped in element nodes (traps regressions around fostered marker on the element getting lost)
-!!options
+!! options
 parsoid=wt2html,wt2wt
 !! wikitext
 <table>
 <tr> || ||
 <td> a
 </table>
+!! html/php+tidy
+ || ||
+<table>
+<tbody><tr><td> a
+</td></tr></tbody></table>
 !! html/parsoid
-<p> || ||
-</p><table>
-<tbody><tr><td> a</td></tr>
-</tbody></table>
-!!end
+<span data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true}'> || ||
+</span><table data-parsoid='{"stx":"html"}'>
+<tbody><tr data-parsoid='{"stx":"html","autoInsertedEnd":true}'><td data-parsoid='{"stx":"html","autoInsertedEnd":true}'> a
+</td></tr></tbody></table>
+!! end
 
-!!test
+!! test
 Encapsulation properly handles null DSR information from foster box
-!!options
+!! options
 parsoid=wt2html,wt2wt
 !! wikitext
 {{echo|<table>foo<tr><td>bar</td></tr></table>}}
 !! html/parsoid
 <span typeof="mw:Transclusion" data-mw="{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;<table>foo<tr><td>bar</td></tr></table>&quot;}},&quot;i&quot;:0}}]}">foo</span><table><tbody><tr><td>bar</td></tr></tbody></table>
-!!end
+!! end
 
-!!test
+!! test
 1. Encapsulate foster-parented transclusion content
-!!options
+!! options
 parsoid=wt2wt,wt2html
 !! wikitext
 <table>{{echo|foo<tr><td>bar</td></tr>}}</table>
+!! html/php+tidy
+foo<table><tbody><tr><td>bar</td></tr></tbody></table>
 !! html/parsoid
-<p typeof="mw:Transclusion" data-mw="{&quot;parts&quot;:[&quot;<table>&quot;,{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;foo<tr><td>bar</td></tr>&quot;}},&quot;i&quot;:0}},&quot;</table>&quot;]}">foo</p><table>
-<tbody>
-<tr>
-<td>bar</td>
-</tr>
-</tbody>
-</table>
-!!end
+<span about="#mwt2" typeof="mw:Transclusion" data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true,"firstWikitextNode":"TABLE_html","pi":[[{"k":"1"}]]}' data-mw='{"parts":["&lt;table>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo&lt;tr>&lt;td>bar&lt;/td>&lt;/tr>"}},"i":0}},"&lt;/table>"]}'>foo</span><table about="#mwt2" data-parsoid='{"stx":"html}'><tbody><tr><td>bar</td></tr></tbody></table>
+!! end
 
-!!test
+!! test
 2. Encapsulate foster-parented transclusion content
-!!options
+!! options
 parsoid=wt2wt,wt2html
 !! wikitext
 <table><div>{{echo|foo}}</div><tr><td>bar</td></tr></table>
@@ -27127,11 +27346,11 @@ parsoid=wt2wt,wt2html
 </tr>
 </tbody>
 </table>
-!!end
+!! end
 
-!!test
+!! test
 3. Encapsulate foster-parented transclusion content
-!!options
+!! options
 parsoid=wt2wt,wt2html
 !! wikitext
 <table><div><p>{{echo|foo</p></div><tr><td>}}bar</td></tr></table>
@@ -27146,11 +27365,11 @@ parsoid=wt2wt,wt2html
 </tr>
 </tbody>
 </table>
-!!end
+!! end
 
-!!test
+!! test
 4. Encapsulate foster-parented transclusion content
-!!options
+!! options
 parsoid=wt2wt,wt2html
 !! wikitext
 <table><div><p>{{echo|foo</p></div><tr><td>}}bar</td></tr></table>
@@ -27165,52 +27384,33 @@ parsoid=wt2wt,wt2html
 </tr>
 </tbody>
 </table>
-!!end
+!! end
 
-!!test
+!! test
 5. Encapsulate foster-parented transclusion content
 !!options
 parsoid=wt2wt,wt2html
 !! wikitext
 <table><tr><td><div><p>{{echo|foo</p></div></td>foo}}</tr></table>
+!! html/php+tidy
+foo<table><tbody><tr><td><div><p>foo</p></div></td></tr></tbody></table>
 !! html/parsoid
-<p typeof="mw:Transclusion" data-mw="{&quot;parts&quot;:[&quot;<table><tr><td><div><p>&quot;,{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;foo</p></div></td>foo&quot;}},&quot;i&quot;:0}},&quot;</tr></table>&quot;]}">foo</p>
-<table>
-<tbody>
-<tr>
-<td>
-<div>
-<p>foo</p>
-</div>
-</td>
-</tr>
-</tbody>
-</table>
-!!end
+<span about="#mwt2" typeof="mw:Transclusion" data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true,"firstWikitextNode":"TABLE_html","pi":[[{"k":"1"}]]}' data-mw='{"parts":["&lt;table>&lt;tr>&lt;td>&lt;div>&lt;p>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo&lt;/p>&lt;/div>&lt;/td>foo"}},"i":0}},"&lt;/tr>&lt;/table>"]}'>foo</span><table about="#mwt2" data-parsoid='{"stx":"html"}'><tbody><tr><td><div><p>foo</p></div></td></tr></tbody></table>
+!! end
 
-!!test
+!! test
 6. Encapsulate foster-parented transclusion content
-!!options
+!! options
 parsoid=wt2wt,wt2html
 !! wikitext
 <table><tr><td><div><p>{{echo|foo</p></div></td>foo</tr></table>}}<p>ok</p>
+!! html/php+tidy
+foo<table><tbody><tr><td><div><p>foo</p></div></td></tr></tbody></table><p>ok</p>
 !! html/parsoid
-<p typeof="mw:Transclusion" data-mw="{&quot;parts&quot;:[&quot;<table><tr><td><div><p>&quot;,{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;foo</p></div></td>foo</tr></table>&quot;}},&quot;i&quot;:0}}]}">foo</p>
-<table>
-<tbody>
-<tr>
-<td>
-<div>
-<p>foo</p>
-</div>
-</td>
-</tr>
-</tbody>
-</table>
-<p>ok</p>
-!!end
+<span about="#mwt2" typeof="mw:Transclusion" data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true,"firstWikitextNode":"TABLE_html","pi":[[{"k":"1"}]]}' data-mw='{"parts":["&lt;table>&lt;tr>&lt;td>&lt;div>&lt;p>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo&lt;/p>&lt;/div>&lt;/td>foo&lt;/tr>&lt;/table>"}},"i":0}}]}'>foo</span><table about="#mwt2" data-parsoid='{"stx":"html"}'><tbody><tr><td><div><p>foo</p></div></td></tr></tbody></table><p data-parsoid='{"stx":"html"}'>ok</p>
+!! end
 
-!!test
+!! test
 7. Encapsulate foster-parented transclusion content
 !!options
 parsoid=wt2wt,wt2html
@@ -27225,13 +27425,13 @@ parsoid=wt2wt,wt2html
 </tr>
 </tbody>
 </table>
-!!end
+!! end
 
 # Note that the wt is broken on purpose: the = should be {{=}} if you
 # don't want it to be a template parameter key.
-!!test
+!! test
 8. Encapsulate foster-parented transclusion content
-!!options
+!! options
 parsoid=wt2wt,wt2html
 !! wikitext
 {{echo|a
@@ -27239,30 +27439,36 @@ parsoid=wt2wt,wt2html
 |-
 |b
 |}
-!! html/parsoid
-<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a\n"}},"i":0}}]}'>a</p>
-<span> </span>
-<p typeof="mw:Transclusion" data-mw='{"parts":["{|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"style":{"wt":"&#39;color:red&#39;"}},"i":0}},"\n|-\n|b\n|}"]}'>{{{1}}}</p>
+!! html/php+tidy
+<p>a
+</p>
 <table>
-<tbody>
-<tr>
-<td>b</td>
-</tr>
-</tbody>
-</table>
-!!end
 
-!!test
+<tbody><tr>
+<td>b
+</td></tr></tbody></table>
+!! html/parsoid
+<p about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a\n"}},"i":0}}]}'>a</p><span about="#mwt1">
+</span><span about="#mwt3" typeof="mw:Transclusion" data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true,"firstWikitextNode":"TABLE","pi":[[{"k":"style","named":true}]]}' data-mw='{"parts":["{|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"style":{"wt":"&apos;color:red&apos;"}},"i":0}},"\n|-\n|b\n|}"]}'>{{{1}}}</span><table about="#mwt3">
+<tbody><tr>
+<td>b
+</td></tr></tbody></table>
+!! end
+
+!! test
 9. Encapsulate foster-parented transclusion content
 !!options
 parsoid=wt2wt,wt2html
 !! wikitext
 <table>{{echo|hi</table>hello}}
+!! html/php+tidy
+hi<table></table><p>hello
+</p>
 !! html/parsoid
-<p about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":["&lt;table>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi&lt;/table>hello"}},"i":0}}]}' data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true,"pi":[[{"k":"1"}]]}'>hi</p><table about="#mwt2" data-parsoid='{"stx":"html"}'></table><p about="#mwt2">hello</p>
-!!end
+<span about="#mwt2" typeof="mw:Transclusion" data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true,"firstWikitextNode":"TABLE_html","pi":[[{"k":"1"}]]}' data-mw='{"parts":["&lt;table>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi&lt;/table>hello"}},"i":0}}]}'>hi</span><table about="#mwt2"></table><p about="#mwt2">hello</p>
+!! end
 
-!!test
+!! test
 Table in fosterable position
 !!options
 parsoid=wt2html
@@ -27280,7 +27486,7 @@ parsoid=wt2html
 
 <table>
 </table>
-!!end
+!! end
 
 # Parsoid only for T66747
 !! test
@@ -27925,7 +28131,7 @@ parsoid={
 
 == hi pal ==
 
-<!--foo-->  [[Category:A3]]
+<!--foo-->[[Category:A3]]
 
 == how goes it ==
 
@@ -28249,7 +28455,7 @@ parsoid={
 !! html/parsoid
 <a rel="mw:WikiLink" href="./Football"><i>Foot</i></a><a rel="mw:WikiLink" href="./Football"><i>ball</i></a>
 !! wikitext
-[[Football|''Football'']]
+''[[Football]]''
 !! end
 
 !! test
@@ -28265,6 +28471,98 @@ parsoid={
 [[Football|Foot]][[Football|ball]]
 !! end
 
+!! test
+1. Move format tags outside of WikiLink
+!! options
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": true
+}
+!! html/parsoid
+<a rel="mw:WikiLink" href="./Football"><i>Football</i></a>
+<a rel="mw:WikiLink" href="./Football"><i><b>Football</b></i></a>
+<a rel="mw:WikiLink" href="./Football"><u><i><b>Football</b></i></u></a>
+!! wikitext
+''[[Football]]''
+'''''[[Football]]'''''
+<u>'''''[[Football]]'''''</u>
+!! end
+
+!! test
+2. Move format tags outside of WikiLink with mergable A tags
+!! options
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": true
+}
+!! html/parsoid
+<a rel="mw:WikiLink" href="./Football"><i><b>Foot</b></i></a><a rel="mw:WikiLink" href="./Football"><i><b>ball</b></i></a>
+!! wikitext
+'''''[[Football]]'''''
+!! end
+
+!! test
+3. Move format tags outside of WikiLink while preserving formats already outside WikiLink
+!! options
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": true
+}
+!! html/parsoid
+<font color="red"><a rel="mw:WikiLink" href="./Foo" title="Foo" class="mw-redirect"><u><b>Foo</b></u></a></font>
+!! wikitext
+<font color="red"><u>'''[[Foo]]'''</u></font>
+!! end
+
+!! test
+4. Do not move format tags outside of WikiLink which includes attributes color, style and class
+!! options
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": true
+}
+!! html/parsoid
+<a rel="mw:WikiLink" href="./Foo" title="Foo" class="mw-redirect"><font color="red">Foo</font></a>
+<a rel="mw:WikiLink" href="./Foo" title="Foo" class="mw-redirect"><span style="color: blue; font-size: 46px;">Foo></span></a>
+<a rel="mw:WikiLink" href="./Foo" title="Foo" class="mw-redirect"><span class="Bar">Foo</span></a>
+!! wikitext
+[[Foo|<font color="red">Foo</font>]]
+[[Foo|<span style="color: blue; font-size: 46px;">Foo></span>]]
+[[Foo|<span class="Bar">Foo</span>]]
+!! end
+
+!! test
+5. T194083 Regression test: Manual edit test that also enables scrubWikitext to move format tags outside wikilinks
+!! options
+parsoid={
+  "modes": ["selser"],
+  "scrubWikitext": true,
+  "changes": [
+    ["a", "html", "<i>Foo</i>"]
+  ]
+}
+!! wikitext
+[[Foo]]
+!! wikitext/edited
+''[[Foo]]''
+!! end
+
+!! test
+6. Regression test: Manual edit test to ensure diff markers are not lost
+!! options
+parsoid={
+  "modes": ["selser"],
+  "scrubWikitext": true,
+  "changes": [
+    ["i", "wrap", "<a href='./Foo' rel='mw:WikiLink'></a>"]
+  ]
+}
+!! wikitext
+''Foo''
+!! wikitext/edited
+''[[Foo]]''
+!! end
+
 #------------------------------
 # End of tag minimization tests
 #------------------------------
@@ -28504,8 +28802,8 @@ Magic links inside image captions (autolinked)
 <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div><a href="/wiki/Special:BookSources/123456789X" class="internal mw-magiclink-isbn">ISBN 123456789x</a></div></div></div>
 !! html/parsoid
 <figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a></figcaption></figure>
-<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a href="https://tools.ietf.org/html/rfc1234" rel="mw:ExtLink" class="external text">RFC 1234</a></figcaption></figure>
-<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract" rel="mw:ExtLink" class="external text">PMID 1234</a></figcaption></figure>
+<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a href="https://tools.ietf.org/html/rfc1234" rel="mw:ExtLink" class="external mw-magiclink">RFC 1234</a></figcaption></figure>
+<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract" rel="mw:ExtLink" class="external mw-magiclink">PMID 1234</a></figcaption></figure>
 <figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a href="./Special:BookSources/123456789X" rel="mw:WikiLink">ISBN 123456789x</a></figcaption></figure>
 !! end
 
@@ -28570,8 +28868,7 @@ parsoid=html2wt,wt2wt
 |<small>-</small>
 |<br />
 -
-|<br />
--
+|<br />-
 |}
 !! html/php+tidy
 <table>
@@ -28592,9 +28889,7 @@ parsoid=html2wt,wt2wt
 <p>-
 </p>
 </td>
-<td><br />
-<p>-
-</p>
+<td><br />-
 </td></tr></tbody></table>
 !! end
 
@@ -28718,6 +29013,147 @@ parsoid=html2wt
 <div id="hello">ok</div>
 !! end
 
+!! test
+Testing serialization after deletion in references
+!! options
+parsoid={
+  "modes": ["wt2wt"],
+  "changes": [
+    ["#x", "remove"]
+  ]
+}
+!! wikitext
+hi <ref><div id="x">ho</div></ref>
+
+<references />
+!! wikitext/edited
+hi <ref></ref>
+
+<references />
+!! end
+
+!!test
+Testing serialization after deletion of table cells
+!!options
+parsoid={
+  "modes": ["wt2wt", "selser"],
+  "changes": [
+    ["#x", "remove"]
+  ]
+}
+!!wikitext
+{|
+!h1 !!h2 !!h3
+| id="x" |c1 {{!}}{{!}}{{!}}c2 |||c3
+|}
+!! wikitext/edited
+{|
+!h1!!h2!!h3
+|c2|||c3
+|}
+!!end
+
+!! test
+Testing selser after addition of new row before first row (T125419)
+!! options
+parsoid={
+  "modes": ["wt2wt", "selser"],
+  "changes": [
+    [ "tr", "before", "<tr><td>X</td></tr>" ]
+  ]
+}
+!! wikitext
+{|
+|a
+|}
+!! wikitext/edited
+{|
+|X
+|-
+|a
+|}
+!! end
+
+!! test
+Serialize new table rows in a HTML table using HTML tags
+!! options
+parsoid={
+  "modes": ["wt2wt", "selser"],
+  "changes": [
+    [ "tr", "before", "<tr><td>X</td></tr>" ]
+  ]
+}
+!! wikitext
+<table><tr><td>a</td></tr></table>
+!! wikitext/edited
+<table><tr><td>X</td></tr><tr><td>a</td></tr></table>
+!! end
+
+!! test
+Serialize new table cells in a HTML row using HTML tags
+!! options
+parsoid={
+  "modes": ["wt2wt", "selser"],
+  "changes": [
+    [ "td", "before", "<td>X</td>" ]
+  ]
+}
+!! wikitext
+<table><tr><td>a</td></tr></table>
+!! wikitext/edited
+<table><tr><td>X</td><td>a</td></tr></table>
+!! end
+
+!! test
+Serialize wikitext list items as HTML list items when embedded in a HTML list
+!! options
+parsoid=html2wt
+!! html
+<ul data-parsoid='{"stx": "html"}'>
+<li data-parsoid='{}'>a</li>
+<li>b</li>
+</ul>
+!! wikitext
+<ul>
+<li>a</li>
+<li>b</li>
+</ul>
+!! end
+
+# SSS FIXME: Is this actually a good thing given the
+# odd nested list output that is generated by MW?
+# <ul><li>foo<ul>..</ul></li></ul> instead of
+# <ul><li>foo</li><ul>..</ul></ul>
+!! test
+Wikitext lists can be nested inside HTML lists
+!! options
+parsoid=html2wt
+!! html
+<ul data-parsoid='{"stx": "html"}'>
+<li data-parsoid='{"stx": "html"}'>a
+<ul><li>b</li></ul>
+</li>
+</ul>
+
+<ul data-parsoid='{"stx": "html"}'>
+<li>x
+<ul><li>y</li></ul>
+</li>
+</ul>
+!! wikitext
+<ul>
+<li>a
+* b
+</li>
+</ul>
+
+<ul>
+<li>x
+* y
+</li>
+</ul>
+!! end
+
 !! test
 WTS change modes
 !! options
@@ -28955,7 +29391,7 @@ parsoid={
 !! html/parsoid
 <h2> <link href="./Category:A2" rel="mw:PageProp/Category" />ok</h2>
 !! wikitext
- [[Category:A2]]
+[[Category:A2]]
 
 == ok ==
 !! end
@@ -29023,7 +29459,7 @@ parsoid={
 !! html/parsoid
 <h2>foo<br/>bar</h2>
 !! wikitext
-== foo<br /> bar ==
+== foo<br />bar ==
 !! end
 
 !! test
@@ -30698,10 +31134,16 @@ headings, and cells. HTML versions of the same should preserve whitespace.
 ##########################################################################
 !! test
 Trim whitespace in wikitext headings, list items, table captions, headings, and cells
+!! options
+parsoid={
+       "modes": ["wt2html"],
+       "preserveIEW": true
+}
 !! wikitext
 __NOTOC__
 ==    <!--c1-->  <!--c2--> Spaces   <!--c3--> <!--c4-->  ==
-==             <!--c2-->       <!--c2--> Tabs          <!--c3--><!--c4-->      ==
+==             <!--c1-->       <!--c2--> Tabs          <!--c3--><!--c4-->      ==
+== <!--Headings with fallback ids--> Личная жизнь ==
 *     <!--c1-->   <!--c2-->  List item <!--c3--> <!--c4-->
 ; <!--term to define--> term : <!--term's definition--> definition
 {|
@@ -30721,6 +31163,7 @@ __NOTOC__
 !! html/php+tidy
 <h2><span class="mw-headline" id="Spaces">Spaces</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Spaces">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <h2><span class="mw-headline" id="Tabs">Tabs</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: Tabs">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h2><span class="mw-headline" id=".D0.9B.D0.B8.D1.87.D0.BD.D0.B0.D1.8F_.D0.B6.D0.B8.D0.B7.D0.BD.D1.8C">Личная жизнь</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Личная жизнь">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <ul><li>List item</li></ul>
 <dl><dt>term&#160;</dt>
 <dd>definition</dd></dl>
@@ -30747,11 +31190,37 @@ __NOTOC__
 <td>Table Cell 1</td>
 <td>Table Cell 2
 </td></tr></tbody></table> foo</dd></dl>
+!! html/parsoid
+<meta property="mw:PageProp/notoc">
+<h2 id="Spaces"><!--c1--><!--c2-->Spaces<!--c3--><!--c4--></h2>
+<h2 id="Tabs"><!--c1--><!--c2-->Tabs<!--c3--><!--c4--></h2>
+<h2 id="Личная_жизнь"><span id=".D0.9B.D0.B8.D1.87.D0.BD.D0.B0.D1.8F_.D0.B6.D0.B8.D0.B7.D0.BD.D1.8C" typeof="mw:FallbackId"></span><!--Headings with fallback ids-->Личная жизнь</h2>
+<ul><li><!--c1--><!--c2-->List item<!--c3--><!--c4--></li></ul>
+<dl><dt><!--term to define-->term&nbsp;</dt><dd><!--term's definition-->definition</dd></dl>
+<table>
+<caption><!--c1--><!--c2-->Table Caption<!--c3--><!--c4--></caption>
+<tbody><tr>
+<th><!--c1--><!--c2-->Table Heading 1<!--c3--><!--c4--></th><th>Table Heading 2<!--c5--></th></tr>
+<tr>
+<td><!--c1--><!--c2-->Table Cell 1<!--c3--><!--c4--></td><td>Table Cell 2<!--c5--></td></tr>
+<tr>
+<td>class="foo"</td><td><!--c1--><!--c2-->Table Cell 3<!--c3--><!--c4--></td></tr>
+<tr>
+<td><!--c1-->testing <a rel="mw:WikiLink" href="./One" title="One">two</a> <!--c2--> | <!--c3--> some content</td></tr>
+</tbody></table>
+<dl><dd><table>
+  <tbody><tr><td><!--c1--><!--c2-->Table Cell 1<!--c3--><!--c4--></td><td>Table Cell 2<!--c5--></td></tr>
+  </tbody></table><p> foo   </p><!--c1--></dd></dl>
 !! end
 
 # Looks like <caption> is not accepted in HTML
 !! test
 Do not trim whitespace in HTML headings, list items, table captions, headings, and cells
+!! options
+parsoid={
+       "modes": ["wt2html"],
+       "preserveIEW": true
+}
 !! wikitext
 __NOTOC__
 <h2>    <!--c1-->   <!--c2--> Heading    <!--c3--> <!--c4-->  </h2>
@@ -30767,10 +31236,23 @@ __NOTOC__
 <tbody><tr><th>   Table Heading   </th><th></th></tr>
 <tr><td>   Table Cell   </td><th></th></tr>
 </tbody></table>
+!! html/parsoid
+<meta property="mw:PageProp/notoc"/>
+<h2 id="Heading">    <!--c1-->   <!--c2--> Heading    <!--c3--> <!--c4-->  </h2>
+<ul><li>     <!--c1-->   <!--c2-->  List item <!--c3--> <!--c4-->  </li></ul>
+<table>
+<tbody><tr><th> <!--c1--> <!--c2--> Table Heading <!--c3--> <!--c4--> </th><th></th></tr>
+<tr><td> <!--c1--> <!--c2--> Table Cell <!--c3--> <!--c4--> </td><th></th></tr>
+</tbody></table>
 !! end
 
 !! test
 Do not trim whitespace in links and quotes
+!! options
+parsoid={
+       "modes": ["wt2html"],
+       "preserveIEW": true
+}
 !! wikitext
 foo ''  <!--c1--> italic <!--c2-->   '' and '''  <!--c3-->  bold  <!--c4-->  '''
 [[Foo|  some text  ]]
@@ -30778,6 +31260,9 @@ foo ''  <!--c1--> italic <!--c2-->   '' and '''  <!--c3-->  bold  <!--c4-->  '''
 <p>foo <i>   italic    </i> and <b>    bold    </b>
 <a href="/wiki/Foo" title="Foo">  some text  </a>
 </p>
+!! html/parsoid
+<p>foo <i>  <!--c1--> italic <!--c2-->   </i> and <b>  <!--c3-->  bold  <!--c4-->  </b>
+<a rel="mw:WikiLink" href="./Foo" title="Foo">  some text  </a></p>
 !! end
 
 !! test
index e82bab7..71966b7 100644 (file)
@@ -140,6 +140,8 @@ class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
 
        /**
         * @covers ResourceLoaderFileModule::getScript
+        * @covers ResourceLoaderFileModule::getScriptFiles
+        * @covers ResourceLoaderFileModule::readScriptFiles
         */
        public function testGetScript() {
                $module = new ResourceLoaderFileModule( [
@@ -220,6 +222,8 @@ class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
         *
         * @covers ResourceLoaderFileModule::getStyles
         * @covers ResourceLoaderFileModule::getStyleFiles
+        * @covers ResourceLoaderFileModule::readStyleFiles
+        * @covers ResourceLoaderFileModule::readStyleFile
         */
        public function testMixedCssAnnotations() {
                $basePath = __DIR__ . '/../../data/css';
@@ -334,6 +338,7 @@ class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
 
        /**
         * @covers ResourceLoaderFileModule::getDefinitionSummary
+        * @covers ResourceLoaderFileModule::getFileHashes
         */
        public function testGetVersionHash() {
                $context = $this->getResourceLoaderContext();
index 0ea4e2b..c925339 100644 (file)
@@ -64,6 +64,19 @@ class ResourceLoaderModuleTest extends ResourceLoaderTestCase {
                );
        }
 
+       /**
+        * @covers ResourceLoaderModule::getVersionHash
+        */
+       public function testGetVersionHash_parentDefinition() {
+               $context = $this->getResourceLoaderContext();
+               $module = $this->getMockBuilder( ResourceLoaderModule::class )
+                       ->setMethods( [ 'getDefinitionSummary' ] )->getMock();
+               $module->method( 'getDefinitionSummary' )->willReturn( [ 'a' => 'summary' ] );
+
+               $this->setExpectedException( LogicException::class, 'must call parent' );
+               $module->getVersionHash( $context );
+       }
+
        /**
         * @covers ResourceLoaderModule::validateScriptFile
         */
index d794d13..aebd0bf 100644 (file)
@@ -11,6 +11,13 @@ class MediaWikiTestCaseSchema1Test extends MediaWikiTestCase {
 
        public static $hasRun = false;
 
+       public function setUp() {
+               parent::setUp();
+               if ( $this->db->getType() == 'postgres' ) {
+                       $this->markTestSkipped( __CLASS__ . ' does not support postgres' );
+               }
+       }
+
        public function getSchemaOverrides( IMaintainableDatabase $db ) {
                return [
                        'create' => [ 'MediaWikiTestCaseTestTable', 'imagelinks' ],
index 5464dc4..c0673a1 100644 (file)
  */
 class MediaWikiTestCaseSchema2Test extends MediaWikiTestCase {
 
+       public function setUp() {
+               parent::setUp();
+               if ( $this->db->getType() == 'postgres' ) {
+                       $this->markTestSkipped( __CLASS__ . ' does not support postgres' );
+               }
+       }
+
        public function testMediaWikiTestCaseSchemaTestOrder() {
                // The first test must have run before this one
                $this->assertTrue( MediaWikiTestCaseSchema1Test::$hasRun );
index bfce387..50e940f 100644 (file)
@@ -1,6 +1,10 @@
 # Notable changes
 
-## [Unreleased]
+## v0.2.0
+
+* Util: Added getTestString().
+
+## v0.1.0
 
 * Api: Added initial version.
 * Page: Added initial version.
index be7ed33..56ea045 100644 (file)
@@ -1,6 +1,6 @@
 {
   "name": "wdio-mediawiki",
-  "version": "0.1.0",
+  "version": "0.2.0",
   "description": "WebdriverIO plugin for testing a MediaWiki site.",
   "homepage": "https://gerrit.wikimedia.org/g/mediawiki/core/+/master/tests/selenium/wdio-mediawiki/",
   "license": "MIT",