Merge "mw.loader: Clean up unit tests by using newer QUnit syntax"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 10 Aug 2016 15:29:36 +0000 (15:29 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 10 Aug 2016 15:29:36 +0000 (15:29 +0000)
168 files changed:
RELEASE-NOTES-1.28
autoload.php
docs/hooks.txt
includes/CategoryFinder.php
includes/DefaultSettings.php
includes/EditPage.php
includes/MediaWiki.php
includes/OutputPage.php
includes/Preferences.php
includes/Setup.php
includes/SiteStats.php
includes/actions/UnwatchAction.php
includes/actions/WatchAction.php
includes/api/ApiAMCreateAccount.php
includes/api/ApiAuthManagerHelper.php
includes/api/ApiClientLogin.php
includes/api/ApiCreateAccount.php [deleted file]
includes/api/ApiLogin.php
includes/api/ApiPageSet.php
includes/api/ApiQueryUsers.php
includes/api/ApiResult.php
includes/api/ApiWatch.php
includes/api/i18n/ba.json
includes/api/i18n/en.json
includes/api/i18n/qqq.json
includes/api/i18n/uk.json
includes/api/i18n/zh-hans.json
includes/auth/AuthManager.php
includes/collation/IcuCollation.php
includes/dao/IDBAccessObject.php
includes/db/Database.php
includes/db/DatabaseMssql.php
includes/db/DatabaseMysqlBase.php
includes/db/DatabasePostgres.php
includes/db/IDatabase.php
includes/db/loadbalancer/LBFactoryMulti.php
includes/db/loadbalancer/LoadBalancer.php
includes/diff/DifferenceEngine.php
includes/filebackend/lockmanager/DBLockManager.php
includes/installer/i18n/diq.json
includes/installer/i18n/dty.json [new file with mode: 0644]
includes/installer/i18n/eu.json
includes/installer/i18n/pl.json
includes/jobqueue/JobRunner.php
includes/libs/HtmlArmor.php
includes/page/Article.php
includes/revisiondelete/RevDelArchivedFileItem.php
includes/revisiondelete/RevDelFileItem.php
includes/session/SessionManager.php
includes/skins/SkinTemplate.php
includes/specialpage/LoginSignupSpecialPage.php
includes/specialpage/SpecialPageFactory.php
includes/specials/SpecialChangeCredentials.php
includes/specials/SpecialContributions.php
includes/specials/SpecialDeletedContributions.php
includes/specials/SpecialEditWatchlist.php
includes/specials/SpecialMostlinkedcategories.php
includes/specials/SpecialNewimages.php
includes/specials/SpecialNewpages.php
includes/specials/SpecialProtectedpages.php
includes/specials/SpecialShortpages.php
includes/specials/SpecialTags.php
includes/specials/SpecialUpload.php
includes/specials/SpecialUploadStash.php
includes/specials/SpecialWatchlist.php
includes/specials/pre-authmanager/README [deleted file]
includes/specials/pre-authmanager/SpecialChangeEmail.php [deleted file]
includes/specials/pre-authmanager/SpecialChangePassword.php [deleted file]
includes/specials/pre-authmanager/SpecialCreateAccount.php [deleted file]
includes/specials/pre-authmanager/SpecialPasswordReset.php [deleted file]
includes/specials/pre-authmanager/SpecialUserlogin.php [deleted file]
includes/specials/pre-authmanager/SpecialUserlogout.php [deleted file]
includes/templates/Usercreate.php [deleted file]
includes/templates/Userlogin.php [deleted file]
includes/tidy/Balancer.php
includes/upload/UploadBase.php
includes/user/User.php
includes/utils/AutoloadGenerator.php
includes/utils/BatchRowIterator.php
includes/utils/MWCryptRand.php
languages/i18n/ar.json
languages/i18n/az.json
languages/i18n/ba.json
languages/i18n/bar.json
languages/i18n/bn.json
languages/i18n/bs.json
languages/i18n/cs.json
languages/i18n/de.json
languages/i18n/diq.json
languages/i18n/dty.json
languages/i18n/en.json
languages/i18n/eo.json
languages/i18n/es.json
languages/i18n/eu.json
languages/i18n/fa.json
languages/i18n/fr.json
languages/i18n/gl.json
languages/i18n/got.json
languages/i18n/gu.json
languages/i18n/he.json
languages/i18n/hr.json
languages/i18n/ia.json
languages/i18n/ja.json
languages/i18n/kn.json
languages/i18n/ko.json
languages/i18n/la.json
languages/i18n/lb.json
languages/i18n/mai.json
languages/i18n/mk.json
languages/i18n/nah.json
languages/i18n/nb.json
languages/i18n/ne.json
languages/i18n/nl.json
languages/i18n/pa.json
languages/i18n/pl.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/ro.json
languages/i18n/ru.json
languages/i18n/sh.json
languages/i18n/sl.json
languages/i18n/szl.json
languages/i18n/th.json
languages/i18n/tt-cyrl.json
languages/i18n/uk.json
languages/i18n/ur.json
languages/i18n/yi.json
languages/i18n/zh-hans.json
maintenance/changePassword.php
maintenance/convertExtensionToRegistration.php
maintenance/createAndPromote.php
package.json
resources/Resources.php
resources/src/jquery/jquery.tablesorter.js
resources/src/mediawiki.action/mediawiki.action.edit.styles.css
resources/src/mediawiki.legacy/commonPrint.css
resources/src/mediawiki.legacy/oldshared.css
resources/src/mediawiki.legacy/shared.css
resources/src/mediawiki.special/mediawiki.special.css
resources/src/mediawiki.special/mediawiki.special.upload.styles.css
resources/src/mediawiki/page/mediawiki.page.patrol.css [new file with mode: 0644]
resources/src/mediawiki/page/mediawiki.page.patrol.print.css [new file with mode: 0644]
tests/phpunit/includes/api/ApiLoginTest.php
tests/phpunit/includes/api/ApiTestCase.php
tests/phpunit/includes/auth/AbstractAuthenticationProviderTest.php
tests/phpunit/includes/auth/AbstractPasswordPrimaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/AbstractPreAuthenticationProviderTest.php
tests/phpunit/includes/auth/AbstractPrimaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/AbstractSecondaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/AuthManagerTest.php
tests/phpunit/includes/auth/AuthPluginPrimaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/AuthenticationRequestTest.php
tests/phpunit/includes/auth/AuthenticationRequestTestCase.php
tests/phpunit/includes/auth/AuthenticationResponseTest.php
tests/phpunit/includes/auth/CheckBlocksSecondaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/ConfirmLinkSecondaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/LegacyHookPreAuthenticationProviderTest.php
tests/phpunit/includes/auth/LocalPasswordPrimaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/ResetPasswordSecondaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/TemporaryPasswordPrimaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/ThrottlePreAuthenticationProviderTest.php
tests/phpunit/includes/auth/ThrottlerTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php
tests/phpunit/includes/session/SessionManagerTest.php
tests/phpunit/includes/user/UserTest.php
tests/phpunit/phpunit.php
tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js

index 757cec3..f26f240 100644 (file)
@@ -38,6 +38,9 @@ production.
   and the file description page, but does not run for uploads to stash.
 * (T141604) Extensions can now provide a better error message when their
   maintenance scripts are run without the extension being installed.
+* (T8948) Numeric sorting in categories is now supported by setting $wgCategoryCollation
+  to uca-default-u-kn or uca-<langcode>-u-kn. If migrating from another
+  collation, you will need to run the updateCollation.php maintenance script.
 
 === External library changes in 1.28 ===
 
index 29f986e..513ec96 100644 (file)
@@ -28,7 +28,6 @@ $wgAutoloadLocalClasses = [
        'ApiClientLogin' => __DIR__ . '/includes/api/ApiClientLogin.php',
        'ApiComparePages' => __DIR__ . '/includes/api/ApiComparePages.php',
        'ApiContinuationManager' => __DIR__ . '/includes/api/ApiContinuationManager.php',
-       'ApiCreateAccount' => __DIR__ . '/includes/api/ApiCreateAccount.php',
        'ApiDelete' => __DIR__ . '/includes/api/ApiDelete.php',
        'ApiDisabled' => __DIR__ . '/includes/api/ApiDisabled.php',
        'ApiEditPage' => __DIR__ . '/includes/api/ApiEditPage.php',
@@ -748,8 +747,6 @@ $wgAutoloadLocalClasses = [
        'LoggedOutEditToken' => __DIR__ . '/includes/user/LoggedOutEditToken.php',
        'LoggedUpdateMaintenance' => __DIR__ . '/maintenance/Maintenance.php',
        'LoginForm' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
-       'LoginFormAuthManager' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
-       'LoginFormPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialUserlogin.php',
        'LoginHelper' => __DIR__ . '/includes/specials/helpers/LoginHelper.php',
        'LoginSignupSpecialPage' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
        'LonelyPagesPage' => __DIR__ . '/includes/specials/SpecialLonelypages.php',
@@ -1281,13 +1278,10 @@ $wgAutoloadLocalClasses = [
        'SpecialChangeContentModel' => __DIR__ . '/includes/specials/SpecialChangeContentModel.php',
        'SpecialChangeCredentials' => __DIR__ . '/includes/specials/SpecialChangeCredentials.php',
        'SpecialChangeEmail' => __DIR__ . '/includes/specials/SpecialChangeEmail.php',
-       'SpecialChangeEmailPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialChangeEmail.php',
        'SpecialChangePassword' => __DIR__ . '/includes/specials/SpecialChangePassword.php',
-       'SpecialChangePasswordPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialChangePassword.php',
        'SpecialComparePages' => __DIR__ . '/includes/specials/SpecialComparePages.php',
        'SpecialContributions' => __DIR__ . '/includes/specials/SpecialContributions.php',
        'SpecialCreateAccount' => __DIR__ . '/includes/specials/SpecialCreateAccount.php',
-       'SpecialCreateAccountPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialCreateAccount.php',
        'SpecialDiff' => __DIR__ . '/includes/specials/SpecialDiff.php',
        'SpecialEditTags' => __DIR__ . '/includes/specials/SpecialEditTags.php',
        'SpecialEditWatchlist' => __DIR__ . '/includes/specials/SpecialEditWatchlist.php',
@@ -1320,7 +1314,6 @@ $wgAutoloadLocalClasses = [
        'SpecialPageLanguage' => __DIR__ . '/includes/specials/SpecialPageLanguage.php',
        'SpecialPagesWithProp' => __DIR__ . '/includes/specials/SpecialPagesWithProp.php',
        'SpecialPasswordReset' => __DIR__ . '/includes/specials/SpecialPasswordReset.php',
-       'SpecialPasswordResetPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialPasswordReset.php',
        'SpecialPermanentLink' => __DIR__ . '/includes/specials/SpecialPermanentLink.php',
        'SpecialPreferences' => __DIR__ . '/includes/specials/SpecialPreferences.php',
        'SpecialPrefixindex' => __DIR__ . '/includes/specials/SpecialPrefixindex.php',
@@ -1351,7 +1344,6 @@ $wgAutoloadLocalClasses = [
        'SpecialUploadStashTooLargeException' => __DIR__ . '/includes/specials/SpecialUploadStash.php',
        'SpecialUserLogin' => __DIR__ . '/includes/specials/SpecialUserLogin.php',
        'SpecialUserLogout' => __DIR__ . '/includes/specials/SpecialUserLogout.php',
-       'SpecialUserlogoutPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialUserlogout.php',
        'SpecialVersion' => __DIR__ . '/includes/specials/SpecialVersion.php',
        'SpecialWatchlist' => __DIR__ . '/includes/specials/SpecialWatchlist.php',
        'SpecialWhatLinksHere' => __DIR__ . '/includes/specials/SpecialWhatlinkshere.php',
@@ -1487,8 +1479,6 @@ $wgAutoloadLocalClasses = [
        'UserOptions' => __DIR__ . '/maintenance/userOptions.inc',
        'UserPasswordPolicy' => __DIR__ . '/includes/password/UserPasswordPolicy.php',
        'UserRightsProxy' => __DIR__ . '/includes/user/UserRightsProxy.php',
-       'UsercreateTemplate' => __DIR__ . '/includes/templates/Usercreate.php',
-       'UserloginTemplate' => __DIR__ . '/includes/templates/Userlogin.php',
        'UserrightsPage' => __DIR__ . '/includes/specials/SpecialUserrights.php',
        'UsersPager' => __DIR__ . '/includes/specials/pagers/UsersPager.php',
        'UtfNormal' => __DIR__ . '/includes/compat/normal/UtfNormal.php',
index 89a54d5..8fa3793 100644 (file)
@@ -1104,6 +1104,9 @@ $row: the DB row for this line
 $id: User identifier
 $title: User page title
 &$tools: Array of tool links
+$specialPage: SpecialPage instance for context and services. Can be either
+  SpecialContributions or DeletedContributionsPage. Extensions should type
+  hint against a generic SpecialPage though.
 
 'ConvertContent': Called by AbstractContent::convert when a conversion to
 another content model is requested.
@@ -1142,6 +1145,85 @@ $page: SpecialPage object for DeletedContributions
 $row: the DB row for this line
 &$classes: the classes to add to the surrounding <li>
 
+'DifferenceEngineMarkPatrolledLink': Allows extensions to change the "mark as patrolled" link
+which is shown both on the diff header as well as on the bottom of a page, usually
+wrapped in a span element which has class="patrollink".
+$differenceEngine: DifferenceEngine object
+&$markAsPatrolledLink: The "mark as patrolled" link HTML (string)
+$rcid: Recent change ID (rc_id) for this change (int)
+$token: Patrol token; $rcid is used in generating this variable
+
+'DifferenceEngineMarkPatrolledRCID': Allows extensions to possibly change the rcid parameter.
+For example the rcid might be set to zero due to the user being the same as the
+performer of the change but an extension might still want to show it under certain
+conditions.
+&$rcid: rc_id (int) of the change or 0
+$differenceEngine: DifferenceEngine object
+$change: RecentChange object
+$user: User object representing the current user
+
+'DifferenceEngineNewHeader': Allows extensions to change the $newHeader variable, which
+contains information about the new revision, such as the revision's author, whether
+the revision was marked as a minor edit or not, etc.
+$differenceEngine: DifferenceEngine object
+&$newHeader: The string containing the various #mw-diff-otitle[1-5] divs, which
+include things like revision author info, revision comment, RevisionDelete link and more
+$formattedRevisionTools: Array containing revision tools, some of which may have
+been injected with the DiffRevisionTools hook
+$nextlink: String containing the link to the next revision (if any); also included in $newHeader
+$rollback: Rollback link (string) to roll this revision back to the previous one, if any
+$newminor: String indicating if the new revision was marked as a minor edit
+$diffOnly: Boolean parameter passed to DifferenceEngine#showDiffPage, indicating
+whether we should show just the diff; passed in as a query string parameter to the
+various URLs constructed here (i.e. $nextlink)
+$rdel: RevisionDelete link for the new revision, if the current user is allowed
+to use the RevisionDelete feature
+$unhide: Boolean parameter indicating whether to show RevisionDeleted revisions
+
+'DifferenceEngineOldHeader': Allows extensions to change the $oldHeader variable, which
+contains information about the old revision, such as the revision's author, whether
+the revision was marked as a minor edit or not, etc.
+$differenceEngine: DifferenceEngine object
+&$oldHeader: The string containing the various #mw-diff-otitle[1-5] divs, which
+include things like revision author info, revision comment, RevisionDelete link and more
+$prevlink: String containing the link to the previous revision (if any); also included in $oldHeader
+$oldminor: String indicating if the old revision was marked as a minor edit
+$diffOnly: Boolean parameter passed to DifferenceEngine#showDiffPage, indicating
+whether we should show just the diff; passed in as a query string parameter to the
+various URLs constructed here (i.e. $prevlink)
+$ldel: RevisionDelete link for the old revision, if the current user is allowed
+to use the RevisionDelete feature
+$unhide: Boolean parameter indicating whether to show RevisionDeleted revisions
+
+'DifferenceEngineOldHeaderNoOldRev': Change the $oldHeader variable in cases when
+there is no old revision
+&$oldHeader: empty string by default
+
+'DifferenceEngineRenderRevisionAddParserOutput': Allows extensions to change the parser output.
+Return false to not add parser output via OutputPage's addParserOutput method.
+$differenceEngine: DifferenceEngine object
+$out: OutputPage object
+$parserOutput: ParserOutput object
+$wikiPage: WikiPage object
+
+DifferenceEngineRenderRevisionShowFinalPatrolLink': An extension can hook into this hook
+point and return false to not show the final "mark as patrolled" link on the bottom
+of a page.
+This hook has no arguments.
+
+'DifferenceEngineShowDiff': Allows extensions to affect the diff text which
+eventually gets sent to the OutputPage object.
+$differenceEngine: DifferenceEngine object
+
+'DifferenceEngineShowEmptyOldContent': Allows extensions to change the diff table
+body (without header) in cases when there is no old revision or the old and new
+revisions are identical.
+$differenceEngine: DifferenceEngine object
+
+'DifferenceEngineShowDiffPage': Add additional output via the available OutputPage
+object into the diff view
+$out: OutputPage object
+
 'DiffRevisionTools': Override or extend the revision tools available from the
 diff view, i.e. undo, etc.
 $newRev: Revision object of the "new" revision
index 3f0528e..3d5e6c5 100644 (file)
@@ -33,8 +33,8 @@
  *
  *     $cf = new CategoryFinder;
  *     $cf->seed(
- *         array( 12345 ),
- *         array( 'Category 1', 'Category 2' ),
+ *         [ 12345 ],
+ *         [ 'Category 1', 'Category 2' ],
  *         'AND'
  *     );
  *     $a = $cf->run();
@@ -49,7 +49,7 @@ class CategoryFinder {
        /** @var array Array of DBKEY category names for categories that don't have a page */
        protected $deadend = [];
 
-       /** @var array Array of [ID => array()] */
+       /** @var array Array of [ ID => [] ] */
        protected $parents = [];
 
        /** @var array Array of article/category IDs */
index 3c5e2d2..8363b32 100644 (file)
@@ -4447,13 +4447,6 @@ $wgPasswordPolicy = [
        ],
 ];
 
-/**
- * Disable AuthManager
- * @since 1.27
- * @deprecated since 1.27, for use during development only
- */
-$wgDisableAuthManager = false;
-
 /**
  * Configure AuthManager
  *
@@ -8173,13 +8166,6 @@ $wgTextModelsToParse = [
        CONTENT_MODEL_CSS, // Make categories etc work, people put them into comments.
 ];
 
-/**
- * Whether the user must enter their password to change their e-mail address
- *
- * @since 1.20
- */
-$wgRequirePasswordforEmailChange = true;
-
 /**
  * Register handlers for specific types of sites.
  *
index 674cf28..ee06993 100644 (file)
@@ -2714,8 +2714,9 @@ class EditPage {
                $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'hiddencats' ],
                        Linker::formatHiddenCategories( $this->page->getHiddenCategories() ) ) );
 
-               $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'limitreport' ],
-                       self::getPreviewLimitReport( $this->mParserOutput ) ) );
+               if ( $this->mParserOutput ) {
+                       $wgOut->setLimitReportData( $this->mParserOutput->getLimitReportData() );
+               }
 
                $wgOut->addModules( 'mediawiki.action.edit.collapsibleFooter' );
 
@@ -3442,41 +3443,12 @@ HTML
                        return '';
                }
 
-               $limitReport = Html::rawElement( 'div', [ 'class' => 'mw-limitReportExplanation' ],
-                       wfMessage( 'limitreport-title' )->parseAsBlock()
+               return ResourceLoader::makeInlineScript(
+                       ResourceLoader::makeConfigSetScript(
+                               [ 'wgPageParseReport' => $output->getLimitReportData() ],
+                               true
+                       )
                );
-
-               // Show/hide animation doesn't work correctly on a table, so wrap it in a div.
-               $limitReport .= Html::openElement( 'div', [ 'class' => 'preview-limit-report-wrapper' ] );
-
-               $limitReport .= Html::openElement( 'table', [
-                       'class' => 'preview-limit-report wikitable'
-               ] ) .
-                       Html::openElement( 'tbody' );
-
-               foreach ( $output->getLimitReportData() as $key => $value ) {
-                       if ( Hooks::run( 'ParserLimitReportFormat',
-                               [ $key, &$value, &$limitReport, true, true ]
-                       ) ) {
-                               $keyMsg = wfMessage( $key );
-                               $valueMsg = wfMessage( [ "$key-value-html", "$key-value" ] );
-                               if ( !$valueMsg->exists() ) {
-                                       $valueMsg = new RawMessage( '$1' );
-                               }
-                               if ( !$keyMsg->isDisabled() && !$valueMsg->isDisabled() ) {
-                                       $limitReport .= Html::openElement( 'tr' ) .
-                                               Html::rawElement( 'th', null, $keyMsg->parse() ) .
-                                               Html::rawElement( 'td', null, $valueMsg->params( $value )->parse() ) .
-                                               Html::closeElement( 'tr' );
-                               }
-                       }
-               }
-
-               $limitReport .= Html::closeElement( 'tbody' ) .
-                       Html::closeElement( 'table' ) .
-                       Html::closeElement( 'div' );
-
-               return $limitReport;
        }
 
        protected function showStandardInputs( &$tabindex = 2 ) {
index 21857b9..7dac0ec 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
 
 /**
  * The MediaWiki class is the helper class for the index.php entry point.
@@ -761,8 +762,9 @@ class MediaWiki {
         * @param string $mode Use 'fast' to always skip job running
         */
        public function restInPeace( $mode = 'fast' ) {
+               $factory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
                // Assure deferred updates are not in the main transaction
-               wfGetLBFactory()->commitMasterChanges( __METHOD__ );
+               $factory->commitMasterChanges( __METHOD__ );
 
                // Loosen DB query expectations since the HTTP client is unblocked
                $trxProfiler = Profiler::instance()->getTransactionProfiler();
@@ -788,7 +790,6 @@ class MediaWiki {
                wfLogProfilingData();
 
                // Commit and close up!
-               $factory = wfGetLBFactory();
                $factory->commitMasterChanges( __METHOD__ );
                $factory->shutdown( LBFactory::SHUTDOWN_NO_CHRONPROT );
 
index b6c48ab..b88db92 100644 (file)
@@ -1773,7 +1773,7 @@ class OutputPage extends ContextSource {
                }
 
                // Include profiling data
-               $this->limitReportData = $parserOutput->getLimitReportData();
+               $this->setLimitReportData( $parserOutput->getLimitReportData() );
 
                // Link flags are ignored for now, but may in the future be
                // used to mark individual language links.
@@ -4051,4 +4051,12 @@ class OutputPage extends ContextSource {
                // public API or you'll be severely disappointed when T87871 is fixed and it disappears.
                $this->addMeta( 'X-OOUI-PHP', '1' );
        }
+
+       /**
+        * @param array $data Data from ParserOutput::getLimitReportData()
+        * @since 1.28
+        */
+       public function setLimitReportData( array $data ) {
+               $this->limitReportData = $data;
+       }
 }
index 3083a8d..70addfc 100644 (file)
@@ -207,8 +207,9 @@ class Preferences {
         * @return void
         */
        static function profilePreferences( $user, IContextSource $context, &$defaultPreferences ) {
-               global $wgAuth, $wgContLang, $wgParser, $wgDisableAuthManager;
+               global $wgContLang, $wgParser;
 
+               $authManager = AuthManager::singleton();
                $config = $context->getConfig();
                // retrieving user name for GENDER and misc.
                $userName = $user->getName();
@@ -283,21 +284,19 @@ class Preferences {
                $canEditPrivateInfo = $user->isAllowed( 'editmyprivateinfo' );
 
                // Actually changeable stuff
-               $realnameChangeAllowed = $wgDisableAuthManager ? $wgAuth->allowPropChange( 'realname' )
-                       : AuthManager::singleton()->allowsPropertyChange( 'realname' );
                $defaultPreferences['realname'] = [
                        // (not really "private", but still shouldn't be edited without permission)
-                       'type' => $canEditPrivateInfo && $realnameChangeAllowed ? 'text' : 'info',
+                       'type' => $canEditPrivateInfo && $authManager->allowsPropertyChange( 'realname' )
+                               ? 'text' : 'info',
                        'default' => $user->getRealName(),
                        'section' => 'personal/info',
                        'label-message' => 'yourrealname',
                        'help-message' => 'prefs-help-realname',
                ];
 
-               $allowPasswordChange = $wgDisableAuthManager ? $wgAuth->allowPasswordChange()
-                       : AuthManager::singleton()->allowsAuthenticationDataChange(
-                               new PasswordAuthenticationRequest(), false )->isGood();
-               if ( $canEditPrivateInfo && $allowPasswordChange ) {
+               if ( $canEditPrivateInfo && $authManager->allowsAuthenticationDataChange(
+                       new PasswordAuthenticationRequest(), false )->isGood()
+               ) {
                        $link = Linker::link( SpecialPage::getTitleFor( 'ChangePassword' ),
                                $context->msg( 'prefs-resetpass' )->escaped(), [],
                                [ 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ] );
@@ -418,10 +417,8 @@ class Preferences {
                        'default' => $oldsigHTML,
                        'section' => 'personal/signature',
                ];
-               $nicknameChangeAllowed = $wgDisableAuthManager ? $wgAuth->allowPropChange( 'nickname' )
-                       : AuthManager::singleton()->allowsPropertyChange( 'nickname' );
                $defaultPreferences['nickname'] = [
-                       'type' => $nicknameChangeAllowed ? 'text' : 'info',
+                       'type' => $authManager->allowsPropertyChange( 'nickname' ) ? 'text' : 'info',
                        'maxlength' => $config->get( 'MaxSigChars' ),
                        'label-message' => 'yournick',
                        'validation-callback' => [ 'Preferences', 'validateSignature' ],
@@ -450,9 +447,7 @@ class Preferences {
                                }
 
                                $emailAddress = $user->getEmail() ? htmlspecialchars( $user->getEmail() ) : '';
-                               $emailChangeAllowed = $wgDisableAuthManager ? $wgAuth->allowPropChange( 'emailaddress' )
-                                       : AuthManager::singleton()->allowsPropertyChange( 'emailaddress' );
-                               if ( $canEditPrivateInfo && $emailChangeAllowed ) {
+                               if ( $canEditPrivateInfo && $authManager->allowsPropertyChange( 'emailaddress' ) ) {
                                        $link = Linker::link(
                                                SpecialPage::getTitleFor( 'ChangeEmail' ),
                                                $context->msg( $user->getEmail() ? 'prefs-changeemail' : 'prefs-setemail' )->escaped(),
index 6c5de90..7909889 100644 (file)
@@ -452,22 +452,6 @@ if ( $wgProfileOnly ) {
        $wgDebugLogFile = '';
 }
 
-// Disable AuthManager API modules if $wgDisableAuthManager
-if ( $wgDisableAuthManager ) {
-       $wgAPIModules += [
-               'clientlogin' => 'ApiDisabled',
-               'createaccount' => 'ApiCreateAccount', // Use the non-AuthManager version
-               'linkaccount' => 'ApiDisabled',
-               'unlinkaccount' => 'ApiDisabled',
-               'changeauthenticationdata' => 'ApiDisabled',
-               'removeauthenticationdata' => 'ApiDisabled',
-               'resetpassword' => 'ApiDisabled',
-       ];
-       $wgAPIMetaModules += [
-               'authmanagerinfo' => 'ApiQueryDisabled',
-       ];
-}
-
 // Backwards compatibility with old password limits
 if ( $wgMinimalPasswordLength !== false ) {
        $wgPasswordPolicy['policies']['default']['MinimalPasswordLength'] = $wgMinimalPasswordLength;
@@ -711,12 +695,10 @@ $wgContLang->initContLang();
 $wgRequest->interpolateTitle();
 
 if ( !is_object( $wgAuth ) ) {
-       $wgAuth = $wgDisableAuthManager ? new AuthPlugin : new MediaWiki\Auth\AuthManagerAuthPlugin;
+       $wgAuth = new MediaWiki\Auth\AuthManagerAuthPlugin;
        Hooks::run( 'AuthPluginSetup', [ &$wgAuth ] );
 }
-if ( !$wgDisableAuthManager &&
-       $wgAuth && !$wgAuth instanceof MediaWiki\Auth\AuthManagerAuthPlugin
-) {
+if ( $wgAuth && !$wgAuth instanceof MediaWiki\Auth\AuthManagerAuthPlugin ) {
        MediaWiki\Auth\AuthManager::singleton()->forcePrimaryAuthenticationProviders( [
                new MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider( [
                        'authoritative' => false,
@@ -852,15 +834,11 @@ if ( !defined( 'MW_NO_SESSION' ) && !$wgCommandLineMode ) {
        $sessionUser = MediaWiki\Session\SessionManager::getGlobalSession()->getUser();
        if ( $sessionUser->getId() === 0 && User::isValidUserName( $sessionUser->getName() ) ) {
                $ps_autocreate = Profiler::instance()->scopedProfileIn( $fname . '-autocreate' );
-               if ( $wgDisableAuthManager ) {
-                       $res = MediaWiki\Session\SessionManager::autoCreateUser( $sessionUser );
-               } else {
-                       $res = MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
-                               $sessionUser,
-                               MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
-                               true
-                       );
-               }
+               $res = MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
+                       $sessionUser,
+                       MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
+                       true
+               );
                Profiler::instance()->scopedProfileOut( $ps_autocreate );
                \MediaWiki\Logger\LoggerFactory::getInstance( 'authmanager' )->info( 'Autocreation attempt', [
                        'event' => 'autocreate',
index 6c536dd..03b4b8c 100644 (file)
@@ -24,7 +24,7 @@
  * Static accessor class for site_stats and related things
  */
 class SiteStats {
-       /** @var bool|ResultWrapper */
+       /** @var bool|stdClass */
        private static $row;
 
        /** @var bool */
@@ -62,7 +62,7 @@ class SiteStats {
        }
 
        /**
-        * @return bool|ResultWrapper
+        * @return bool|stdClass
         */
        static function loadAndLazyInit() {
                global $wgMiserMode;
@@ -96,7 +96,7 @@ class SiteStats {
 
        /**
         * @param IDatabase $db
-        * @return bool|ResultWrapper
+        * @return bool|stdClass
         */
        static function doLoad( $db ) {
                return $db->selectRow( 'site_stats', [
@@ -107,7 +107,7 @@ class SiteStats {
                                'ss_users',
                                'ss_active_users',
                                'ss_images',
-                       ], false, __METHOD__ );
+                       ], [], __METHOD__ );
        }
 
        /**
index f8f1dc1..7f043e4 100644 (file)
@@ -50,7 +50,8 @@ class UnwatchAction extends WatchAction {
        }
 
        public function onSuccess() {
-               $this->getOutput()->addWikiMsg( 'removedwatchtext', $this->getTitle()->getPrefixedText() );
+               $msgKey = $this->getTitle()->isTalkPage() ? 'removedwatchtext-talk' : 'removedwatchtext';
+               $this->getOutput()->addWikiMsg( $msgKey, $this->getTitle()->getPrefixedText() );
        }
 
        public function doesWrites() {
index 890740f..23505c0 100644 (file)
@@ -67,7 +67,8 @@ class WatchAction extends FormAction {
        }
 
        public function onSuccess() {
-               $this->getOutput()->addWikiMsg( 'addedwatchtext', $this->getTitle()->getPrefixedText() );
+               $msgKey = $this->getTitle()->isTalkPage() ? 'addedwatchtext-talk' : 'addedwatchtext';
+               $this->getOutput()->addWikiMsg( $msgKey, $this->getTitle()->getPrefixedText() );
        }
 
        /* Static utility methods */
index 52a7951..2511e3b 100644 (file)
@@ -66,13 +66,15 @@ class ApiAMCreateAccount extends ApiBase {
                $helper = new ApiAuthManagerHelper( $this );
                $manager = AuthManager::singleton();
 
-               // Make sure it's possible to log in
+               // Make sure it's possible to create accounts
                if ( !$manager->canCreateAccounts() ) {
                        $this->getResult()->addValue( null, 'createaccount', $helper->formatAuthenticationResponse(
                                AuthenticationResponse::newFail(
                                        $this->msg( 'userlogin-cannot-' . AuthManager::ACTION_CREATE )
                                )
                        ) );
+                       $helper->logAuthenticationResult( 'accountcreation',
+                               'userlogin-cannot-' . AuthManager::ACTION_CREATE );
                        return;
                }
 
@@ -93,6 +95,7 @@ class ApiAMCreateAccount extends ApiBase {
 
                $this->getResult()->addValue( null, 'createaccount',
                        $helper->formatAuthenticationResponse( $res ) );
+               $helper->logAuthenticationResult( 'accountcreation', $res );
        }
 
        public function isReadMode() {
index e30f22b..fe5675a 100644 (file)
@@ -25,6 +25,7 @@ use MediaWiki\Auth\AuthManager;
 use MediaWiki\Auth\AuthenticationRequest;
 use MediaWiki\Auth\AuthenticationResponse;
 use MediaWiki\Auth\CreateFromLoginAuthenticationRequest;
+use MediaWiki\Logger\LoggerFactory;
 
 /**
  * Helper class for AuthManager-using API modules. Intended for use via
@@ -220,6 +221,30 @@ class ApiAuthManagerHelper {
                return $ret;
        }
 
+       /**
+        * Logs successful or failed authentication.
+        * @param string|AuthenticationResponse $result Response or error message
+        * @param string $event Event type (e.g. 'accountcreation')
+        */
+       public function logAuthenticationResult( $event, $result ) {
+               if ( is_string( $result ) ) {
+                       $status = Status::newFatal( $result );
+               } elseif ( $result->status === AuthenticationResponse::PASS ) {
+                       $status = Status::newGood();
+               } elseif ( $result->status === AuthenticationResponse::FAIL ) {
+                       $status = Status::newFatal( $result->message );
+               } else {
+                       return;
+               }
+
+               $module = $this->module->getModuleName();
+               LoggerFactory::getInstance( 'authmanager' )->info( "$module API attempt", [
+                       'event' => $event,
+                       'status' => $status,
+                       'module' => $module,
+               ] );
+       }
+
        /**
         * Fetch the preserved CreateFromLoginAuthenticationRequest, if any
         * @return CreateFromLoginAuthenticationRequest|null
index 8e5a3c7..cbb1524 100644 (file)
@@ -72,6 +72,7 @@ class ApiClientLogin extends ApiBase {
                        $this->getResult()->addValue( null, 'clientlogin', $helper->formatAuthenticationResponse(
                                AuthenticationResponse::newFail( $this->msg( 'userlogin-cannot-' . AuthManager::ACTION_LOGIN ) )
                        ) );
+                       $helper->logAuthenticationResult( 'login', 'userlogin-cannot-' . AuthManager::ACTION_LOGIN );
                        return;
                }
 
@@ -99,6 +100,7 @@ class ApiClientLogin extends ApiBase {
 
                $this->getResult()->addValue( null, 'clientlogin',
                        $helper->formatAuthenticationResponse( $res ) );
+               $helper->logAuthenticationResult( 'login', $res );
        }
 
        public function isReadMode() {
diff --git a/includes/api/ApiCreateAccount.php b/includes/api/ApiCreateAccount.php
deleted file mode 100644 (file)
index 6a48610..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-<?php
-/**
- * Created on August 7, 2012
- *
- * Copyright © 2012 Tyler Romeo <tylerromeo@gmail.com>
- *
- * 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
- */
-use MediaWiki\Logger\LoggerFactory;
-
-/**
- * Unit to authenticate account registration attempts to the current wiki.
- *
- * @ingroup API
- * @deprecated since 1.27, only used when $wgDisableAuthManager is true
- */
-class ApiCreateAccount extends ApiBase {
-       public function execute() {
-               // If we're in a mode that breaks the same-origin policy, no tokens can
-               // be obtained
-               if ( $this->lacksSameOriginSecurity() ) {
-                       $this->dieUsage(
-                               'Cannot create account when the same-origin policy is not applied', 'aborted'
-                       );
-               }
-
-               // $loginForm->addNewaccountInternal will throw exceptions
-               // if wiki is read only (already handled by api), user is blocked or does not have rights.
-               // Use userCan in order to hit GlobalBlock checks (according to Special:userlogin)
-               $loginTitle = SpecialPage::getTitleFor( 'Userlogin' );
-               if ( !$loginTitle->userCan( 'createaccount', $this->getUser() ) ) {
-                       $this->dieUsage(
-                               'You do not have the right to create a new account',
-                               'permdenied-createaccount'
-                       );
-               }
-               if ( $this->getUser()->isBlockedFromCreateAccount() ) {
-                       $this->dieUsage(
-                               'You cannot create a new account because you are blocked',
-                               'blocked',
-                               0,
-                               [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $this->getUser()->getBlock() ) ]
-                       );
-               }
-
-               $params = $this->extractRequestParams();
-
-               // Make sure session is persisted
-               MediaWiki\Session\SessionManager::getGlobalSession()->persist();
-
-               if ( $params['mailpassword'] && !$params['email'] ) {
-                       $this->dieUsageMsg( 'noemail' );
-               }
-
-               if ( $params['language'] && !Language::isSupportedLanguage( $params['language'] ) ) {
-                       $this->dieUsage( 'Invalid language parameter', 'langinvalid' );
-               }
-
-               $context = new DerivativeContext( $this->getContext() );
-               $context->setRequest( new DerivativeRequest(
-                       $this->getContext()->getRequest(),
-                       [
-                               'type' => 'signup',
-                               'uselang' => $params['language'],
-                               'wpName' => $params['name'],
-                               'wpPassword' => $params['password'],
-                               'wpRetype' => $params['password'],
-                               'wpDomain' => $params['domain'],
-                               'wpEmail' => $params['email'],
-                               'wpRealName' => $params['realname'],
-                               'wpCreateaccountToken' => $params['token'],
-                               'wpCreateaccount' => $params['mailpassword'] ? null : '1',
-                               'wpCreateaccountMail' => $params['mailpassword'] ? '1' : null
-                       ]
-               ) );
-
-               $loginForm = new LoginForm();
-               $loginForm->setContext( $context );
-               Hooks::run( 'AddNewAccountApiForm', [ $this, $loginForm ] );
-               $loginForm->load();
-
-               $status = $loginForm->addNewAccountInternal();
-               LoggerFactory::getInstance( 'authmanager' )->info( 'Account creation attempt via API', [
-                       'event' => 'accountcreation',
-                       'status' => $status,
-               ] );
-               $result = [];
-               if ( $status->isGood() ) {
-                       // Success!
-                       $user = $status->getValue();
-
-                       if ( $params['language'] ) {
-                               $user->setOption( 'language', $params['language'] );
-                       }
-
-                       if ( $params['mailpassword'] ) {
-                               // If mailpassword was set, disable the password and send an email.
-                               $user->setPassword( null );
-                               $status->merge( $loginForm->mailPasswordInternal(
-                                       $user,
-                                       false,
-                                       'createaccount-title',
-                                       'createaccount-text'
-                               ) );
-                       } elseif ( $this->getConfig()->get( 'EmailAuthentication' ) &&
-                               Sanitizer::validateEmail( $user->getEmail() )
-                       ) {
-                               // Send out an email authentication message if needed
-                               $status->merge( $user->sendConfirmationMail() );
-                       }
-
-                       // Save settings (including confirmation token)
-                       $user->saveSettings();
-
-                       Hooks::run( 'AddNewAccount', [ $user, $params['mailpassword'] ] );
-
-                       if ( $params['mailpassword'] ) {
-                               $logAction = 'byemail';
-                       } elseif ( $this->getUser()->isLoggedIn() ) {
-                               $logAction = 'create2';
-                       } else {
-                               $logAction = 'create';
-                       }
-                       $user->addNewUserLogEntry( $logAction, (string)$params['reason'] );
-
-                       // Add username, id, and token to result.
-                       $result['username'] = $user->getName();
-                       $result['userid'] = $user->getId();
-                       $result['token'] = $user->getToken();
-               }
-
-               $apiResult = $this->getResult();
-
-               if ( $status->hasMessage( 'sessionfailure' ) || $status->hasMessage( 'nocookiesfornew' ) ) {
-                       // Token was incorrect, so add it to result, but don't throw an exception
-                       // since not having the correct token is part of the normal
-                       // flow of events.
-                       $result['token'] = LoginForm::getCreateaccountToken()->toString();
-                       $result['result'] = 'NeedToken';
-                       $this->setWarning( 'Fetching a token via action=createaccount is deprecated. ' .
-                               'Use action=query&meta=tokens&type=createaccount instead.' );
-                       $this->logFeatureUsage( 'action=createaccount&!token' );
-               } elseif ( !$status->isOK() ) {
-                       // There was an error. Die now.
-                       $this->dieStatus( $status );
-               } elseif ( !$status->isGood() ) {
-                       // Status is not good, but OK. This means warnings.
-                       $result['result'] = 'Warning';
-
-                       // Add any warnings to the result
-                       $warnings = $status->getErrorsByType( 'warning' );
-                       if ( $warnings ) {
-                               foreach ( $warnings as &$warning ) {
-                                       ApiResult::setIndexedTagName( $warning['params'], 'param' );
-                               }
-                               ApiResult::setIndexedTagName( $warnings, 'warning' );
-                               $result['warnings'] = $warnings;
-                       }
-               } else {
-                       // Everything was fine.
-                       $result['result'] = 'Success';
-               }
-
-               // Give extensions a chance to modify the API result data
-               Hooks::run( 'AddNewAccountApiResult', [ $this, $loginForm, &$result ] );
-
-               $apiResult->addValue( null, 'createaccount', $result );
-       }
-
-       public function mustBePosted() {
-               return true;
-       }
-
-       public function isReadMode() {
-               return false;
-       }
-
-       public function isWriteMode() {
-               return true;
-       }
-
-       public function getAllowedParams() {
-               return [
-                       'name' => [
-                               ApiBase::PARAM_TYPE => 'user',
-                               ApiBase::PARAM_REQUIRED => true
-                       ],
-                       'password' => [
-                               ApiBase::PARAM_TYPE => 'password',
-                       ],
-                       'domain' => null,
-                       'token' => [
-                               ApiBase::PARAM_TYPE => 'string',
-                               ApiBase::PARAM_REQUIRED => false, // for BC
-                               ApiBase::PARAM_HELP_MSG => [ 'api-help-param-token', 'createaccount' ],
-                       ],
-                       'email' => [
-                               ApiBase::PARAM_TYPE => 'string',
-                               ApiBase::PARAM_REQUIRED => $this->getConfig()->get( 'EmailConfirmToEdit' ),
-                       ],
-                       'realname' => null,
-                       'mailpassword' => [
-                               ApiBase::PARAM_TYPE => 'boolean',
-                               ApiBase::PARAM_DFLT => false
-                       ],
-                       'reason' => null,
-                       'language' => null
-               ];
-       }
-
-       protected function getExamplesMessages() {
-               return [
-                       'action=createaccount&name=testuser&password=test123'
-                               => 'apihelp-createaccount-example-pass',
-                       'action=createaccount&name=testmailuser&mailpassword=true&reason=MyReason'
-                               => 'apihelp-createaccount-example-mail',
-               ];
-       }
-
-       public function getHelpUrls() {
-               return 'https://www.mediawiki.org/wiki/API:Account_creation';
-       }
-}
index 1dadc07..b9f65b3 100644 (file)
@@ -42,9 +42,7 @@ class ApiLogin extends ApiBase {
        }
 
        protected function getDescriptionMessage() {
-               if ( $this->getConfig()->get( 'DisableAuthManager' ) ) {
-                       return 'apihelp-login-description-nonauthmanager';
-               } elseif ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
+               if ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
                        return 'apihelp-login-description';
                } else {
                        return 'apihelp-login-description-nobotpasswords';
@@ -124,85 +122,52 @@ class ApiLogin extends ApiBase {
                }
 
                if ( $authRes === false ) {
-                       if ( $this->getConfig()->get( 'DisableAuthManager' ) ) {
-                               // Non-AuthManager login
-                               $context->setRequest( new DerivativeRequest(
-                                       $this->getContext()->getRequest(),
-                                       [
-                                               'wpName' => $params['name'],
-                                               'wpPassword' => $params['password'],
-                                               'wpDomain' => $params['domain'],
-                                               'wpLoginToken' => $params['token'],
-                                               'wpRemember' => ''
-                                       ]
-                               ) );
-                               $loginForm = new LoginForm();
-                               $loginForm->setContext( $context );
-                               $authRes = $loginForm->authenticateUserData();
-                               $loginType = 'LoginForm';
-
-                               switch ( $authRes ) {
-                                       case LoginForm::SUCCESS:
-                                               $authRes = 'Success';
-                                               break;
-                                       case LoginForm::NEED_TOKEN:
-                                               $authRes = 'NeedToken';
-                                               break;
-                               }
-                       } else {
-                               // Simplified AuthManager login, for backwards compatibility
-                               $manager = AuthManager::singleton();
-                               $reqs = AuthenticationRequest::loadRequestsFromSubmission(
-                                       $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN, $this->getUser() ),
-                                       [
-                                               'username' => $params['name'],
-                                               'password' => $params['password'],
-                                               'domain' => $params['domain'],
-                                               'rememberMe' => true,
-                                       ]
-                               );
-                               $res = AuthManager::singleton()->beginAuthentication( $reqs, 'null:' );
-                               switch ( $res->status ) {
-                                       case AuthenticationResponse::PASS:
-                                               if ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
-                                                       $warn = 'Main-account login via action=login is deprecated and may stop working ' .
-                                                               'without warning.';
-                                                       $warn .= ' To continue login with action=login, see [[Special:BotPasswords]].';
-                                                       $warn .= ' To safely continue using main-account login, see action=clientlogin.';
-                                               } else {
-                                                       $warn = 'Login via action=login is deprecated and may stop working without warning.';
-                                                       $warn .= ' To safely log in, see action=clientlogin.';
-                                               }
-                                               $this->setWarning( $warn );
-                                               $authRes = 'Success';
-                                               $loginType = 'AuthManager';
-                                               break;
-
-                                       case AuthenticationResponse::FAIL:
-                                               // Hope it's not a PreAuthenticationProvider that failed...
-                                               $authRes = 'Failed';
-                                               $message = $res->message;
-                                               \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
-                                                       ->info( __METHOD__ . ': Authentication failed: ' . $message->plain() );
-                                               break;
-
-                                       default:
-                                               $authRes = 'Aborted';
-                                               break;
-                               }
+                       // Simplified AuthManager login, for backwards compatibility
+                       $manager = AuthManager::singleton();
+                       $reqs = AuthenticationRequest::loadRequestsFromSubmission(
+                               $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN, $this->getUser() ),
+                               [
+                                       'username' => $params['name'],
+                                       'password' => $params['password'],
+                                       'domain' => $params['domain'],
+                                       'rememberMe' => true,
+                               ]
+                       );
+                       $res = AuthManager::singleton()->beginAuthentication( $reqs, 'null:' );
+                       switch ( $res->status ) {
+                               case AuthenticationResponse::PASS:
+                                       if ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
+                                               $warn = 'Main-account login via action=login is deprecated and may stop working ' .
+                                                       'without warning.';
+                                               $warn .= ' To continue login with action=login, see [[Special:BotPasswords]].';
+                                               $warn .= ' To safely continue using main-account login, see action=clientlogin.';
+                                       } else {
+                                               $warn = 'Login via action=login is deprecated and may stop working without warning.';
+                                               $warn .= ' To safely log in, see action=clientlogin.';
+                                       }
+                                       $this->setWarning( $warn );
+                                       $authRes = 'Success';
+                                       $loginType = 'AuthManager';
+                                       break;
+
+                               case AuthenticationResponse::FAIL:
+                                       // Hope it's not a PreAuthenticationProvider that failed...
+                                       $authRes = 'Failed';
+                                       $message = $res->message;
+                                       \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
+                                               ->info( __METHOD__ . ': Authentication failed: ' . $message->plain() );
+                                       break;
+
+                               default:
+                                       $authRes = 'Aborted';
+                                       break;
                        }
                }
 
                $result['result'] = $authRes;
                switch ( $authRes ) {
                        case 'Success':
-                               if ( $this->getConfig()->get( 'DisableAuthManager' ) ) {
-                                       $user = $context->getUser();
-                                       $this->getContext()->setUser( $user );
-                                       $user->setCookies( $this->getRequest(), null, true );
-                               } else {
-                                       $user = $session->getUser();
-                               }
+                               $user = $session->getUser();
 
                                ApiQueryInfo::resetTokenCache();
 
@@ -212,6 +177,15 @@ class ApiLogin extends ApiBase {
 
                                $result['lguserid'] = intval( $user->getId() );
                                $result['lgusername'] = $user->getName();
+
+                               // @todo: These are deprecated, and should be removed at some
+                               // point (1.28 at the earliest, and see T121527). They were ok
+                               // when the core cookie-based login was the only thing, but
+                               // CentralAuth broke that a while back and
+                               // SessionManager/AuthManager *really* break it.
+                               $result['lgtoken'] = $user->getToken();
+                               $result['cookieprefix'] = $this->getConfig()->get( 'CookiePrefix' );
+                               $result['sessionid'] = $session->getId();
                                break;
 
                        case 'NeedToken':
@@ -219,6 +193,10 @@ class ApiLogin extends ApiBase {
                                $this->setWarning( 'Fetching a token via action=login is deprecated. ' .
                                   'Use action=query&meta=tokens&type=login instead.' );
                                $this->logFeatureUsage( 'action=login&!lgtoken' );
+
+                               // @todo: See above about deprecation
+                               $result['cookieprefix'] = $this->getConfig()->get( 'CookiePrefix' );
+                               $result['sessionid'] = $session->getId();
                                break;
 
                        case 'WrongToken':
@@ -239,65 +217,6 @@ class ApiLogin extends ApiBase {
                                }
                                break;
 
-                       // Results from LoginForm for when $wgDisableAuthManager is true
-                       case LoginForm::WRONG_TOKEN:
-                               $result['result'] = 'WrongToken';
-                               break;
-
-                       case LoginForm::NO_NAME:
-                               $result['result'] = 'NoName';
-                               break;
-
-                       case LoginForm::ILLEGAL:
-                               $result['result'] = 'Illegal';
-                               break;
-
-                       case LoginForm::WRONG_PLUGIN_PASS:
-                               $result['result'] = 'WrongPluginPass';
-                               break;
-
-                       case LoginForm::NOT_EXISTS:
-                               $result['result'] = 'NotExists';
-                               break;
-
-                       // bug 20223 - Treat a temporary password as wrong. Per SpecialUserLogin:
-                       // The e-mailed temporary password should not be used for actual logins.
-                       case LoginForm::RESET_PASS:
-                       case LoginForm::WRONG_PASS:
-                               $result['result'] = 'WrongPass';
-                               break;
-
-                       case LoginForm::EMPTY_PASS:
-                               $result['result'] = 'EmptyPass';
-                               break;
-
-                       case LoginForm::CREATE_BLOCKED:
-                               $result['result'] = 'CreateBlocked';
-                               $result['details'] = 'Your IP address is blocked from account creation';
-                               $block = $context->getUser()->getBlock();
-                               if ( $block ) {
-                                       $result = array_merge( $result, ApiQueryUserInfo::getBlockInfo( $block ) );
-                               }
-                               break;
-
-                       case LoginForm::THROTTLED:
-                               $result['result'] = 'Throttled';
-                               $result['wait'] = intval( $loginForm->mThrottleWait );
-                               break;
-
-                       case LoginForm::USER_BLOCKED:
-                               $result['result'] = 'Blocked';
-                               $block = User::newFromName( $params['name'] )->getBlock();
-                               if ( $block ) {
-                                       $result = array_merge( $result, ApiQueryUserInfo::getBlockInfo( $block ) );
-                               }
-                               break;
-
-                       case LoginForm::ABORTED:
-                               $result['result'] = 'Aborted';
-                               $result['reason'] = $loginForm->mAbortLoginErrorMsg;
-                               break;
-
                        default:
                                ApiBase::dieDebug( __METHOD__, "Unhandled case value: {$authRes}" );
                }
@@ -316,8 +235,7 @@ class ApiLogin extends ApiBase {
        }
 
        public function isDeprecated() {
-               return !$this->getConfig()->get( 'DisableAuthManager' ) &&
-                       !$this->getConfig()->get( 'EnableBotPasswords' );
+               return !$this->getConfig()->get( 'EnableBotPasswords' );
        }
 
        public function mustBePosted() {
index 8045447..90438d4 100644 (file)
@@ -1002,7 +1002,7 @@ class ApiPageSet extends ApiBase {
                                // Get pageIDs data from the `page` table
                                $res = $db->select( 'page', $pageFlds, $set, __METHOD__ );
 
-                               // Hack: get the ns:titles stored in array(ns => array(titles)) format
+                               // Hack: get the ns:titles stored in [ns => array(titles)] format
                                $this->initFromQueryResult( $res, $linkBatch->data, true );
                        }
                }
index 5afb66f..cfc1e46 100644 (file)
@@ -261,7 +261,7 @@ class ApiQueryUsers extends ApiQueryBase {
                                        }
                                } else {
                                        $data[$u]['missing'] = true;
-                                       if ( isset( $this->prop['cancreate'] ) && !$this->getConfig()->get( 'DisableAuthManager' ) ) {
+                                       if ( isset( $this->prop['cancreate'] ) ) {
                                                $status = MediaWiki\Auth\AuthManager::singleton()->canCreateAccount( $u );
                                                $data[$u]['cancreate'] = $status->isGood();
                                                if ( !$status->isGood() ) {
@@ -307,7 +307,7 @@ class ApiQueryUsers extends ApiQueryBase {
        }
 
        public function getAllowedParams() {
-               $ret = [
+               return [
                        'prop' => [
                                ApiBase::PARAM_ISMULTI => true,
                                ApiBase::PARAM_TYPE => [
@@ -320,6 +320,7 @@ class ApiQueryUsers extends ApiQueryBase {
                                        'emailable',
                                        'gender',
                                        'centralids',
+                                       'cancreate',
                                        // When adding a prop, consider whether it should be added
                                        // to self::$publicProps
                                ],
@@ -336,10 +337,6 @@ class ApiQueryUsers extends ApiQueryBase {
                                ApiBase::PARAM_ISMULTI => true
                        ],
                ];
-               if ( !$this->getConfig()->get( 'DisableAuthManager' ) ) {
-                       $ret['prop'][ApiBase::PARAM_TYPE][] = 'cancreate';
-               }
-               return $ret;
        }
 
        protected function getExamplesMessages() {
index 3a4b012..00846f5 100644 (file)
@@ -20,7 +20,7 @@
 
 /**
  * This class represents the result of the API operations.
- * It simply wraps a nested array() structure, adding some functions to simplify
+ * It simply wraps a nested array structure, adding some functions to simplify
  * array's modifications. As various modules execute, they add different pieces
  * of information to this result, structuring it as it will be given to the client.
  *
index f09fdcb..3a7a082 100644 (file)
@@ -110,14 +110,16 @@ class ApiWatch extends ApiBase {
                        $status = UnwatchAction::doUnwatch( $title, $user );
                        $res['unwatched'] = $status->isOK();
                        if ( $status->isOK() ) {
-                               $res['message'] = $this->msg( 'removedwatchtext', $title->getPrefixedText() )
+                               $msgKey = $title->isTalkPage() ? 'removedwatchtext-talk' : 'removedwatchtext';
+                               $res['message'] = $this->msg( $msgKey, $title->getPrefixedText() )
                                        ->title( $title )->parseAsBlock();
                        }
                } else {
                        $status = WatchAction::doWatch( $title, $user );
                        $res['watched'] = $status->isOK();
                        if ( $status->isOK() ) {
-                               $res['message'] = $this->msg( 'addedwatchtext', $title->getPrefixedText() )
+                               $msgKey = $title->isTalkPage() ? 'addedwatchtext-talk' : 'addedwatchtext';
+                               $res['message'] = $this->msg( $msgKey, $title->getPrefixedText() )
                                        ->title( $title )->parseAsBlock();
                        }
                }
index 7dcc4fd..2107e89 100644 (file)
        "apihelp-parse-paramvalue-prop-displaytitle": "Вики-текстың синтаксик анализына исем ҡуя.",
        "apihelp-parse-paramvalue-prop-headitems": "<код> & ЛТ -ҡа һалыу өсөн элементтар бирә; башы & GT; биттең </ код>",
        "apihelp-parse-paramvalue-prop-headhtml": "Айырылған <код> & лт бирә; & баштары GТ; биттең </ код>.",
-       "apihelp-parse-paramvalue-prop-jsconfigvars": "Бит өсөн үҙенсәлекле  JavaScript үҙгәреүсән конфигурациялар бирә.",
+       "apihelp-parse-paramvalue-prop-jsconfigvars": "Бит өсөн үҙенсәлекле JavaScript үҙгәреүсән конфигурациялар бирә. Ҡулланыр өсөн, <code>mw.config.set()</code> ҡабыҙырға.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "JavaScriptтың JSON юлы һымаҡ үҙенсәлекле биттәренә  алышына торған конфигурация бирә.",
        "apihelp-parse-paramvalue-prop-iwlinks": "Вики-текстың синтаксик анализында интервиктарға һылтанма бирә.",
        "apihelp-parse-paramvalue-prop-wikitext": "Һығымта яҺау өсөн тәүге вики-тексты күрһәтә",
        "apihelp-protect-param-tags": "Юйҙырылғандар журналындағы яҙмаларға  мөрәжәғәт итер өсөн, билдәләрҙе үҙгәртергә.",
        "apihelp-protect-param-watchlist": "Ағымдағы ҡулланыусының теҙмәһенән битте һүҙһеҙ өҫтәргә йәки юйырға, һылтанмаларҙы файҙаланығыҙ йәки сәғәтте алмаштырмаҫҡа.",
        "apihelp-protect-example-protect": "Битте һаҡларға.",
-       "apihelp-protect-example-unprotect": "<kbd>всех</kbd> өсөн сикләүҙәр ҡуйып,биттән һаҡлауҙы алырға.",
+       "apihelp-protect-example-unprotect": "<kbd>all</kbd> сикләүҙәрен (йәғни һәр береһе эшләй ала) ҡуйып, бит һағын асырға.",
        "apihelp-protect-example-unprotect2": "Бер ниндәй сикләүҙәр ҡуймай биттән һаҡлауҙы алырға.",
        "apihelp-purge-param-forcelinkupdate": "Таблицалар бәйләнешен яңыртыу.",
        "apihelp-purge-param-forcerecursivelinkupdate": "Һылтанманы һәм таблицаны яңыртығыҙ һәм был битте шаблон итеп ҡулланған башҡа биттәр өсөн һылтанмаларҙы ла яңыртығыҙ.",
index 7f30ef8..2f46e71 100644 (file)
 
        "apihelp-login-description": "Log in and get authentication cookies.\n\nThis action should only be used in combination with [[Special:BotPasswords]]; use for main-account login is deprecated and may fail without warning. To safely log in to the main account, use <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
        "apihelp-login-description-nobotpasswords": "Log in and get authentication cookies.\n\nThis action is deprecated and may fail without warning. To safely log in, use <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
-       "apihelp-login-description-nonauthmanager": "Log in and get authentication cookies.\n\nIn the event of a successful log-in, the needed cookies will be included in the HTTP response headers. In the event of a failed log-in, further attempts may be throttled to limit automated password guessing attacks.",
        "apihelp-login-param-name": "User name.",
        "apihelp-login-param-password": "Password.",
        "apihelp-login-param-domain": "Domain (optional).",
index 6c47aa4..cbd9fb8 100644 (file)
        "apihelp-linkaccount-example-link": "{{doc-apihelp-example|linkaccount}}",
        "apihelp-login-description": "{{doc-apihelp-description|login|info=This message is used when <code>$wgEnableBotPasswords</code> is true.|seealso=* {{msg-mw|apihelp-login-description-nobotpasswords}}}}",
        "apihelp-login-description-nobotpasswords": "{{doc-apihelp-description|login|info=This message is used when <code>$wgEnableBotPasswords</code> is false.|seealso=* {{msg-mw|apihelp-login-description}}}}",
-       "apihelp-login-description-nonauthmanager": "{{doc-apihelp-description|login|info=This message is used when <code>$wgDisableAuthManager</code> is true.|seealso=* {{msg-mw|apihelp-login-description}}}}",
        "apihelp-login-param-name": "{{doc-apihelp-param|login|name}}\n{{Identical|Username}}",
        "apihelp-login-param-password": "{{doc-apihelp-param|login|password}}\n{{Identical|Password}}",
        "apihelp-login-param-domain": "{{doc-apihelp-param|login|domain}}",
index 9c32fa3..9e5d754 100644 (file)
@@ -75,6 +75,8 @@
        "apihelp-createaccount-example-pass": "Створити користувача <kbd>testuser</kbd> з паролем <kbd>test123</kbd>.",
        "apihelp-createaccount-example-mail": "Створити користувача <kbd>testmailuser</kbd> і надіслати на електронну пошту випадково-згенерований пароль.",
        "apihelp-cspreport-description": "Використовується браузерами для повідомлення порушень Правил безпеки контенту (Content Security Policy). Цей модуль не повинен використовуватися, окрім випадків автоматичного використання веб-браузером для CSP-скарги.",
+       "apihelp-cspreport-param-reportonly": "Позначити як доповідь із моніторингової політики, не примусової політики",
+       "apihelp-cspreport-param-source": "Що згенерувало CSP-заголовок, який запустив цю доповідь",
        "apihelp-delete-description": "Вилучити сторінку.",
        "apihelp-delete-param-title": "Назва сторінки для вилучення. Не можна використати разом з <var>$1pageid</var>.",
        "apihelp-delete-param-pageid": "ID-сторінки на вилучення. Не можна використати разом з <var>$1title</var>.",
        "apihelp-undelete-example-page": "Відновити сторінку <kbd>Main Page</kbd>.",
        "apihelp-undelete-example-revisions": "Відновити дві версії сторінки <kbd>Main Page</kbd>.",
        "apihelp-unlinkaccount-description": "Вилучити пов'язаний обліковий запис третьої сторони з поточного користувача.",
+       "apihelp-unlinkaccount-example-simple": "Здійснити спробу вилучити посилання поточного користувача для провайдера, асоційованого з <kbd>FooAuthenticationRequest</kbd>.",
        "apihelp-upload-description": "Завантажити файл, або отримати статус завантажень у процесі.\n\nДоступні декілька методів:\n* Завантажити вміст файлу напряму, використовуючи параметр <var>$1file</var>.\n* Завантажити файл шматками, використовуючи параметри <var>$1filesize</var>, <var>$1chunk</var>, та <var>$1offset</var>.\n* Змусити сервер Медіавікі отримати файл за URL, використовуючи параметр <var>$1url</var>.\n* Завершити раніше розпочате завантаження, яке не вдалось через попередження, використовуючи параметр <var>$1filekey</var>.\nЗауважте, що HTTP POST повинен бути здійснений як завантаження файлу (наприклад, використовуючи <code>multipart/form-data</code>)",
        "apihelp-upload-param-filename": "Цільова назва файлу.",
        "apihelp-upload-param-comment": "Коментар завантаження. Також використовується як початковий текст сторінок для нових файлів, якщо <var>$1text</var> не вказано.",
        "api-help-permissions-granted-to": "{{PLURAL:$1|Надано|Надані}}: $2",
        "api-help-right-apihighlimits": "Використовувати вищі ліміти у запитах API (повільні запити: $1; швидкі запити: $2). Ліміти для повільних запитів також застосовуються до багатозначних параметрів.",
        "api-help-open-in-apisandbox": "<small>[відкрити в пісочниці]</small>",
+       "api-help-authmanager-general-usage": "Загальна процедура використання цього модуля така:\n# Отримайте доступні поля зі <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> за допомогою <kbd>amirequestsfor=$4</kbd>, а також токен  <kbd>$5</kbd> зі <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.\n# Передайте ці поля користувачеві, і отримайте інформацію, якою він їх заповнить.\n# Напишіть до цього модуля, заповнивши <var>$1returnurl</var> та всі релевантні поля.\n# Перевірте <samp>status</samp> у відповіді.\n#* Якщо Ви отримали <samp>PASS</samp> або <samp>FAIL</samp>, роботу завершено. Операція або була успішною, або провалилася.\n#* Якщо Ви отримали <samp>UI</samp>, надішліть нові поля користувачеві й отримайте інформацію, якою він їх заповнить. Далі напишіть до цього модуля із <var>$1continue</var> та заповніть всі реелевантні поля, після чого повторіть крок 4.\n#* Якщо Ви отримали <samp>REDIRECT</samp>, направте користувача до <samp>redirecttarget</samp> і дочекайтеся повернення до <var>$1returnurl</var>. Тоді напишіть до цього модуля із <var>$1continue</var>, та з усіма полями, що були передані до повернутої URL-адреси, після чого повторіть крок 4.\n#* Якщо Ви отримали <samp>RESTART</samp>, це означає, що автентифікація спрацювала, але ми не маємо пов'язаного облікового запису користувача. Ви можете розцінити це як <samp>UI</samp>, або як <samp>FAIL</samp>.",
+       "api-help-authmanagerhelper-requests": "Використовувати ці автентифікаційні запити через <samp>id</samp>, що повертається з <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> за допомогою <kbd>amirequestsfor=$1</kbd>, або з попередньої відповіді з цього модуля.",
+       "api-help-authmanagerhelper-request": "Використовувати цей автентифікаційний запит через <samp>id</samp>, що повертається з <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> за допомогою <kbd>amirequestsfor=$1</kbd>.",
        "api-help-authmanagerhelper-messageformat": "Формат до використання для повернення повідомлень.",
        "api-help-authmanagerhelper-mergerequestfields": "Об'єднати інформацію всіх автентифікаційних запитів у один масив.",
        "api-help-authmanagerhelper-preservestate": "Зберегти статус з попередньої спроби входу, що не вдалась, якщо можливо.",
+       "api-help-authmanagerhelper-returnurl": "URL-адреса повернення для сторонніх автентифікаційних потоків повинна бути абсолютною. Обов'язковим є це, або <var>$1continue</var>. \n\nПри отриманні відповіді <samp>REDIRECT</samp>, найбільш звичною Вашою дією буде відкриття браузерного чи іншого веб-перегляду вказаного URL-посилання для стороннього потоку автентифікації. Коли ця операція буде завершена, стороння програма перенаправить веб-переглядач на цю URL-адресу. Ви повинні видобувати будь-які параметри запитів або POST-параметри із цієї URL-адреси, і передавати їх як запит <var>$1continue</var> до цього модуля API.",
+       "api-help-authmanagerhelper-continue": "Цей запит є продовженням після попередньої відповіді <samp>UI</samp> або <samp>REDIRECT</samp>. Або це, або <var>$1returnurl</var> є обов'язковим.",
+       "api-help-authmanagerhelper-additional-params": "Цей модуль приймає додаткові параметри, залежно від доступних автентифікаційних запитів. Використовуйте <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> за допомогою <kbd>amirequestsfor=$1</kbd> (або попередню відповідь від цього модуля, якщо це застосовно), аби визначити доступні запити та поля, які вони використовують.",
        "api-credits-header": "Автор(и)",
        "api-credits": "Розробники API:\n* Roan Kattouw (головний розробник вер. 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (творець, головний розробник вер. 2006 – вер. 2007)\n* Brad Jorsch (головний розробник 2013 – тепер)\n\nБудь ласка, надсилайте свої коментарі, пропозиції та запитання на mediawiki-api@lists.wikimedia.org\nабо зафайліть звіт про баґ на https://phabricator.wikimedia.org/."
 }
index 448233c..5c85832 100644 (file)
@@ -34,7 +34,7 @@
        "apihelp-main-param-requestid": "任何在此提供的值将包含在响应中。可能可以用以区别请求。",
        "apihelp-main-param-servedby": "包含保存结果请求的主机名。",
        "apihelp-main-param-curtimestamp": "在结果中包括当前时间戳。",
-       "apihelp-main-param-origin": "当通过跨域名AJAX请求(CORS)访问API时,设置此作为起始域名。这必须包括在任何pre-flight请求中,并因此必须是请求的URI的一部分(而不是POST正文)。\n\n对于已验证的请求,这必须正确匹配<code>Origin</code>标头中的原点之一,因此它已经设置为像<kbd>https://zh.wikipedia.org</kbd>或<kbd>https://meta.wikimedia.org</kbd>的东西。如果此参数不匹配<code>Origin</code>页顶,就返回403错误响应。如果此参数匹配<code>Origin</code>页顶并且起点在白名单中,将设置<code>Access-Control-Allow-Origin</code>和<code>Access-Control-Allow-Credentials</code>开头。\n\n对于未验证的请求,会指定值<kbd>*</kbd>。这将导致<code>Access-Control-Allow-Origin</code>标头被设置,但<code>Access-Control-Allow-Credentials</code>将为<code>false</code>,且所有用户特定数据将受限制。",
+       "apihelp-main-param-origin": "当通过跨域名AJAX请求(CORS)访问API时,设置此作为起始域名。这必须包括在任何pre-flight请求中,并因此必须是请求的URI的一部分(而不是POST正文)。\n\n对于已验证的请求,这必须正确匹配<code>Origin</code>标头中的原点之一,因此它已经设置为像<kbd>https://zh.wikipedia.org</kbd>或<kbd>https://meta.wikimedia.org</kbd>的东西。如果此参数不匹配<code>Origin</code>页顶,就返回403错误响应。如果此参数匹配<code>Origin</code>页顶并且起点被白名单,将设置<code>Access-Control-Allow-Origin</code>和<code>Access-Control-Allow-Credentials</code>开头。\n\n对于未验证的请求,会指定值<kbd>*</kbd>。这将导致<code>Access-Control-Allow-Origin</code>标头被设置,但<code>Access-Control-Allow-Credentials</code>将为<code>false</code>,且所有用户特定数据将受限制。",
        "apihelp-main-param-uselang": "用于消息翻译的语言。<kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd>与<kbd>siprop=languages</kbd>可返回语言代码列表,或指定<kbd>user</kbd>以使用当前用户的语言设置,或指定<kbd>content</kbd>以使用此wiki的内容语言。",
        "apihelp-block-description": "封禁一位用户。",
        "apihelp-block-param-user": "您要封禁的用户、IP地址或IP地址段。",
@@ -86,6 +86,7 @@
        "apihelp-createaccount-example-mail": "创建用户<kbd>testmailuser</kbd>并电邮发送一个随机生成的密码。",
        "apihelp-cspreport-description": "由浏览器使用以报告违反内容安全方针的内容。此模块应永不使用,除了在被CSP兼容的浏览器自动使用时。",
        "apihelp-cspreport-param-reportonly": "标记作为来自监视方针的报告,而不是执行方针的报告",
+       "apihelp-cspreport-param-source": "生成引发此报告的CSP标头的事物",
        "apihelp-delete-description": "删除一个页面。",
        "apihelp-delete-param-title": "要删除的页面标题。不能与<var>$1pageid</var>一起使用。",
        "apihelp-delete-param-pageid": "要删除的页面的页面 ID。不能与<var>$1title</var>一起使用。",
index 82eeff0..eab5068 100644 (file)
@@ -105,12 +105,6 @@ class AuthManager implements LoggerAwareInterface {
         * @return AuthManager
         */
        public static function singleton() {
-               global $wgDisableAuthManager;
-
-               if ( $wgDisableAuthManager ) {
-                       throw new \BadMethodCallException( '$wgDisableAuthManager is set' );
-               }
-
                if ( self::$instance === null ) {
                        self::$instance = new self(
                                \RequestContext::getMain()->getRequest(),
index f5d3c33..530fc76 100644 (file)
@@ -150,7 +150,7 @@ class IcuCollation extends Collation {
                'la' => [],
                'lb' => [],
                'lt' => [ "Č", "Š", "Ž" ],
-               'mk' => [],
+               'mk' => [ "Ѓ", "Ќ" ],
                'mo' => [ "Ă", "Â", "Î", "Ş", "Ţ" ],
                'mt' => [ "Ċ", "Ġ", "Għ", "Ħ", "Ż" ],
                'nl' => [],
index 3690735..c24962b 100644 (file)
  *   - READ_EXCLUSIVE : Up-to-date read as of now, that locks (exclusive) the records
  * All record locks persist for the duration of the transaction.
  *
+ * A special constant READ_LATEST_IMMUTABLE can be used for fetching append-only data. Such
+ * data is either (a) on a slave and up-to-date or (b) not yet there, but on the master/quorum.
+ * Because the data is append-only, it can never be stale on a slave if present.
+ *
  * Callers should use READ_NORMAL (or pass in no flags) unless the read determines a write.
  * In theory, such cases may require READ_LOCKING, though to avoid contention, READ_LATEST is
  * often good enough. If UPDATE race condition checks are required on a row and expensive code
  * must run after the row is fetched to determine the UPDATE, it may help to do something like:
- *   - a) Read the current row
- *   - b) Determine the new row (expensive, so we don't want to hold locks now)
- *   - c) Re-read the current row with READ_LOCKING; if it changed then bail out
- *   - d) otherwise, do the updates
+ *   - a) Start transaction
+ *   - b) Read the current row with READ_LATEST
+ *   - c) Determine the new row (expensive, so we don't want to hold locks now)
+ *   - d) Re-read the current row with READ_LOCKING; if it changed then bail out
+ *   - e) otherwise, do the updates
+ *   - f) Commit transaction
  *
  * @since 1.20
  */
 interface IDBAccessObject {
-       // Constants for object loading bitfield flags (higher => higher QoS)
-       const READ_LATEST = 1; // read from the master
+       /** Constants for object loading bitfield flags (higher => higher QoS) */
+       /** @var integer Read from a slave/non-quorum */
+       const READ_NORMAL = 0;
+       /** @var integer Read from the master/quorum */
+       const READ_LATEST = 1;
+       /* @var integer Read from the master/quorum and lock out other writers */
        const READ_LOCKING = 3; // READ_LATEST (1) and "LOCK IN SHARE MODE" (2)
+       /** @var integer Read from the master/quorum and lock out other writers and locking readers */
        const READ_EXCLUSIVE = 7; // READ_LOCKING (3) and "FOR UPDATE" (4)
 
-       // Convenience constant for callers to explicitly request slave data
-       const READ_NORMAL = 0; // read from the slave
+       /** @var integer Read from a slave/non-quorum immutable data, using the master/quorum on miss */
+       const READ_LATEST_IMMUTABLE = 8;
 
        // Convenience constant for tracking how data was loaded (higher => higher QoS)
        const READ_NONE = -1; // not loaded yet (or the object was cleared)
index 3dc6e92..ba25183 100644 (file)
@@ -2642,13 +2642,13 @@ abstract class DatabaseBase implements IDatabase {
                                        "$fname: Transaction already in progress (from {$this->mTrxFname}), " .
                                                " performing implicit commit!"
                                );
-                       } else {
+                       } elseif ( $this->mTrxDoneWrites ) {
                                // The transaction was automatic and has done write operations
-                               if ( $this->mTrxDoneWrites ) {
-                                       wfLogDBError( "$fname: Automatic transaction with writes in progress" .
+                               throw new DBUnexpectedError(
+                                       $this,
+                                       "$fname: Automatic transaction with writes in progress" .
                                                " (from {$this->mTrxFname}), performing implicit commit!\n"
-                                       );
-                               }
+                               );
                        }
 
                        $this->runOnTransactionPreCommitCallbacks();
index 33f8162..5e0365a 100644 (file)
@@ -378,10 +378,10 @@ class DatabaseMssql extends Database {
         * @param mixed $conds Array or string, condition(s) for WHERE
         * @param string $fname Calling function name (use __METHOD__) for logs/profiling
         * @param array $options Associative array of options (e.g.
-        *   array('GROUP BY' => 'page_title')), see Database::makeSelectOptions
+        *   [ 'GROUP BY' => 'page_title' ]), see Database::makeSelectOptions
         *   code for list of supported stuff
         * @param array $join_conds Associative array of table join conditions
-        *   (optional) (e.g. array( 'page' => array('LEFT JOIN','page_latest=rev_id') )
+        *   (optional) (e.g. [ 'page' => [ 'LEFT JOIN','page_latest=rev_id' ] ]
         * @return mixed Database result resource (feed to Database::fetchObject
         *   or whatever), or false on failure
         * @throws DBQueryError
@@ -434,10 +434,10 @@ class DatabaseMssql extends Database {
         * @param mixed $vars Array or string, field name(s) to be retrieved
         * @param mixed $conds Array or string, condition(s) for WHERE
         * @param string $fname Calling function name (use __METHOD__) for logs/profiling
-        * @param array $options Associative array of options (e.g. array('GROUP BY' => 'page_title')),
+        * @param array $options Associative array of options (e.g. [ 'GROUP BY' => 'page_title' ]),
         *   see Database::makeSelectOptions code for list of supported stuff
         * @param array $join_conds Associative array of table join conditions (optional)
-        *    (e.g. array( 'page' => array('LEFT JOIN','page_latest=rev_id') )
+        *    (e.g. [ 'page' => [ 'LEFT JOIN','page_latest=rev_id' ] ]
         * @return string The SQL text
         */
        public function selectSQLText( $table, $vars, $conds = '', $fname = __METHOD__,
@@ -717,7 +717,7 @@ class DatabaseMssql extends Database {
 
        /**
         * INSERT SELECT wrapper
-        * $varMap must be an associative array of the form array( 'dest1' => 'source1', ...)
+        * $varMap must be an associative array of the form [ 'dest1' => 'source1', ... ]
         * Source items may be literals rather than field names, but strings should
         * be quoted with Database::addQuotes().
         * @param string $destTable
index a6f8c31..798815d 100644 (file)
@@ -798,7 +798,7 @@ abstract class DatabaseMysqlBase extends Database {
                // Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
                if ( $this->useGTIDs && $pos->gtids ) {
                        // Wait on the GTID set (MariaDB only)
-                       $gtidArg = implode( ',', $pos->gtids );
+                       $gtidArg = $this->addQuotes( implode( ',', $pos->gtids ) );
                        $res = $this->doQuery( "SELECT MASTER_GTID_WAIT($gtidArg, $timeout)" );
                } else {
                        // Wait on the binlog coordinates
@@ -1186,12 +1186,6 @@ abstract class DatabaseMysqlBase extends Database {
                return $this->lastErrno() == 1205;
        }
 
-       /**
-        * Determines if the last query error was something that should be dealt
-        * with by pinging the connection and reissuing the query
-        *
-        * @return bool
-        */
        function wasErrorReissuable() {
                return $this->lastErrno() == 2013 || $this->lastErrno() == 2006;
        }
index c9127ff..867aeb8 100644 (file)
@@ -888,7 +888,7 @@ __INDEXATTR__;
 
        /**
         * INSERT SELECT wrapper
-        * $varMap must be an associative array of the form array( 'dest1' => 'source1', ...)
+        * $varMap must be an associative array of the form [ 'dest1' => 'source1', ... ]
         * Source items may be literals rather then field names, but strings should
         * be quoted with Database::addQuotes()
         * $conds may be "*" to copy the whole table
index 41b131f..43592e2 100644 (file)
@@ -329,7 +329,7 @@ interface IDatabase {
         *
         * Example:
         * $id = $dbw->nextSequenceValue( 'page_page_id_seq' );
-        * $dbw->insert( 'page', array( 'page_id' => $id ) );
+        * $dbw->insert( 'page', [ 'page_id' => $id ] );
         * $id = $dbw->insertId();
         *
         * @return int
@@ -519,7 +519,7 @@ interface IDatabase {
         * May be either an array of table names, or a single string holding a table
         * name. If an array is given, table aliases can be specified, for example:
         *
-        *    array( 'a' => 'user' )
+        *    [ 'a' => 'user' ]
         *
         * This includes the user table in the query, with the alias "a" available
         * for use in field names (e.g. a.user_name).
@@ -537,7 +537,7 @@ interface IDatabase {
         * can be complete fragments of SQL, for direct inclusion into the SELECT
         * query. If an array is given, field aliases can be specified, for example:
         *
-        *   array( 'maxrev' => 'MAX(rev_id)' )
+        *   [ 'maxrev' => 'MAX(rev_id)' ]
         *
         * This includes an expression with the alias "maxrev" in the query.
         *
@@ -582,7 +582,7 @@ interface IDatabase {
         * including them in the array as a string value with a numeric key, for
         * example:
         *
-        *    array( 'FOR UPDATE' )
+        *    [ 'FOR UPDATE' ]
         *
         * The supported options are:
         *
@@ -644,7 +644,7 @@ interface IDatabase {
         * an SQL fragment, or an array where the string keys are equality and the
         * numeric keys are SQL fragments all AND'd together. For example:
         *
-        *    array( 'page' => array( 'LEFT JOIN', 'page_latest=rev_id' ) )
+        *    [ 'page' => [ 'LEFT JOIN', 'page_latest=rev_id' ] ]
         *
         * @return ResultWrapper|bool If the query returned no rows, a ResultWrapper
         *   with no rows in it will be returned. If there was a query error, a
@@ -857,7 +857,7 @@ interface IDatabase {
         * The keys on each level may be either integers or strings.
         *
         * @param array $data Organized as 2-d
-        *    array(baseKeyVal => array(subKeyVal => [ignored], ...), ...)
+        *    [ baseKeyVal => [ subKeyVal => [ignored], ... ], ... ]
         * @param string $baseKey Field name to match the base-level keys to (eg 'pl_namespace')
         * @param string $subKey Field name to match the sub-level keys to (eg 'pl_title')
         * @return string|bool SQL fragment, or false if no items in array
@@ -950,7 +950,7 @@ interface IDatabase {
         * Example: $dbr->buildLike( 'My_page_title/', $dbr->anyString() ) returns
         * a LIKE clause that searches for subpages of 'My page title'.
         * Alternatively:
-        *   $pattern = array( 'My_page_title/', $dbr->anyString() );
+        *   $pattern = [ 'My_page_title/', $dbr->anyString() ];
         *   $query .= $dbr->buildLike( $pattern );
         *
         * @since 1.16
@@ -1092,7 +1092,7 @@ interface IDatabase {
         *    to include in a join.
         *
         * @param array $varMap Must be an associative array of the form
-        *    array( 'dest1' => 'source1', ...). Source items may be literals
+        *    [ 'dest1' => 'source1', ... ]. Source items may be literals
         *    rather than field names, but strings should be quoted with
         *    IDatabase::addQuotes()
         *
@@ -1156,7 +1156,6 @@ interface IDatabase {
 
        /**
         * Determines how long the server has been up
-        * STUB
         *
         * @return int
         */
@@ -1164,7 +1163,6 @@ interface IDatabase {
 
        /**
         * Determines if the last failure was due to a deadlock
-        * STUB
         *
         * @return bool
         */
@@ -1172,16 +1170,14 @@ interface IDatabase {
 
        /**
         * Determines if the last failure was due to a lock timeout
-        * STUB
         *
         * @return bool
         */
        public function wasLockTimeout();
 
        /**
-        * Determines if the last query error was something that should be dealt
-        * with by pinging the connection and reissuing the query.
-        * STUB
+        * Determines if the last query error was due to a dropped connection and should
+        * be dealt with by pinging the connection and reissuing the query.
         *
         * @return bool
         */
@@ -1189,7 +1185,6 @@ interface IDatabase {
 
        /**
         * Determines if the last failure was due to the database being read-only.
-        * STUB
         *
         * @return bool
         */
index 3a543ac..32b1a0f 100644 (file)
  *
  *     sectionLoads                A 2-d map. For each section, gives a map of server names to
  *                                 load ratios. For example:
- *                                 array(
- *                                     'section1' => array(
+ *                                 [
+ *                                     'section1' => [
  *                                         'db1' => 100,
  *                                         'db2' => 100
- *                                     )
- *                                 )
+ *                                     ]
+ *                                 ]
  *
  *     serverTemplate              A server info associative array as documented for $wgDBservers.
  *                                 The host, hostName and load entries will be overridden.
  *
  *     groupLoadsBySection         A 3-d map giving server load ratios for each section and group.
  *                                 For example:
- *                                 array(
- *                                     'section1' => array(
- *                                         'group1' => array(
+ *                                 [
+ *                                     'section1' => [
+ *                                         'group1' => [
  *                                             'db1' => 100,
  *                                             'db2' => 100
- *                                         )
- *                                     )
- *                                 )
+ *                                         ]
+ *                                     ]
+ *                                 ]
  *
  *     groupLoadsByDB              A 3-d map giving server load ratios by DB name.
  *
index b44b559..1269c3e 100644 (file)
@@ -617,7 +617,7 @@ class LoadBalancer {
                        /**
                         * This can happen in code like:
                         *   foreach ( $dbs as $db ) {
-                        *     $conn = $lb->getConnection( DB_SLAVE, array(), $db );
+                        *     $conn = $lb->getConnection( DB_SLAVE, [], $db );
                         *     ...
                         *     $lb->reuseConnection( $conn );
                         *   }
index 33955b2..4a6ac8e 100644 (file)
@@ -238,12 +238,14 @@ class DifferenceEngine extends ContextSource {
        }
 
        public function showDiffPage( $diffOnly = false ) {
-
                # Allow frames except in certain special cases
                $out = $this->getOutput();
                $out->allowClickjacking();
                $out->setRobotPolicy( 'noindex,nofollow' );
 
+               // Allow extensions to add any extra output here
+               Hooks::run( 'DifferenceEngineShowDiffPage', [ $out ] );
+
                if ( !$this->loadRevisionData() ) {
                        $this->showMissingRevision();
 
@@ -285,6 +287,8 @@ class DifferenceEngine extends ContextSource {
                        $out->setPageTitle( $this->msg( 'difference-title', $this->mNewPage->getPrefixedText() ) );
                        $samePage = true;
                        $oldHeader = '';
+                       // Allow extensions to change the $oldHeader variable
+                       Hooks::run( 'DifferenceEngineOldHeaderNoOldRev', [ &$oldHeader ] );
                } else {
                        Hooks::run( 'DiffViewHeader', [ $this, $this->mOldRev, $this->mNewRev ] );
 
@@ -354,6 +358,10 @@ class DifferenceEngine extends ContextSource {
                                '<div id="mw-diff-otitle5">' . $oldChangeTags[0] . '</div>' .
                                '<div id="mw-diff-otitle4">' . $prevlink . '</div>';
 
+                       // Allow extensions to change the $oldHeader variable
+                       Hooks::run( 'DifferenceEngineOldHeader', [ $this, &$oldHeader, $prevlink, $oldminor,
+                               $diffOnly, $ldel, $this->unhide ] );
+
                        if ( $this->mOldRev->isDeleted( Revision::DELETED_TEXT ) ) {
                                $deleted = true; // old revisions text is hidden
                                if ( $this->mOldRev->isDeleted( Revision::DELETED_RESTRICTED ) ) {
@@ -415,6 +423,10 @@ class DifferenceEngine extends ContextSource {
                        '<div id="mw-diff-ntitle5">' . $newChangeTags[0] . '</div>' .
                        '<div id="mw-diff-ntitle4">' . $nextlink . $this->markPatrolledLink() . '</div>';
 
+               // Allow extensions to change the $newHeader variable
+               Hooks::run( 'DifferenceEngineNewHeader', [ $this, &$newHeader, $formattedRevisionTools,
+                       $nextlink, $rollback, $newminor, $diffOnly, $rdel, $this->unhide ] );
+
                if ( $this->mNewRev->isDeleted( Revision::DELETED_TEXT ) ) {
                        $deleted = true; // new revisions text is hidden
                        if ( $this->mNewRev->isDeleted( Revision::DELETED_RESTRICTED ) ) {
@@ -487,6 +499,9 @@ class DifferenceEngine extends ContextSource {
                                                        'token' => $linkInfo['token'],
                                                ]
                                        ) . ']</span>';
+                               // Allow extensions to change the markpatrolled link
+                               Hooks::run( 'DifferenceEngineMarkPatrolledLink', [ $this,
+                                       &$this->mMarkPatrolledLink, $linkInfo['rcid'], $linkInfo['token'] ] );
                        }
                }
                return $this->mMarkPatrolledLink;
@@ -530,9 +545,17 @@ class DifferenceEngine extends ContextSource {
                                // If the user could patrol this it already would be patrolled
                                $rcid = 0;
                        }
+
+                       // Allow extensions to possibly change the rcid here
+                       // For example the rcid might be set to zero due to the user
+                       // being the same as the performer of the change but an extension
+                       // might still want to show it under certain conditions
+                       Hooks::run( 'DifferenceEngineMarkPatrolledRCID', [ &$rcid, $this, $change, $user ] );
+
                        // Build the link
                        if ( $rcid ) {
                                $this->getOutput()->preventClickjacking();
+                               $this->getOutput()->addModuleStyles( 'mediawiki.page.patrol' );
                                if ( $wgEnableAPI && $wgEnableWriteAPI
                                        && $user->isAllowed( 'writeapi' )
                                ) {
@@ -617,15 +640,20 @@ class DifferenceEngine extends ContextSource {
 
                                # WikiPage::getParserOutput() should not return false, but just in case
                                if ( $parserOutput ) {
-                                       $out->addParserOutput( $parserOutput );
+                                       // Allow extensions to change parser output here
+                                       if ( Hooks::run( 'DifferenceEngineRenderRevisionAddParserOutput', [ $this, $out, $parserOutput, $wikiPage ] ) ) {
+                                               $out->addParserOutput( $parserOutput );
+                                       }
                                }
                        }
                }
                # @codingStandardsIgnoreEnd
 
-               # Add redundant patrol link on bottom...
-               $out->addHTML( $this->markPatrolledLink() );
-
+               // Allow extensions to optionally not show the final patrolled link
+               if ( Hooks::run( 'DifferenceEngineRenderRevisionShowFinalPatrolLink' ) ) {
+                       # Add redundant patrol link on bottom...
+                       $out->addHTML( $this->markPatrolledLink() );
+               }
        }
 
        protected function getParserOutput( WikiPage $page, Revision $rev ) {
@@ -651,6 +679,9 @@ class DifferenceEngine extends ContextSource {
         * @return bool
         */
        public function showDiff( $otitle, $ntitle, $notice = '' ) {
+               // Allow extensions to affect the output here
+               Hooks::run( 'DifferenceEngineShowDiff', [ $this ] );
+
                $diff = $this->getDiff( $otitle, $ntitle, $notice );
                if ( $diff === false ) {
                        $this->showMissingRevision();
@@ -720,7 +751,9 @@ class DifferenceEngine extends ContextSource {
                if ( $this->mOldRev === false || ( $this->mOldRev && $this->mNewRev
                        && $this->mOldRev->getId() == $this->mNewRev->getId() )
                ) {
-                       return '';
+                       if ( Hooks::run( 'DifferenceEngineShowEmptyOldContent', [ $this ] ) ) {
+                               return '';
+                       }
                }
                // Cacheable?
                $key = false;
index e5ded45..b61b08d 100644 (file)
@@ -150,8 +150,7 @@ abstract class DBLockManager extends QuorumLockManager {
                if ( !isset( $this->conns[$lockDb] ) ) {
                        $db = null;
                        if ( $lockDb === 'localDBMaster' ) {
-                               $lb = wfGetLBFactory()->getMainLB( $this->domain );
-                               $db = $lb->getConnection( DB_MASTER, [], $this->domain );
+                               $db = $this->getLocalLB()->getConnection( DB_MASTER, [], $this->domain );
                        } elseif ( isset( $this->dbServers[$lockDb] ) ) {
                                $config = $this->dbServers[$lockDb];
                                $db = DatabaseBase::factory( $config['type'], $config );
@@ -178,6 +177,13 @@ abstract class DBLockManager extends QuorumLockManager {
                return $this->conns[$lockDb];
        }
 
+       /**
+        * @return LoadBalancer
+        */
+       protected function getLocalLB() {
+               return wfGetLBFactory()->getMainLB( $this->domain );
+       }
+
        /**
         * Do additional initialization for new lock DB connection
         *
@@ -249,10 +255,11 @@ class MySqlLockManager extends DBLockManager {
                self::LOCK_EX => self::LOCK_EX
        ];
 
-       /**
-        * @param string $lockDb
-        * @param IDatabase $db
-        */
+       protected function getLocalLB() {
+               // Use a separate connection so releaseAllLocks() doesn't rollback the main trx
+               return wfGetLBFactory()->newMainLB( $this->domain );
+       }
+
        protected function initConnection( $lockDb, IDatabase $db ) {
                # Let this transaction see lock rows from other transactions
                $db->query( "SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;" );
index f8d26a7..b29e3bd 100644 (file)
        "config-env-php": "PHP $1 i biyo saz.",
        "config-db-type": "Database tipe:",
        "config-db-host": "Database host:",
+       "config-db-host-oracle": "Database TNS:",
        "config-db-name": "Database name:",
+       "config-db-username": "Database nameykarberi:",
+       "config-db-password": "Database parola :",
        "config-db-port": "Portê database:",
        "config-type-mssql": "Microsoft SQL Server",
        "config-header-mysql": "Eyarê MySQL",
diff --git a/includes/installer/i18n/dty.json b/includes/installer/i18n/dty.json
new file mode 100644 (file)
index 0000000..a986e00
--- /dev/null
@@ -0,0 +1,52 @@
+{
+       "@metadata": {
+               "authors": [
+                       "राम प्रसाद जोशी"
+               ]
+       },
+       "config-desc": "मेडियाविकिको लागि स्थापक",
+       "config-title": "मेडिया विकि $1 स्थापना",
+       "config-information": "जानकारी",
+       "config-localsettings-upgrade": "<code>LocalSettings.php</code> फाइल पाइयो ।\nयै स्थापनालाई अपग्रेड गर्न, तलीखाइ दिया  बक्समी <code>$wgUpgradeKey</code>  को मान दर्ज गर ।\nतम <code>LocalSettings.php</code> मा भेट्टे हौ ।",
+       "config-localsettings-cli-upgrade": "<code>LocalSettings.php</code> फाइल पाइयो ।\nयै स्थापनालाई अपग्रेड गद्द, बदलामी कृपया यैलाई चलाओ <code>update.php</code>",
+       "config-localsettings-key": "नवीनीकरण साँचो",
+       "config-localsettings-badkey": "तमले प्रोभाइट गर्याको नवनिकरण साँचो मान्य छैन",
+       "config-upgrade-key-missing": "An existing installation of MediaWiki has been detected.\nTo upgrade this installation, please put the following line at the bottom of your <code>LocalSettings.php</code>:\n\n$1",
+       "config-localsettings-incomplete": "The existing <code>LocalSettings.php</code> appears to be incomplete.\nThe $1 variable is not set.\nPlease change <code>LocalSettings.php</code> so that this variable is set, and click \"{{int:Config-continue}}\".",
+       "config-localsettings-connection-error": "An error was encountered when connecting to the database using the settings specified in <code>LocalSettings.php</code>. Please fix these settings and try again.\n\n$1",
+       "config-session-error": "Error starting session: $1",
+       "config-session-expired": "Your session data seems to have expired.\nSessions are configured for a lifetime of $1.\nYou can increase this by setting <code>session.gc_maxlifetime</code> in php.ini.\nRestart the installation process.",
+       "config-no-session": "तमरो सेसन डाटा मेटिया छ!\nतमरो php चेक गर। ini र make sure <code>session.save_path</code> is set to an appropriate directory.",
+       "config-your-language": "तमरो भाषा:",
+       "config-your-language-help": "इन्स्टाल गर्दा उपयोग गद्दे भाषा छान ।",
+       "config-wiki-language": "विकि भाषाहरू",
+       "config-wiki-language-help": "Select the language that the wiki will predominantly be written in.",
+       "config-back": "← पछाडी",
+       "config-continue": "जारी राख्या",
+       "config-page-language": "भाषा",
+       "config-page-welcome": "मिडीयाविकिमी तमलाई स्वागत छ!",
+       "config-page-dbconnect": "डेटाबेससँग सम्बन्ध बनाउन्या",
+       "config-page-upgrade": "मौजूदा स्थापनाको नवीनीकरण",
+       "config-page-dbsettings": "डेटावेस सेटिङ",
+       "config-page-name": "नाऊ",
+       "config-page-options": "विकल्पहरू",
+       "config-page-install": "स्थापना गद्दे",
+       "config-page-complete": "पूरा भयो !",
+       "config-page-restart": "स्थापना फेरि सुरु गद्दे",
+       "config-page-readme": "थप पड्डे",
+       "config-page-releasenotes": "प्रकाशन टिप्पणी",
+       "config-page-copying": "कपि हून लाग्याको छ",
+       "config-page-upgradedoc": "अद्यावधिक गरिदै",
+       "config-page-existingwiki": "विकि बन्द हुँदै",
+       "config-help-restart": "Do you want to clear all saved data that you have entered and restart the installation process?",
+       "config-restart": "हुन्छ, पुनः सुचारू गद्दे",
+       "config-welcome": "=== Environmental checks ===\nBasic checks will now be performed to see if this environment is suitable for MediaWiki installation.\nRemember to include this information if you seek support on how to complete the installation.",
+       "config-copyright": "=== Copyright and Terms ===\n\n$1\n\nThis 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.\n\nThis program is distributed in the hope that it will be useful, but <strong>without any warranty</strong>; without even the implied warranty of <strong>merchantability</strong> or <strong>fitness for a particular purpose</strong>.\nSee the GNU General Public License for more details.\n\nYou should have received <doclink href=Copying>a copy of the GNU General Public License</doclink> along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA, or [http://www.gnu.org/copyleft/gpl.html read it online].",
+       "config-sidebar": "* [https://www.mediawiki.org MediaWiki home]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents User's Guide]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Administrator's Guide]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ]\n----\n* <doclink href=Readme>Read me</doclink>\n* <doclink href=ReleaseNotes>Release notes</doclink>\n* <doclink href=Copying>Copying</doclink>\n* <doclink href=UpgradeDoc>Upgrading</doclink>",
+       "config-env-good": "The environment has been checked.\nYou can install MediaWiki.",
+       "config-env-bad": "The environment has been checked.\nYou cannot install MediaWiki.",
+       "config-env-php": "PHP $1 is installed.",
+       "config-env-hhvm": "HHVM $1 स्थापना गरिएको छ ।",
+       "config-unicode-using-intl": "Using the [http://pecl.php.net/intl intl PECL extension] for Unicode normalization.",
+       "config-unicode-pure-php-warning": "<strong>Warning:</strong> The [http://pecl.php.net/intl intl PECL extension] is not available to handle Unicode normalization, falling back to slow pure-PHP implementation.\nIf you run a high-traffic site, you should read a little on [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalization]."
+}
index 1158193..f812471 100644 (file)
@@ -63,6 +63,7 @@
        "config-header-oracle": "Oracle hobespenak",
        "config-header-mssql": "Microsoft SQL Server-en ezarpenak",
        "config-invalid-db-type": "Datu-base mota baliogabea.",
+       "config-db-sys-user-exists-oracle": "$1 erabiltzaile kontua dagoeneko existitzen da. SYSDBA kontu berri bat sortzeko erabili daiteke soilik!",
        "config-mysql-innodb": "InnoDB",
        "config-mysql-myisam": "MyISAM",
        "config-mysql-binary": "Bitarra",
index 423926b..8d54c98 100644 (file)
        "config-subscribe": "Zapisz się na [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce listę pocztową z ogłoszeniami o nowych wersjach].",
        "config-subscribe-help": "Jest to lista o małej liczbie wiadomości, wykorzystywana do przesyłania informacji o udostępnieniu nowej wersji oraz istotnych sprawach dotyczących bezpieczeństwa.\nPowinieneś zapisać się na tę listę i aktualizować zainstalowane oprogramowanie MediaWiki gdy pojawia się nowa wersja.",
        "config-subscribe-noemail": "Próbowano subskrybować listę mailingową ogłoszeń wersji bez podania adresu e-mail.\nProszę podać adres e-mail, jeśli chcesz subskrybować listę wysyłkową.",
+       "config-pingback": "Udostępnij dane o instalacji twórcom MediaWiki.",
+       "config-pingback-help": "Jeżeli wybierzesz tę opcję, MediaWiki będzie okresowo wysyłać na https://www.mediawiki.org podstawowe dane na temat tej instancji MediaWiki. Te dane zawierają np. typ systemu, wersję PHP i wybrany silnik bazy danych. Fundacja Wikimedia dzieli się tymi danymi z twórcami MediaWiki, aby pomóc w podejmowaniu dalszych wysiłków co do rozwoju. Poniższe dane o Twoim systemie zostaną wysłane:\n<pre>$1</pre>",
        "config-almost-done": "To już prawie koniec!\nMożesz pominąć pozostałe czynności konfiguracyjne i zainstalować wiki.",
        "config-optional-continue": "Zadaj mi więcej pytań.",
        "config-optional-skip": "Jestem już znudzony, po prostu zainstaluj wiki.",
index 1350958..98d7d12 100644 (file)
@@ -307,7 +307,7 @@ class JobRunner implements LoggerAwareInterface {
                $stats->timing( "jobqueue.run.$jType", $timeMs );
                // Track RSS increases for jobs (in case of memory leaks)
                if ( $rssStart && $rssEnd ) {
-                       $stats->increment( "jobqueue.rss_delta.$jType", $rssEnd - $rssStart );
+                       $stats->updateCount( "jobqueue.rss_delta.$jType", $rssEnd - $rssStart );
                }
 
                if ( $status === false ) {
index 511e1c9..4ba1bc3 100644 (file)
@@ -50,7 +50,7 @@ class HtmlArmor {
                if ( $input instanceof HtmlArmor ) {
                        return $input->value;
                } else {
-                       return htmlspecialchars( $input );
+                       return htmlspecialchars( $input, ENT_QUOTES );
                }
        }
 }
index 6396aaa..f5a860e 100644 (file)
@@ -1196,6 +1196,7 @@ class Article implements Page {
                $token = $user->getEditToken( $rcid );
 
                $outputPage->preventClickjacking();
+               $outputPage->addModuleStyles( 'mediawiki.page.patrol' );
                if ( $wgEnableAPI && $wgEnableWriteAPI && $user->isAllowed( 'writeapi' ) ) {
                        $outputPage->addModules( 'mediawiki.page.patrol.ajax' );
                }
index 39fb8ef..52df2e3 100644 (file)
  * Item class for a filearchive table row
  */
 class RevDelArchivedFileItem extends RevDelFileItem {
-       /** @var RevDelArchivedFileList */
-       protected $list;
-       /** @var ArchivedFile */
-       protected $file;
+       /** @var $list RevDelArchivedFileList */
+       /** @var $file ArchivedFile */
        /** @var LocalFile */
        protected $lockFile;
 
index 3a3b467..ff01cee 100644 (file)
  * Item class for an oldimage table row
  */
 class RevDelFileItem extends RevDelItem {
-       /** @var OldLocalFile */
-       public $file;
        /** @var RevDelFileList */
        protected $list;
+       /** @var OldLocalFile */
+       protected $file;
 
        public function __construct( $list, $row ) {
                parent::__construct( $list, $row );
index 3e5ef3b..8ccb6d1 100644 (file)
@@ -374,202 +374,15 @@ final class SessionManager implements SessionManagerInterface {
         * @deprecated since 1.27, use MediaWiki\Auth\AuthManager::autoCreateUser instead
         * @param User $user User to auto-create
         * @return bool Success
+        * @codeCoverageIgnore
         */
        public static function autoCreateUser( User $user ) {
-               global $wgAuth, $wgDisableAuthManager;
-
-               // @codeCoverageIgnoreStart
-               if ( !$wgDisableAuthManager ) {
-                       wfDeprecated( __METHOD__, '1.27' );
-                       return \MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
-                               $user,
-                               \MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
-                               false
-                       )->isGood();
-               }
-               // @codeCoverageIgnoreEnd
-
-               $logger = self::singleton()->logger;
-
-               // Much of this code is based on that in CentralAuth
-
-               // Try the local user from the slave DB
-               $localId = User::idFromName( $user->getName() );
-               $flags = 0;
-
-               // Fetch the user ID from the master, so that we don't try to create the user
-               // when they already exist, due to replication lag
-               // @codeCoverageIgnoreStart
-               if ( !$localId && wfGetLB()->getReaderIndex() != 0 ) {
-                       $localId = User::idFromName( $user->getName(), User::READ_LATEST );
-                       $flags = User::READ_LATEST;
-               }
-               // @codeCoverageIgnoreEnd
-
-               if ( $localId ) {
-                       // User exists after all.
-                       $user->setId( $localId );
-                       $user->loadFromId( $flags );
-                       return false;
-               }
-
-               // Denied by AuthPlugin? But ignore AuthPlugin itself.
-               if ( get_class( $wgAuth ) !== 'AuthPlugin' && !$wgAuth->autoCreate() ) {
-                       $logger->debug( __METHOD__ . ': denied by AuthPlugin' );
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               // Wiki is read-only?
-               if ( wfReadOnly() ) {
-                       $logger->debug( __METHOD__ . ': denied by wfReadOnly()' );
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               $userName = $user->getName();
-
-               // Check the session, if we tried to create this user already there's
-               // no point in retrying.
-               $session = self::getGlobalSession();
-               $reason = $session->get( 'MWSession::AutoCreateBlacklist' );
-               if ( $reason ) {
-                       $logger->debug( __METHOD__ . ": blacklisted in session ($reason)" );
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               // Is the IP user able to create accounts?
-               $anon = new User;
-               if ( !$anon->isAllowedAny( 'createaccount', 'autocreateaccount' )
-                       || $anon->isBlockedFromCreateAccount()
-               ) {
-                       // Blacklist the user to avoid repeated DB queries subsequently
-                       $logger->debug( __METHOD__ . ': user is blocked from this wiki, blacklisting' );
-                       $session->set( 'MWSession::AutoCreateBlacklist', 'blocked', 600 );
-                       $session->persist();
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               // Check for validity of username
-               if ( !User::isCreatableName( $userName ) ) {
-                       $logger->debug( __METHOD__ . ': Invalid username, blacklisting' );
-                       $session->set( 'MWSession::AutoCreateBlacklist', 'invalid username', 600 );
-                       $session->persist();
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               // Give other extensions a chance to stop auto creation.
-               $user->loadDefaults( $userName );
-               $abortMessage = '';
-               if ( !\Hooks::run( 'AbortAutoAccount', [ $user, &$abortMessage ] ) ) {
-                       // In this case we have no way to return the message to the user,
-                       // but we can log it.
-                       $logger->debug( __METHOD__ . ": denied by hook: $abortMessage" );
-                       $session->set( 'MWSession::AutoCreateBlacklist', "hook aborted: $abortMessage", 600 );
-                       $session->persist();
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               // Make sure the name has not been changed
-               if ( $user->getName() !== $userName ) {
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       throw new \UnexpectedValueException(
-                               'AbortAutoAccount hook tried to change the user name'
-                       );
-               }
-
-               // Ignore warnings about master connections/writes...hard to avoid here
-               \Profiler::instance()->getTransactionProfiler()->resetExpectations();
-
-               $cache = \ObjectCache::getLocalClusterInstance();
-               $backoffKey = wfMemcKey( 'MWSession', 'autocreate-failed', md5( $userName ) );
-               if ( $cache->get( $backoffKey ) ) {
-                       $logger->debug( __METHOD__ . ': denied by prior creation attempt failures' );
-                       $user->setId( 0 );
-                       $user->loadFromId();
-                       return false;
-               }
-
-               // Checks passed, create the user...
-               $from = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : 'CLI';
-               $logger->info( __METHOD__ . ': creating new user ({username}) - from: {url}',
-                       [
-                               'username' => $userName,
-                               'url' => $from,
-               ] );
-
-               try {
-                       // Insert the user into the local DB master
-                       $status = $user->addToDatabase();
-                       if ( !$status->isOK() ) {
-                               // @codeCoverageIgnoreStart
-                               // double-check for a race condition (T70012)
-                               $id = User::idFromName( $user->getName(), User::READ_LATEST );
-                               if ( $id ) {
-                                       $logger->info( __METHOD__ . ': tried to autocreate existing user',
-                                               [
-                                                       'username' => $userName,
-                                               ] );
-                               } else {
-                                       $logger->error(
-                                               __METHOD__ . ': failed with message ' . $status->getWikiText( false, false, 'en' ),
-                                               [
-                                                       'username' => $userName,
-                                               ]
-                                       );
-                               }
-                               $user->setId( $id );
-                               $user->loadFromId( User::READ_LATEST );
-                               return false;
-                               // @codeCoverageIgnoreEnd
-                       }
-               } catch ( \Exception $ex ) {
-                       // @codeCoverageIgnoreStart
-                       $logger->error( __METHOD__ . ': failed with exception {exception}', [
-                               'exception' => $ex,
-                               'username' => $userName,
-                       ] );
-                       // Do not keep throwing errors for a while
-                       $cache->set( $backoffKey, 1, 600 );
-                       // Bubble up error; which should normally trigger DB rollbacks
-                       throw $ex;
-                       // @codeCoverageIgnoreEnd
-               }
-
-               # Notify AuthPlugin
-               // @codeCoverageIgnoreStart
-               $tmpUser = $user;
-               $wgAuth->initUser( $tmpUser, true );
-               if ( $tmpUser !== $user ) {
-                       $logger->warning( __METHOD__ . ': ' .
-                               get_class( $wgAuth ) . '::initUser() replaced the user object' );
-               }
-               // @codeCoverageIgnoreEnd
-
-               # Notify hooks (e.g. Newuserlog)
-               \Hooks::run( 'AuthPluginAutoCreate', [ $user ] );
-               \Hooks::run( 'LocalUserCreated', [ $user, true ] );
-
-               $user->saveSettings();
-
-               # Update user count
-               \DeferredUpdates::addUpdate( new \SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
-
-               # Watch user's userpage and talk page
-               $user->addWatch( $user->getUserPage(), User::IGNORE_USER_RIGHTS );
-
-               return true;
+               wfDeprecated( __METHOD__, '1.27' );
+               return \MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
+                       $user,
+                       \MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
+                       false
+               )->isGood();
        }
 
        /**
index 69e2e8b..22413b9 100644 (file)
@@ -665,34 +665,17 @@ class SkinTemplate extends Skin {
                                ? 'nav-login-createaccount'
                                : 'pt-login';
 
-                       // TODO remove this after AuthManager is stable
-                       global $wgDisableAuthManager;
-                       if ( $wgDisableAuthManager ) {
-                               $is_signup = $request->getText( 'type' ) == 'signup';
-                               $login_url = [
-                                       'text' => $this->msg( $loginlink )->text(),
-                                       'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
-                                       'active' => $title->isSpecial( 'Userlogin' )
-                                               && ( $loginlink == 'nav-login-createaccount' || !$is_signup ),
-                               ];
-                               $createaccount_url = [
-                                       'text' => $this->msg( 'pt-createaccount' )->text(),
-                                       'href' => self::makeSpecialUrl( 'Userlogin', "$returnto&type=signup" ),
-                                       'active' => $title->isSpecial( 'Userlogin' ) && $is_signup,
-                               ];
-                       } else {
-                               $login_url = [
-                                       'text' => $this->msg( $loginlink )->text(),
-                                       'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
-                                       'active' => $title->isSpecial( 'Userlogin' ) ||
-                                               $title->isSpecial( 'CreateAccount' ) && $useCombinedLoginLink,
-                               ];
-                               $createaccount_url = [
-                                       'text' => $this->msg( 'pt-createaccount' )->text(),
-                                       'href' => self::makeSpecialUrl( 'CreateAccount', $returnto ),
-                                       'active' => $title->isSpecial( 'CreateAccount' ),
-                               ];
-                       }
+                       $login_url = [
+                               'text' => $this->msg( $loginlink )->text(),
+                               'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
+                               'active' => $title->isSpecial( 'Userlogin' )
+                                       || $title->isSpecial( 'CreateAccount' ) && $useCombinedLoginLink,
+                       ];
+                       $createaccount_url = [
+                               'text' => $this->msg( 'pt-createaccount' )->text(),
+                               'href' => self::makeSpecialUrl( 'CreateAccount', $returnto ),
+                               'active' => $title->isSpecial( 'CreateAccount' ),
+                       ];
 
                        // No need to show Talk and Contributions to anons if they can't contribute!
                        if ( User::groupHasPermission( '*', 'edit' ) ) {
index 5dab221..8a2e0d6 100644 (file)
@@ -1342,196 +1342,12 @@ class FakeAuthTemplate extends BaseTemplate {
        }
 }
 
-/**
- * A horrible hack to handle AuthManager's feature flag. For other special pages this is done in
- * SpecialPageFactory, but LoginForm is used directly by some extensions. Will be killed as soon
- * as AuthManager is stable.
- */
-class LoginForm extends SpecialPage {
-       private $realLoginForm;
-
-       public function __construct( $request = null ) {
-               global $wgDisableAuthManager;
-               if ( $wgDisableAuthManager ) {
-                       $this->realLoginForm = new LoginFormPreAuthManager( $request );
-               } else {
-                       $this->realLoginForm = new LoginFormAuthManager( $request );
-               }
-       }
-
-       // proxy everything
-
-       public function __get( $name ) {
-               return $this->realLoginForm->$name;
-       }
-
-       public function __set( $name, $value ) {
-               $this->realLoginForm->$name = $value;
-       }
-
-       public function __call( $name, $args ) {
-               return call_user_func_array( [ $this->realLoginForm, $name ], $args );
-       }
-
-       public static function __callStatic( $name, $args ) {
-               global $wgDisableAuthManager;
-               return call_user_func_array( [ $wgDisableAuthManager ? LoginFormPreAuthManager::class
-                       : LoginFormAuthManager::class, $name ], $args );
-       }
-
-       // all public SpecialPage methods need to be proxied explicitly
-
-       public function getName() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getRestriction() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function isListed() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function setListed( $listed ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function listed( $x = null ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function isIncludable() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function including( $x = null ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getLocalName() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function isExpensive() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function isCached() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function isRestricted() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function userCanExecute( User $user ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function displayRestrictionError() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function checkPermissions() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function checkReadOnly() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function requireLogin(
-               $reasonMsg = 'exception-nologin-text', $titleMsg = 'exception-nologin'
-       ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function prefixSearchSubpages( $search, $limit, $offset ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function execute( $subPage ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getDescription() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       function getTitle( $subpage = false ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       function getPageTitle( $subpage = false ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function setContext( $context ) {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getContext() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getRequest() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getOutput() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getUser() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getSkin() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getLanguage() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getConfig() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getFullTitle() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function getFinalGroupName() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-       public function doesWrites() {
-               return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
-       }
-
-       // no way to proxy constants and static properties
-
-       const SUCCESS = 0;
-       const NO_NAME = 1;
-       const ILLEGAL = 2;
-       const WRONG_PLUGIN_PASS = 3;
-       const NOT_EXISTS = 4;
-       const WRONG_PASS = 5;
-       const EMPTY_PASS = 6;
-       const RESET_PASS = 7;
-       const ABORTED = 8;
-       const CREATE_BLOCKED = 9;
-       const THROTTLED = 10;
-       const USER_BLOCKED = 11;
-       const NEED_TOKEN = 12;
-       const WRONG_TOKEN = 13;
-       const USER_MIGRATED = 14;
-
-       public static $statusCodes = [
-               self::SUCCESS => 'success',
-               self::NO_NAME => 'no_name',
-               self::ILLEGAL => 'illegal',
-               self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
-               self::NOT_EXISTS => 'not_exists',
-               self::WRONG_PASS => 'wrong_pass',
-               self::EMPTY_PASS => 'empty_pass',
-               self::RESET_PASS => 'reset_pass',
-               self::ABORTED => 'aborted',
-               self::CREATE_BLOCKED => 'create_blocked',
-               self::THROTTLED => 'throttled',
-               self::USER_BLOCKED => 'user_blocked',
-               self::NEED_TOKEN => 'need_token',
-               self::WRONG_TOKEN => 'wrong_token',
-               self::USER_MIGRATED => 'user_migrated',
-       ];
-
-       public static $validErrorMessages = [
-               'exception-nologin-text',
-               'watchlistanontext',
-               'changeemail-no-info',
-               'resetpass-no-info',
-               'confirmemail_needlogin',
-               'prefsnologintext2',
-       ];
-}
-
 /**
  * LoginForm as a special page has been replaced by SpecialUserLogin and SpecialCreateAccount,
  * but some extensions called its public methods directly, so the class is retained as a
  * B/C wrapper. Anything that used it before should use AuthManager instead.
  */
-class LoginFormAuthManager extends SpecialPage {
+class LoginForm extends SpecialPage {
        const SUCCESS = 0;
        const NO_NAME = 1;
        const ILLEGAL = 2;
index b69b28a..030a903 100644 (file)
@@ -84,8 +84,8 @@ class SpecialPageFactory {
 
                // Authentication
                'Userlogin' => 'SpecialUserLogin',
-               'Userlogout' => 'SpecialUserlogoutPreAuthManager',
-               'CreateAccount' => 'SpecialCreateAccountPreAuthManager',
+               'Userlogout' => 'SpecialUserLogout',
+               'CreateAccount' => 'SpecialCreateAccount',
                'LinkAccounts' => 'SpecialLinkAccounts',
                'UnlinkAccounts' => 'SpecialUnlinkAccounts',
                'ChangeCredentials' => 'SpecialChangeCredentials',
@@ -96,9 +96,9 @@ class SpecialPageFactory {
                'Block' => 'SpecialBlock',
                'Unblock' => 'SpecialUnblock',
                'BlockList' => 'SpecialBlockList',
-               'ChangePassword' => 'SpecialChangePasswordPreAuthManager',
+               'ChangePassword' => 'SpecialChangePassword',
                'BotPasswords' => 'SpecialBotPasswords',
-               'PasswordReset' => 'SpecialPasswordResetPreAuthManager',
+               'PasswordReset' => 'SpecialPasswordReset',
                'DeletedContributions' => 'DeletedContributionsPage',
                'Preferences' => 'SpecialPreferences',
                'ResetTokens' => 'SpecialResetTokens',
@@ -231,7 +231,6 @@ class SpecialPageFactory {
                global $wgDisableInternalSearch, $wgEmailAuthentication;
                global $wgEnableEmail, $wgEnableJavaScriptTest;
                global $wgPageLanguageUseDB, $wgContentHandlerUseDB;
-               global $wgDisableAuthManager;
 
                if ( !is_array( self::$list ) ) {
 
@@ -247,7 +246,7 @@ class SpecialPageFactory {
                        }
 
                        if ( $wgEnableEmail ) {
-                               self::$list['ChangeEmail'] = 'SpecialChangeEmailPreAuthManager';
+                               self::$list['ChangeEmail'] = 'SpecialChangeEmail';
                        }
 
                        if ( $wgEnableJavaScriptTest ) {
@@ -261,20 +260,6 @@ class SpecialPageFactory {
                                self::$list['ChangeContentModel'] = 'SpecialChangeContentModel';
                        }
 
-                       // horrible hack to allow selection between old and new classes via a feature flag - T110756
-                       // will be removed once AuthManager is stable
-                       if ( !$wgDisableAuthManager ) {
-                               self::$list = array_map( function ( $class ) {
-                                       return preg_replace( '/PreAuthManager$/', '', $class );
-                               }, self::$list );
-                               self::$list['Userlogout'] = 'SpecialUserLogout'; // case matters
-                       } else {
-                               self::$list['Userlogin'] = 'LoginForm';
-                               self::$list = array_diff_key( self::$list, array_fill_keys( [
-                                       'LinkAccounts', 'UnlinkAccounts', 'ChangeCredentials', 'RemoveCredentials',
-                               ], true ) );
-                       }
-
                        // Add extension special pages
                        self::$list = array_merge( self::$list, $wgSpecialPages );
 
index 4da8049..d98504d 100644 (file)
@@ -184,6 +184,7 @@ class SpecialChangeCredentials extends AuthManagerSpecialPage {
                        $groupedRequests[(string)$info['provider']][] = $req;
                }
 
+               $linkRenderer = $this->getLinkRenderer();
                $out->addHTML( Html::openElement( 'dl' ) );
                foreach ( $groupedRequests as $group => $members ) {
                        $out->addHTML( Html::element( 'dt', [], $group ) );
@@ -191,8 +192,10 @@ class SpecialChangeCredentials extends AuthManagerSpecialPage {
                                /** @var AuthenticationRequest $req */
                                $info = $req->describeCredentials();
                                $out->addHTML( Html::rawElement( 'dd', [],
-                                       Linker::link( $this->getPageTitle( $req->getUniqueId() ),
-                                               htmlspecialchars( $info['account'], ENT_QUOTES ) )
+                                       $linkRenderer->makeLink(
+                                               $this->getPageTitle( $req->getUniqueId() ),
+                                               $info['account']
+                                       )
                                ) );
                        }
                }
index cce88b9..0a98721 100644 (file)
@@ -267,13 +267,13 @@ class SpecialContributions extends IncludableSpecialPage {
                        }
                        $user = htmlspecialchars( $userObj->getName() );
                } else {
-                       $user = Linker::link( $userObj->getUserPage(), htmlspecialchars( $userObj->getName() ) );
+                       $user = $this->getLinkRenderer()->makeLink( $userObj->getUserPage(), $userObj->getName() );
                }
                $nt = $userObj->getUserPage();
                $talk = $userObj->getTalkPage();
                $links = '';
                if ( $talk ) {
-                       $tools = $this->getUserLinks( $nt, $talk, $userObj );
+                       $tools = self::getUserLinks( $this, $userObj );
                        $links = $this->getLanguage()->pipeList( $tools );
 
                        // Show a note if the user is blocked and display the last block log entry.
@@ -313,86 +313,93 @@ class SpecialContributions extends IncludableSpecialPage {
 
        /**
         * Links to different places.
-        * @param Title $userpage Target user page
-        * @param Title $talkpage Talk page
+        *
+        * @note This function is also called in DeletedContributionsPage
+        * @param SpecialPage $sp SpecialPage instance, for context
         * @param User $target Target user object
         * @return array
         */
-       public function getUserLinks( Title $userpage, Title $talkpage, User $target ) {
+       public static function getUserLinks( SpecialPage $sp, User $target ) {
 
                $id = $target->getId();
                $username = $target->getName();
+               $userpage = $target->getUserPage();
+               $talkpage = $target->getTalkPage();
 
-               $tools[] = Linker::link( $talkpage, $this->msg( 'sp-contributions-talk' )->escaped() );
+               $linkRenderer = $sp->getLinkRenderer();
+               $tools['user-talk'] = $linkRenderer->makeLink(
+                       $talkpage,
+                       $sp->msg( 'sp-contributions-talk' )->text()
+               );
 
                if ( ( $id !== null ) || ( $id === null && IP::isIPAddress( $username ) ) ) {
-                       if ( $this->getUser()->isAllowed( 'block' ) ) { # Block / Change block / Unblock links
+                       if ( $sp->getUser()->isAllowed( 'block' ) ) { # Block / Change block / Unblock links
                                if ( $target->isBlocked() && $target->getBlock()->getType() != Block::TYPE_AUTO ) {
-                                       $tools[] = Linker::linkKnown( # Change block link
+                                       $tools['block'] = $linkRenderer->makeKnownLink( # Change block link
                                                SpecialPage::getTitleFor( 'Block', $username ),
-                                               $this->msg( 'change-blocklink' )->escaped()
+                                               $sp->msg( 'change-blocklink' )->text()
                                        );
-                                       $tools[] = Linker::linkKnown( # Unblock link
+                                       $tools['unblock'] = $linkRenderer->makeKnownLink( # Unblock link
                                                SpecialPage::getTitleFor( 'Unblock', $username ),
-                                               $this->msg( 'unblocklink' )->escaped()
+                                               $sp->msg( 'unblocklink' )->text()
                                        );
                                } else { # User is not blocked
-                                       $tools[] = Linker::linkKnown( # Block link
+                                       $tools['block'] = $linkRenderer->makeKnownLink( # Block link
                                                SpecialPage::getTitleFor( 'Block', $username ),
-                                               $this->msg( 'blocklink' )->escaped()
+                                               $sp->msg( 'blocklink' )->text()
                                        );
                                }
                        }
 
                        # Block log link
-                       $tools[] = Linker::linkKnown(
+                       $tools['log-block'] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( 'Log', 'block' ),
-                               $this->msg( 'sp-contributions-blocklog' )->escaped(),
+                               $sp->msg( 'sp-contributions-blocklog' )->text(),
                                [],
                                [ 'page' => $userpage->getPrefixedText() ]
                        );
 
                        # Suppression log link (bug 59120)
-                       if ( $this->getUser()->isAllowed( 'suppressionlog' ) ) {
-                               $tools[] = Linker::linkKnown(
+                       if ( $sp->getUser()->isAllowed( 'suppressionlog' ) ) {
+                               $tools['log-suppression'] = $linkRenderer->makeKnownLink(
                                        SpecialPage::getTitleFor( 'Log', 'suppress' ),
-                                       $this->msg( 'sp-contributions-suppresslog' )->escaped(),
+                                       $sp->msg( 'sp-contributions-suppresslog' )->text(),
                                        [],
                                        [ 'offender' => $username ]
                                );
                        }
                }
                # Uploads
-               $tools[] = Linker::linkKnown(
+               $tools['uploads'] = $linkRenderer->makeKnownLink(
                        SpecialPage::getTitleFor( 'Listfiles', $username ),
-                       $this->msg( 'sp-contributions-uploads' )->escaped()
+                       $sp->msg( 'sp-contributions-uploads' )->text()
                );
 
                # Other logs link
-               $tools[] = Linker::linkKnown(
+               $tools['logs'] = $linkRenderer->makeKnownLink(
                        SpecialPage::getTitleFor( 'Log', $username ),
-                       $this->msg( 'sp-contributions-logs' )->escaped()
+                       $sp->msg( 'sp-contributions-logs' )->text()
                );
 
                # Add link to deleted user contributions for priviledged users
-               if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) {
-                       $tools[] = Linker::linkKnown(
+               if ( $sp->getUser()->isAllowed( 'deletedhistory' ) ) {
+                       $tools['deletedcontribs'] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( 'DeletedContributions', $username ),
-                               $this->msg( 'sp-contributions-deleted' )->escaped()
+                               $sp->msg( 'sp-contributions-deleted' )->text()
                        );
                }
 
                # Add a link to change user rights for privileged users
                $userrightsPage = new UserrightsPage();
-               $userrightsPage->setContext( $this->getContext() );
+               $userrightsPage->setContext( $sp->getContext() );
                if ( $userrightsPage->userCanChangeRights( $target ) ) {
-                       $tools[] = Linker::linkKnown(
+                       $tools['userrights'] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( 'Userrights', $username ),
-                               $this->msg( 'sp-contributions-userrights' )->escaped()
+                               $sp->msg( 'sp-contributions-userrights' )->text()
                        );
                }
 
-               Hooks::run( 'ContributionsToolLinks', [ $id, $userpage, &$tools ] );
+               Hooks::run( 'ContributionsToolLinks', [ $id, $userpage, &$tools, $sp ] );
 
                return $tools;
        }
index 190bf9f..8e168b2 100644 (file)
@@ -129,97 +129,29 @@ class DeletedContributionsPage extends SpecialPage {
         * Generates the subheading with links
         * @param User $userObj User object for the target
         * @return string Appropriately-escaped HTML to be output literally
-        * @todo FIXME: Almost the same as contributionsSub in SpecialContributions.php. Could be combined.
         */
        function getSubTitle( $userObj ) {
+               $linkRenderer = $this->getLinkRenderer();
                if ( $userObj->isAnon() ) {
                        $user = htmlspecialchars( $userObj->getName() );
                } else {
-                       $user = Linker::link( $userObj->getUserPage(), htmlspecialchars( $userObj->getName() ) );
+                       $user = $linkRenderer->makeKnownLink( $userObj->getUserPage(), $userObj->getName() );
                }
                $links = '';
                $nt = $userObj->getUserPage();
-               $id = $userObj->getId();
                $talk = $nt->getTalkPage();
                if ( $talk ) {
-                       # Talk page link
-                       $tools[] = Linker::link( $talk, $this->msg( 'sp-contributions-talk' )->escaped() );
-                       if ( ( $id !== null ) || ( $id === null && IP::isIPAddress( $nt->getText() ) ) ) {
-                               # Block / Change block / Unblock links
-                               if ( $this->getUser()->isAllowed( 'block' ) ) {
-                                       if ( $userObj->isBlocked() && $userObj->getBlock()->getType() !== Block::TYPE_AUTO ) {
-                                               $tools[] = Linker::linkKnown( # Change block link
-                                                       SpecialPage::getTitleFor( 'Block', $nt->getDBkey() ),
-                                                       $this->msg( 'change-blocklink' )->escaped()
-                                               );
-                                               $tools[] = Linker::linkKnown( # Unblock link
-                                                       SpecialPage::getTitleFor( 'BlockList' ),
-                                                       $this->msg( 'unblocklink' )->escaped(),
-                                                       [],
-                                                       [
-                                                               'action' => 'unblock',
-                                                               'ip' => $nt->getDBkey()
-                                                       ]
-                                               );
-                                       } else {
-                                               # User is not blocked
-                                               $tools[] = Linker::linkKnown( # Block link
-                                                       SpecialPage::getTitleFor( 'Block', $nt->getDBkey() ),
-                                                       $this->msg( 'blocklink' )->escaped()
-                                               );
-                                       }
-                               }
-                               # Block log link
-                               $tools[] = Linker::linkKnown(
-                                       SpecialPage::getTitleFor( 'Log' ),
-                                       $this->msg( 'sp-contributions-blocklog' )->escaped(),
-                                       [],
-                                       [
-                                               'type' => 'block',
-                                               'page' => $nt->getPrefixedText()
-                                       ]
-                               );
-                               # Suppression log link (bug 59120)
-                               if ( $this->getUser()->isAllowed( 'suppressionlog' ) ) {
-                                       $tools[] = Linker::linkKnown(
-                                               SpecialPage::getTitleFor( 'Log', 'suppress' ),
-                                               $this->msg( 'sp-contributions-suppresslog' )->escaped(),
-                                               [],
-                                               [ 'offender' => $userObj->getName() ]
-                                       );
-                               }
-                       }
+                       $tools = SpecialContributions::getUserLinks( $this, $userObj );
 
-                       # Uploads
-                       $tools[] = Linker::linkKnown(
-                               SpecialPage::getTitleFor( 'Listfiles', $userObj->getName() ),
-                               $this->msg( 'sp-contributions-uploads' )->escaped()
-                       );
-
-                       # Other logs link
-                       $tools[] = Linker::linkKnown(
-                               SpecialPage::getTitleFor( 'Log' ),
-                               $this->msg( 'sp-contributions-logs' )->escaped(),
-                               [],
-                               [ 'user' => $nt->getText() ]
-                       );
                        # Link to contributions
-                       $tools[] = Linker::linkKnown(
+                       $insert['contribs'] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( 'Contributions', $nt->getDBkey() ),
-                               $this->msg( 'sp-deletedcontributions-contribs' )->escaped()
+                               $this->msg( 'sp-deletedcontributions-contribs' )->text()
                        );
 
-                       # Add a link to change user rights for privileged users
-                       $userrightsPage = new UserrightsPage();
-                       $userrightsPage->setContext( $this->getContext() );
-                       if ( $userrightsPage->userCanChangeRights( $userObj ) ) {
-                               $tools[] = Linker::linkKnown(
-                                       SpecialPage::getTitleFor( 'Userrights', $nt->getDBkey() ),
-                                       $this->msg( 'sp-contributions-userrights' )->escaped()
-                               );
-                       }
-
-                       Hooks::run( 'ContributionsToolLinks', [ $id, $nt, &$tools ] );
+                       // Swap out the deletedcontribs link for our contribs one
+                       $tools = wfArrayInsertAfter( $tools, $insert, 'deletedcontribs' );
+                       unset( $tools['deletedcontribs'] );
 
                        $links = $this->getLanguage()->pipeList( $tools );
 
index 627dd2c..a5a45d5 100644 (file)
@@ -2,7 +2,6 @@
 /**
  * @defgroup Watchlist Users watchlist handling
  */
-use MediaWiki\Linker\LinkTarget;
 
 /**
  * Implements Special:EditWatchlist
@@ -27,6 +26,8 @@ use MediaWiki\Linker\LinkTarget;
  * @ingroup Watchlist
  */
 
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\Linker\LinkTarget;
 use MediaWiki\MediaWikiServices;
 
 /**
@@ -138,7 +139,13 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
        protected function outputSubtitle() {
                $out = $this->getOutput();
                $out->addSubtitle( $this->msg( 'watchlistfor2', $this->getUser()->getName() )
-                       ->rawParams( SpecialEditWatchlist::buildTools( null ) ) );
+                       ->rawParams(
+                               self::buildTools(
+                                       $this->getLanguage(),
+                                       $this->getLinkRenderer()
+                               )
+                       )
+               );
        }
 
        /**
@@ -277,7 +284,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
         * @param string $output
         */
        private function showTitles( $titles, &$output ) {
-               $talk = $this->msg( 'talkpagelinktext' )->escaped();
+               $talk = $this->msg( 'talkpagelinktext' )->text();
                // Do a batch existence check
                $batch = new LinkBatch();
                if ( count( $titles ) >= 100 ) {
@@ -300,6 +307,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                // Print out the list
                $output .= "<ul>\n";
 
+               $linkRenderer = $this->getLinkRenderer();
                foreach ( $titles as $title ) {
                        if ( !$title instanceof Title ) {
                                $title = Title::newFromText( $title );
@@ -307,9 +315,9 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
 
                        if ( $title instanceof Title ) {
                                $output .= '<li>' .
-                                       Linker::link( $title ) . ' ' .
+                                       $linkRenderer->makeLink( $title ) . ' ' .
                                        $this->msg( 'parentheses' )->rawParams(
-                                               Linker::link( $title->getTalkPage(), $talk )
+                                               $linkRenderer->makeLink( $title->getTalkPage(), $talk )
                                        )->escaped() .
                                        "</li>\n";
                        }
@@ -610,26 +618,27 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
         * @return string
         */
        private function buildRemoveLine( $title ) {
-               $link = Linker::link( $title );
+               $linkRenderer = $this->getLinkRenderer();
+               $link = $linkRenderer->makeLink( $title );
 
-               $tools['talk'] = Linker::link(
+               $tools['talk'] = $linkRenderer->makeLink(
                        $title->getTalkPage(),
-                       $this->msg( 'talkpagelinktext' )->escaped()
+                       $this->msg( 'talkpagelinktext' )->text()
                );
 
                if ( $title->exists() ) {
-                       $tools['history'] = Linker::linkKnown(
+                       $tools['history'] = $linkRenderer->makeKnownLink(
                                $title,
-                               $this->msg( 'history_short' )->escaped(),
+                               $this->msg( 'history_short' )->text(),
                                [],
                                [ 'action' => 'history' ]
                        );
                }
 
                if ( $title->getNamespace() == NS_USER && !$title->isSubpage() ) {
-                       $tools['contributions'] = Linker::linkKnown(
+                       $tools['contributions'] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( 'Contributions', $title->getText() ),
-                               $this->msg( 'contributions' )->escaped()
+                               $this->msg( 'contributions' )->text()
                        );
                }
 
@@ -724,11 +733,19 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
         * Build a set of links for convenient navigation
         * between watchlist viewing and editing modes
         *
-        * @param null $unused
+        * @param Language $lang
+        * @param LinkRenderer|null $linkRenderer
         * @return string
         */
-       public static function buildTools( $unused ) {
-               global $wgLang;
+       public static function buildTools( $lang, LinkRenderer $linkRenderer = null ) {
+               if ( !$lang instanceof Language ) {
+                       // back-compat where the first parameter was $unused
+                       global $wgLang;
+                       $lang = $wgLang;
+               }
+               if ( !$linkRenderer ) {
+                       $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+               }
 
                $tools = [];
                $modes = [
@@ -740,16 +757,16 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
 
                foreach ( $modes as $mode => $arr ) {
                        // can use messages 'watchlisttools-view', 'watchlisttools-edit', 'watchlisttools-raw'
-                       $tools[] = Linker::linkKnown(
+                       $tools[] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( $arr[0], $arr[1] ),
-                               wfMessage( "watchlisttools-{$mode}" )->escaped()
+                               wfMessage( "watchlisttools-{$mode}" )->text()
                        );
                }
 
                return Html::rawElement(
                        'span',
                        [ 'class' => 'mw-watchlist-toollinks' ],
-                       wfMessage( 'parentheses' )->rawParams( $wgLang->pipeList( $tools ) )->escaped()
+                       wfMessage( 'parentheses' )->rawParams( $lang->pipeList( $tools ) )->escaped()
                );
        }
 }
index b8316f3..3ead08a 100644 (file)
@@ -94,7 +94,7 @@ class MostlinkedCategoriesPage extends QueryPage {
                }
 
                $text = $wgContLang->convert( $nt->getText() );
-               $plink = Linker::link( $nt, htmlspecialchars( $text ) );
+               $plink = $this->getLinkRenderer()->makeLink( $nt, $text );
                $nlinks = $this->msg( 'nmembers' )->numParams( $result->value )->escaped();
 
                return $this->getLanguage()->specialList( $plink, $nlinks );
index 98ff187..077a5d2 100644 (file)
@@ -55,6 +55,7 @@ class SpecialNewFiles extends IncludableSpecialPage {
                $this->opts = $opts;
 
                if ( !$this->including() ) {
+                       $this->setTopText();
                        $this->buildForm();
                }
 
index 718a6dc..d2513ed 100644 (file)
@@ -349,6 +349,7 @@ class SpecialNewpages extends IncludableSpecialPage {
 
                if ( $this->patrollable( $result ) ) {
                        $classes[] = 'not-patrolled';
+                       $this->getOutput()->addModuleStyles( 'mediawiki.page.patrol' );
                }
 
                # Add a class for zero byte pages
index 54b471e..342509c 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\Linker\LinkRenderer;
+
 /**
  * A special page that lists protected pages
  *
@@ -59,7 +61,8 @@ class SpecialProtectedpages extends SpecialPage {
                        $size,
                        $indefOnly,
                        $cascadeOnly,
-                       $noRedirect
+                       $noRedirect,
+                       $this->getLinkRenderer()
                );
 
                $this->getOutput()->addHTML( $this->showOptions(
@@ -279,8 +282,27 @@ class ProtectedPagesPager extends TablePager {
        public $mForm, $mConds;
        private $type, $level, $namespace, $sizetype, $size, $indefonly, $cascadeonly, $noredirect;
 
+       /**
+        * @var LinkRenderer
+        */
+       private $linkRenderer;
+
+       /**
+        * @param SpecialProtectedpages $form
+        * @param array $conds
+        * @param $type
+        * @param $level
+        * @param $namespace
+        * @param string $sizetype
+        * @param int $size
+        * @param bool $indefonly
+        * @param bool $cascadeonly
+        * @param bool $noredirect
+        * @param LinkRenderer $linkRenderer
+        */
        function __construct( $form, $conds = [], $type, $level, $namespace,
-               $sizetype = '', $size = 0, $indefonly = false, $cascadeonly = false, $noredirect = false
+               $sizetype = '', $size = 0, $indefonly = false, $cascadeonly = false, $noredirect = false,
+               LinkRenderer $linkRenderer
        ) {
                $this->mForm = $form;
                $this->mConds = $conds;
@@ -292,6 +314,7 @@ class ProtectedPagesPager extends TablePager {
                $this->indefonly = (bool)$indefonly;
                $this->cascadeonly = (bool)$cascadeonly;
                $this->noredirect = (bool)$noredirect;
+               $this->linkRenderer = $linkRenderer;
                parent::__construct( $form->getContext() );
        }
 
@@ -354,8 +377,6 @@ class ProtectedPagesPager extends TablePager {
                /** @var $row object */
                $row = $this->mCurrentRow;
 
-               $formatted = '';
-
                switch ( $field ) {
                        case 'log_timestamp':
                                // when timestamp is null, this is a old protection row
@@ -384,7 +405,7 @@ class ProtectedPagesPager extends TablePager {
                                                )
                                        );
                                } else {
-                                       $formatted = Linker::link( $title );
+                                       $formatted = $this->linkRenderer->makeLink( $title );
                                }
                                if ( !is_null( $row->page_len ) ) {
                                        $formatted .= $this->getLanguage()->getDirMark() .
@@ -401,9 +422,9 @@ class ProtectedPagesPager extends TablePager {
                                        $value, /* User preference timezone */true ) );
                                $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
                                if ( $this->getUser()->isAllowed( 'protect' ) && $title ) {
-                                       $changeProtection = Linker::linkKnown(
+                                       $changeProtection = $this->linkRenderer->makeKnownLink(
                                                $title,
-                                               $this->msg( 'protect_change' )->escaped(),
+                                               $this->msg( 'protect_change' )->text(),
                                                [],
                                                [ 'action' => 'unprotect' ]
                                        );
index 20f2fc8..a76b511 100644 (file)
@@ -104,19 +104,20 @@ class ShortPagesPage extends QueryPage {
                                Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) );
                }
 
-               $hlink = Linker::linkKnown(
+               $linkRenderer = $this->getLinkRenderer();
+               $hlink = $linkRenderer->makeKnownLink(
                        $title,
-                       $this->msg( 'hist' )->escaped(),
+                       $this->msg( 'hist' )->text(),
                        [],
                        [ 'action' => 'history' ]
                );
                $hlinkInParentheses = $this->msg( 'parentheses' )->rawParams( $hlink )->escaped();
 
                if ( $this->isCached() ) {
-                       $plink = Linker::link( $title );
+                       $plink = $linkRenderer->makeLink( $title );
                        $exists = $title->exists();
                } else {
-                       $plink = Linker::linkKnown( $title );
+                       $plink = $linkRenderer->makeKnownLink( $title );
                        $exists = true;
                }
 
index 2139949..e957b3c 100644 (file)
@@ -128,8 +128,7 @@ class SpecialTags extends SpecialPage {
                        ChangeTags::listExtensionDefinedTags(), true );
 
                // List all defined tags, even if they were never applied
-               $definedTags = array_keys( array_merge(
-                       $this->explicitlyDefinedTags, $this->extensionDefinedTags ) );
+               $definedTags = array_keys( $this->explicitlyDefinedTags + $this->extensionDefinedTags );
 
                // Show header only if there exists atleast one tag
                if ( !$tagStats && !$definedTags ) {
@@ -176,12 +175,13 @@ class SpecialTags extends SpecialPage {
                $newRow = '';
                $newRow .= Xml::tags( 'td', null, Xml::element( 'code', null, $tag ) );
 
+               $linkRenderer = $this->getLinkRenderer();
                $disp = ChangeTags::tagDescription( $tag );
                if ( $showEditLinks ) {
                        $disp .= ' ';
-                       $editLink = Linker::link(
+                       $editLink = $linkRenderer->makeLink(
                                $this->msg( "tag-$tag" )->inContentLanguage()->getTitle(),
-                               $this->msg( 'tags-edit' )->escaped()
+                               $this->msg( 'tags-edit' )->text()
                        );
                        $disp .= $this->msg( 'parentheses' )->rawParams( $editLink )->escaped();
                }
@@ -191,9 +191,9 @@ class SpecialTags extends SpecialPage {
                $desc = !$msg->exists() ? '' : $msg->parse();
                if ( $showEditLinks ) {
                        $desc .= ' ';
-                       $editDescLink = Linker::link(
+                       $editDescLink = $linkRenderer->makeLink(
                                $this->msg( "tag-$tag-description" )->inContentLanguage()->getTitle(),
-                               $this->msg( 'tags-edit' )->escaped()
+                               $this->msg( 'tags-edit' )->text()
                        );
                        $desc .= $this->msg( 'parentheses' )->rawParams( $editDescLink )->escaped();
                }
@@ -217,14 +217,16 @@ class SpecialTags extends SpecialPage {
                $activeMsg = ( $isActive ? 'tags-active-yes' : 'tags-active-no' );
                $newRow .= Xml::tags( 'td', null, $this->msg( $activeMsg )->escaped() );
 
-               $hitcountLabel = $this->msg( 'tags-hitcount' )->numParams( $hitcount )->escaped();
+               $hitcountLabelMsg = $this->msg( 'tags-hitcount' )->numParams( $hitcount );
                if ( $this->getConfig()->get( 'UseTagFilter' ) ) {
-                       $hitcountLabel = Linker::link(
+                       $hitcountLabel = $linkRenderer->makeLink(
                                SpecialPage::getTitleFor( 'Recentchanges' ),
-                               $hitcountLabel,
+                               $hitcountLabelMsg->text(),
                                [],
                                [ 'tagfilter' => $tag ]
                        );
+               } else {
+                       $hitcountLabel = $hitcountLabelMsg->escaped();
                }
 
                // add raw $hitcount for sorting, because tags-hitcount contains numbers and letters
@@ -235,8 +237,9 @@ class SpecialTags extends SpecialPage {
 
                // delete
                if ( $showDeleteActions && ChangeTags::canDeleteTag( $tag )->isOK() ) {
-                       $actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'delete' ),
-                               $this->msg( 'tags-delete' )->escaped(),
+                       $actionLinks[] = $linkRenderer->makeKnownLink(
+                               $this->getPageTitle( 'delete' ),
+                               $this->msg( 'tags-delete' )->text(),
                                [],
                                [ 'tag' => $tag ] );
                }
@@ -245,16 +248,18 @@ class SpecialTags extends SpecialPage {
 
                        // activate
                        if ( ChangeTags::canActivateTag( $tag )->isOK() ) {
-                               $actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'activate' ),
-                                       $this->msg( 'tags-activate' )->escaped(),
+                               $actionLinks[] = $linkRenderer->makeKnownLink(
+                                       $this->getPageTitle( 'activate' ),
+                                       $this->msg( 'tags-activate' )->text(),
                                        [],
                                        [ 'tag' => $tag ] );
                        }
 
                        // deactivate
                        if ( ChangeTags::canDeactivateTag( $tag )->isOK() ) {
-                               $actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'deactivate' ),
-                                       $this->msg( 'tags-deactivate' )->escaped(),
+                               $actionLinks[] = $linkRenderer->makeKnownLink(
+                                       $this->getPageTitle( 'deactivate' ),
+                                       $this->msg( 'tags-deactivate' )->text(),
                                        [],
                                        [ 'tag' => $tag ] );
                        }
index a0e3096..bfb52e8 100644 (file)
@@ -22,6 +22,9 @@
  * @ingroup Upload
  */
 
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\MediaWikiServices;
+
 /**
  * Form for handling uploads and special page.
  *
@@ -261,7 +264,7 @@ class SpecialUpload extends SpecialPage {
                        'texttop' => $this->uploadFormTextTop,
                        'textaftersummary' => $this->uploadFormTextAfterSummary,
                        'destfile' => $this->mDesiredDestName,
-               ], $context );
+               ], $context, $this->getLinkRenderer() );
 
                # Check the token, but only if necessary
                if (
@@ -313,9 +316,9 @@ class SpecialUpload extends SpecialPage {
                if ( $title instanceof Title ) {
                        $count = $title->isDeleted();
                        if ( $count > 0 && $user->isAllowed( 'deletedhistory' ) ) {
-                               $restorelink = Linker::linkKnown(
+                               $restorelink = $this->getLinkRenderer()->makeKnownLink(
                                        SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedText() ),
-                                       $this->msg( 'restorelink' )->numParams( $count )->escaped()
+                                       $this->msg( 'restorelink' )->numParams( $count )->text()
                                );
                                $link = $this->msg( $user->isAllowed( 'delete' ) ? 'thisisdeleted' : 'viewdeleted' )
                                        ->rawParams( $restorelink )->parseAsBlock();
@@ -370,6 +373,7 @@ class SpecialUpload extends SpecialPage {
                // Add styles for the warning, reused from the live preview
                $this->getOutput()->addModuleStyles( 'mediawiki.special.upload.styles' );
 
+               $linkRenderer = $this->getLinkRenderer();
                $warningHtml = '<h2>' . $this->msg( 'uploadwarning' )->escaped() . "</h2>\n"
                        . '<div class="mw-destfile-warning"><ul>';
                foreach ( $warnings as $warning => $args ) {
@@ -381,9 +385,9 @@ class SpecialUpload extends SpecialPage {
                        } elseif ( $warning == 'was-deleted' ) {
                                # If the file existed before and was deleted, warn the user of this
                                $ltitle = SpecialPage::getTitleFor( 'Log' );
-                               $llink = Linker::linkKnown(
+                               $llink = $linkRenderer->makeKnownLink(
                                        $ltitle,
-                                       wfMessage( 'deletionlog' )->escaped(),
+                                       wfMessage( 'deletionlog' )->text(),
                                        [],
                                        [
                                                'type' => 'delete',
@@ -833,11 +837,17 @@ class UploadForm extends HTMLForm {
 
        protected $mMaxUploadSize = [];
 
-       public function __construct( array $options = [], IContextSource $context = null ) {
+       public function __construct( array $options = [], IContextSource $context = null,
+               LinkRenderer $linkRenderer = null
+       ) {
                if ( $context instanceof IContextSource ) {
                        $this->setContext( $context );
                }
 
+               if ( !$linkRenderer ) {
+                       $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+               }
+
                $this->mWatch = !empty( $options['watch'] );
                $this->mForReUpload = !empty( $options['forreupload'] );
                $this->mSessionKey = isset( $options['sessionkey'] ) ? $options['sessionkey'] : '';
@@ -862,12 +872,12 @@ class UploadForm extends HTMLForm {
                Hooks::run( 'UploadFormInitDescriptor', [ &$descriptor ] );
                parent::__construct( $descriptor, $context, 'upload' );
 
-               # Add a link to edit MediaWik:Licenses
+               # Add a link to edit MediaWiki:Licenses
                if ( $this->getUser()->isAllowed( 'editinterface' ) ) {
-                       $this->getOutput()->addModuleStyles( 'mediawiki.special' );
-                       $licensesLink = Linker::linkKnown(
+                       $this->getOutput()->addModuleStyles( 'mediawiki.special.upload.styles' );
+                       $licensesLink = $linkRenderer->makeKnownLink(
                                $this->msg( 'licenses' )->inContentLanguage()->getTitle(),
-                               $this->msg( 'licenses-edit' )->escaped(),
+                               $this->msg( 'licenses-edit' )->text(),
                                [],
                                [ 'action' => 'edit' ]
                        );
index 555fe5c..1412324 100644 (file)
@@ -391,17 +391,21 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                if ( $files && count( $files ) ) {
                        sort( $files );
                        $fileListItemsHtml = '';
+                       $linkRenderer = $this->getLinkRenderer();
                        foreach ( $files as $file ) {
-                               $itemHtml = Linker::linkKnown( $this->getPageTitle( "file/$file" ), htmlspecialchars( $file ) );
+                               $itemHtml = $linkRenderer->makeKnownLink(
+                                       $this->getPageTitle( "file/$file" ),
+                                       $file
+                               );
                                try {
                                        $fileObj = $this->stash->getFile( $file );
                                        $thumb = $fileObj->generateThumbName( $file, [ 'width' => 220 ] );
                                        $itemHtml .=
                                                $this->msg( 'word-separator' )->escaped() .
                                                $this->msg( 'parentheses' )->rawParams(
-                                                       Linker::linkKnown(
+                                                       $linkRenderer->makeKnownLink(
                                                                $this->getPageTitle( "thumb/$file/$thumb" ),
-                                                               $this->msg( 'uploadstash-thumbnail' )->escaped()
+                                                               $this->msg( 'uploadstash-thumbnail' )->text()
                                                        )
                                                )->escaped();
                                } catch ( Exception $e ) {
index 58cde7e..17d77ba 100644 (file)
@@ -429,7 +429,10 @@ class SpecialWatchlist extends ChangesListSpecialPage {
 
                $out->addSubtitle(
                        $this->msg( 'watchlistfor2', $user->getName() )
-                               ->rawParams( SpecialEditWatchlist::buildTools( null ) )
+                               ->rawParams( SpecialEditWatchlist::buildTools(
+                                       $this->getLanguage(),
+                                       $this->getLinkRenderer()
+                               ) )
                );
 
                $this->setTopText( $opts );
diff --git a/includes/specials/pre-authmanager/README b/includes/specials/pre-authmanager/README
deleted file mode 100644 (file)
index 1cfdd5f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-This directory temporarily hosts pre-AuthManager code as a way of feature-flagging.
-Class names are postfixed with 'PreAuthManager' and SpecialPageFactory adds/removes
-that postfix based on the feature flag.
-
-This is a horrible hack that will only be in place for a few weeks, to allow instant
-rollback while AuthManager is tested in WMF production and major problems are ironed
-out. In the past such issues have been handled via deployment branches, but that
-meant blocking the work of all WMF developers from being deployed. This is hoped
-to be a less disruptive method.
-
diff --git a/includes/specials/pre-authmanager/SpecialChangeEmail.php b/includes/specials/pre-authmanager/SpecialChangeEmail.php
deleted file mode 100644 (file)
index 7861562..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-<?php
-/**
- * Implements Special:ChangeEmail
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-/**
- * Let users change their email address.
- *
- * @ingroup SpecialPage
- */
-class SpecialChangeEmailPreAuthManager extends FormSpecialPage {
-       /**
-        * @var Status
-        */
-       private $status;
-
-       public function __construct() {
-               parent::__construct( 'ChangeEmail', 'editmyprivateinfo' );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       /**
-        * @return bool
-        */
-       public function isListed() {
-               global $wgAuth;
-
-               return $wgAuth->allowPropChange( 'emailaddress' );
-       }
-
-       /**
-        * Main execution point
-        * @param string $par
-        */
-       function execute( $par ) {
-               $out = $this->getOutput();
-               $out->disallowUserJs();
-
-               parent::execute( $par );
-       }
-
-       protected function checkExecutePermissions( User $user ) {
-               global $wgAuth;
-
-               if ( !$wgAuth->allowPropChange( 'emailaddress' ) ) {
-                       throw new ErrorPageError( 'changeemail', 'cannotchangeemail' );
-               }
-
-               $this->requireLogin( 'changeemail-no-info' );
-
-               // This could also let someone check the current email address, so
-               // require both permissions.
-               if ( !$this->getUser()->isAllowed( 'viewmyprivateinfo' ) ) {
-                       throw new PermissionsError( 'viewmyprivateinfo' );
-               }
-
-               parent::checkExecutePermissions( $user );
-       }
-
-       protected function getFormFields() {
-               $user = $this->getUser();
-
-               $fields = [
-                       'Name' => [
-                               'type' => 'info',
-                               'label-message' => 'username',
-                               'default' => $user->getName(),
-                       ],
-                       'OldEmail' => [
-                               'type' => 'info',
-                               'label-message' => 'changeemail-oldemail',
-                               'default' => $user->getEmail() ?: $this->msg( 'changeemail-none' )->text(),
-                       ],
-                       'NewEmail' => [
-                               'type' => 'email',
-                               'label-message' => 'changeemail-newemail',
-                               'autofocus' => true,
-                               'help-message' => 'changeemail-newemail-help',
-                       ],
-               ];
-
-               if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' ) ) {
-                       $fields['Password'] = [
-                               'type' => 'password',
-                               'label-message' => 'changeemail-password'
-                       ];
-               }
-
-               return $fields;
-       }
-
-       protected function getDisplayFormat() {
-               return 'ooui';
-       }
-
-       protected function alterForm( HTMLForm $form ) {
-               $form->setId( 'mw-changeemail-form' );
-               $form->setTableId( 'mw-changeemail-table' );
-               $form->setSubmitTextMsg( 'changeemail-submit' );
-               $form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
-
-               $form->addHeaderText( $this->msg( 'changeemail-header' )->parseAsBlock() );
-               if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' ) ) {
-                       $form->addHeaderText( $this->msg( 'changeemail-passwordrequired' )->parseAsBlock() );
-               }
-       }
-
-       public function onSubmit( array $data ) {
-               $password = isset( $data['Password'] ) ? $data['Password'] : null;
-               $status = $this->attemptChange( $this->getUser(), $password, $data['NewEmail'] );
-
-               $this->status = $status;
-
-               return $status;
-       }
-
-       public function onSuccess() {
-               $request = $this->getRequest();
-
-               $returnto = $request->getVal( 'returnto' );
-               $titleObj = $returnto !== null ? Title::newFromText( $returnto ) : null;
-               if ( !$titleObj instanceof Title ) {
-                       $titleObj = Title::newMainPage();
-               }
-               $query = $request->getVal( 'returntoquery' );
-
-               if ( $this->status->value === true ) {
-                       $this->getOutput()->redirect( $titleObj->getFullURL( $query ) );
-               } elseif ( $this->status->value === 'eauth' ) {
-                       # Notify user that a confirmation email has been sent...
-                       $this->getOutput()->wrapWikiMsg( "<div class='error' style='clear: both;'>\n$1\n</div>",
-                               'eauthentsent', $this->getUser()->getName() );
-                       // just show the link to go back
-                       $this->getOutput()->addReturnTo( $titleObj, wfCgiToArray( $query ) );
-               }
-       }
-
-       /**
-        * @param User $user
-        * @param string $pass
-        * @param string $newaddr
-        * @return Status
-        */
-       private function attemptChange( User $user, $pass, $newaddr ) {
-               global $wgAuth;
-
-               if ( $newaddr != '' && !Sanitizer::validateEmail( $newaddr ) ) {
-                       return Status::newFatal( 'invalidemailaddress' );
-               }
-
-               if ( $newaddr === $user->getEmail() ) {
-                       return Status::newFatal( 'changeemail-nochange' );
-               }
-
-               $throttleInfo = LoginForm::incrementLoginThrottle( $user->getName() );
-               if ( $throttleInfo ) {
-                       $lang = $this->getLanguage();
-                       return Status::newFatal(
-                               'changeemail-throttled',
-                               $lang->formatDuration( $throttleInfo['wait'] )
-                       );
-               }
-
-               if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' )
-                       && !$user->checkTemporaryPassword( $pass )
-                       && !$user->checkPassword( $pass )
-               ) {
-                       return Status::newFatal( 'wrongpassword' );
-               }
-
-               LoginForm::clearLoginThrottle( $user->getName() );
-
-               $oldaddr = $user->getEmail();
-               $status = $user->setEmailWithConfirmation( $newaddr );
-               if ( !$status->isGood() ) {
-                       return $status;
-               }
-
-               Hooks::run( 'PrefsEmailAudit', [ $user, $oldaddr, $newaddr ] );
-
-               $user->saveSettings();
-
-               $wgAuth->updateExternalDB( $user );
-
-               return $status;
-       }
-
-       public function requiresUnblock() {
-               return false;
-       }
-
-       protected function getGroupName() {
-               return 'users';
-       }
-}
diff --git a/includes/specials/pre-authmanager/SpecialChangePassword.php b/includes/specials/pre-authmanager/SpecialChangePassword.php
deleted file mode 100644 (file)
index 3955fee..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-<?php
-/**
- * Implements Special:ChangePassword
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-/**
- * Let users recover their password.
- *
- * @ingroup SpecialPage
- */
-class SpecialChangePasswordPreAuthManager extends FormSpecialPage {
-       protected $mUserName;
-       protected $mDomain;
-
-       // Optional Wikitext Message to show above the password change form
-       protected $mPreTextMessage = null;
-
-       // label for old password input
-       protected $mOldPassMsg = null;
-
-       public function __construct() {
-               parent::__construct( 'ChangePassword', 'editmyprivateinfo' );
-               $this->listed( false );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       /**
-        * Main execution point
-        * @param string|null $par
-        */
-       function execute( $par ) {
-               $this->getOutput()->disallowUserJs();
-
-               parent::execute( $par );
-       }
-
-       protected function checkExecutePermissions( User $user ) {
-               parent::checkExecutePermissions( $user );
-
-               if ( !$this->getRequest()->wasPosted() ) {
-                       $this->requireLogin( 'resetpass-no-info' );
-               }
-       }
-
-       /**
-        * Set a message at the top of the Change Password form
-        * @since 1.23
-        * @param Message $msg Message to parse and add to the form header
-        */
-       public function setChangeMessage( Message $msg ) {
-               $this->mPreTextMessage = $msg;
-       }
-
-       /**
-        * Set a message at the top of the Change Password form
-        * @since 1.23
-        * @param string $msg Message label for old/temp password field
-        */
-       public function setOldPasswordMessage( $msg ) {
-               $this->mOldPassMsg = $msg;
-       }
-
-       protected function getFormFields() {
-               $user = $this->getUser();
-               $request = $this->getRequest();
-
-               $oldpassMsg = $this->mOldPassMsg;
-               if ( $oldpassMsg === null ) {
-                       $oldpassMsg = $user->isLoggedIn() ? 'oldpassword' : 'resetpass-temp-password';
-               }
-
-               $fields = [
-                       'Name' => [
-                               'type' => 'info',
-                               'label-message' => 'username',
-                               'default' => $request->getVal( 'wpName', $user->getName() ),
-                       ],
-                       'Password' => [
-                               'type' => 'password',
-                               'label-message' => $oldpassMsg,
-                       ],
-                       'NewPassword' => [
-                               'type' => 'password',
-                               'label-message' => 'newpassword',
-                       ],
-                       'Retype' => [
-                               'type' => 'password',
-                               'label-message' => 'retypenew',
-                       ],
-               ];
-
-               if ( !$this->getUser()->isLoggedIn() ) {
-                       $fields['LoginOnChangeToken'] = [
-                               'type' => 'hidden',
-                               'label' => 'Change Password Token',
-                               'default' => LoginForm::getLoginToken()->toString(),
-                       ];
-               }
-
-               $extraFields = [];
-               Hooks::run( 'ChangePasswordForm', [ &$extraFields ] );
-               foreach ( $extraFields as $extra ) {
-                       list( $name, $label, $type, $default ) = $extra;
-                       $fields[$name] = [
-                               'type' => $type,
-                               'name' => $name,
-                               'label-message' => $label,
-                               'default' => $default,
-                       ];
-               }
-
-               if ( !$user->isLoggedIn() ) {
-                       $fields['Remember'] = [
-                               'type' => 'check',
-                               'label' => $this->msg( 'remembermypassword' )
-                                               ->numParams(
-                                                       ceil( $this->getConfig()->get( 'CookieExpiration' ) / ( 3600 * 24 ) )
-                                               )->text(),
-                               'default' => $request->getVal( 'wpRemember' ),
-                       ];
-               }
-
-               return $fields;
-       }
-
-       protected function alterForm( HTMLForm $form ) {
-               $form->setId( 'mw-resetpass-form' );
-               $form->setTableId( 'mw-resetpass-table' );
-               $form->setWrapperLegendMsg( 'resetpass_header' );
-               $form->setSubmitTextMsg(
-                       $this->getUser()->isLoggedIn()
-                               ? 'resetpass-submit-loggedin'
-                               : 'resetpass_submit'
-               );
-               $form->addButton( [
-                       'name' => 'wpCancel',
-                       'value' => $this->msg( 'resetpass-submit-cancel' )->text()
-               ] );
-               $form->setHeaderText( $this->msg( 'resetpass_text' )->parseAsBlock() );
-               if ( $this->mPreTextMessage instanceof Message ) {
-                       $form->addPreText( $this->mPreTextMessage->parseAsBlock() );
-               }
-               $form->addHiddenFields(
-                       $this->getRequest()->getValues( 'wpName', 'wpDomain', 'returnto', 'returntoquery' ) );
-       }
-
-       public function onSubmit( array $data ) {
-               global $wgAuth;
-
-               $request = $this->getRequest();
-
-               if ( $request->getCheck( 'wpLoginToken' ) ) {
-                       // This comes from Special:Userlogin when logging in with a temporary password
-                       return false;
-               }
-
-               if ( !$this->getUser()->isLoggedIn()
-                       && !LoginForm::getLoginToken()->match( $request->getVal( 'wpLoginOnChangeToken' ) )
-               ) {
-                       // Potential CSRF (bug 62497)
-                       return false;
-               }
-
-               if ( $request->getCheck( 'wpCancel' ) ) {
-                       $returnto = $request->getVal( 'returnto' );
-                       $titleObj = $returnto !== null ? Title::newFromText( $returnto ) : null;
-                       if ( !$titleObj instanceof Title ) {
-                               $titleObj = Title::newMainPage();
-                       }
-                       $query = $request->getVal( 'returntoquery' );
-                       $this->getOutput()->redirect( $titleObj->getFullURL( $query ) );
-
-                       return true;
-               }
-
-               $this->mUserName = $request->getVal( 'wpName', $this->getUser()->getName() );
-               $this->mDomain = $wgAuth->getDomain();
-
-               if ( !$wgAuth->allowPasswordChange() ) {
-                       throw new ErrorPageError( 'changepassword', 'resetpass_forbidden' );
-               }
-
-               $status = $this->attemptReset( $data['Password'], $data['NewPassword'], $data['Retype'] );
-
-               return $status;
-       }
-
-       public function onSuccess() {
-               if ( $this->getUser()->isLoggedIn() ) {
-                       $this->getOutput()->wrapWikiMsg(
-                               "<div class=\"successbox\">\n$1\n</div>",
-                               'changepassword-success'
-                       );
-                       $this->getOutput()->returnToMain();
-               } else {
-                       $request = $this->getRequest();
-                       LoginForm::clearLoginToken();
-                       $token = LoginForm::getLoginToken()->toString();
-                       $data = [
-                               'action' => 'submitlogin',
-                               'wpName' => $this->mUserName,
-                               'wpDomain' => $this->mDomain,
-                               'wpLoginToken' => $token,
-                               'wpPassword' => $request->getVal( 'wpNewPassword' ),
-                       ] + $request->getValues( 'wpRemember', 'returnto', 'returntoquery' );
-                       $login = new LoginForm( new DerivativeRequest( $request, $data, true ) );
-                       $login->setContext( $this->getContext() );
-                       $login->execute( null );
-               }
-       }
-
-       /**
-        * Checks the new password if it meets the requirements for passwords and set
-        * it as a current password, otherwise set the passed Status object to fatal
-        * and doesn't change anything
-        *
-        * @param string $oldpass The current (temporary) password.
-        * @param string $newpass The password to set.
-        * @param string $retype The string of the retype password field to check with newpass
-        * @return Status
-        */
-       protected function attemptReset( $oldpass, $newpass, $retype ) {
-               $isSelf = ( $this->mUserName === $this->getUser()->getName() );
-               if ( $isSelf ) {
-                       $user = $this->getUser();
-               } else {
-                       $user = User::newFromName( $this->mUserName );
-               }
-
-               if ( !$user || $user->isAnon() ) {
-                       return Status::newFatal( $this->msg( 'nosuchusershort', $this->mUserName ) );
-               }
-
-               if ( $newpass !== $retype ) {
-                       Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'badretype' ] );
-                       return Status::newFatal( $this->msg( 'badretype' ) );
-               }
-
-               $throttleInfo = LoginForm::incrementLoginThrottle( $this->mUserName );
-               if ( $throttleInfo ) {
-                       return Status::newFatal( $this->msg( 'changepassword-throttled' )
-                               ->durationParams( $throttleInfo['wait'] )
-                       );
-               }
-
-               // @todo Make these separate messages, since the message is written for both cases
-               if ( !$user->checkTemporaryPassword( $oldpass ) && !$user->checkPassword( $oldpass ) ) {
-                       Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'wrongpassword' ] );
-                       return Status::newFatal( $this->msg( 'resetpass-wrong-oldpass' ) );
-               }
-
-               // User is resetting their password to their old password
-               if ( $oldpass === $newpass ) {
-                       return Status::newFatal( $this->msg( 'resetpass-recycled' ) );
-               }
-
-               // Do AbortChangePassword after checking mOldpass, so we don't leak information
-               // by possibly aborting a new password before verifying the old password.
-               $abortMsg = 'resetpass-abort-generic';
-               if ( !Hooks::run( 'AbortChangePassword', [ $user, $oldpass, $newpass, &$abortMsg ] ) ) {
-                       Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'abortreset' ] );
-                       return Status::newFatal( $this->msg( $abortMsg ) );
-               }
-
-               // Please reset throttle for successful logins, thanks!
-               LoginForm::clearLoginThrottle( $this->mUserName );
-
-               try {
-                       $user->setPassword( $newpass );
-                       Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'success' ] );
-               } catch ( PasswordError $e ) {
-                       Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'error' ] );
-                       return Status::newFatal( new RawMessage( $e->getMessage() ) );
-               }
-
-               if ( $isSelf ) {
-                       // This is needed to keep the user connected since
-                       // changing the password also modifies the user's token.
-                       $remember = $this->getRequest()->getCookie( 'Token' ) !== null;
-                       $user->setCookies( null, null, $remember );
-               }
-               $user->saveSettings();
-               $this->resetPasswordExpiration( $user );
-               return Status::newGood();
-       }
-
-       public function requiresUnblock() {
-               return false;
-       }
-
-       protected function getGroupName() {
-               return 'users';
-       }
-
-       /**
-        * For resetting user password expiration, until AuthManager comes along
-        * @param User $user
-        */
-       private function resetPasswordExpiration( User $user ) {
-               global $wgPasswordExpirationDays;
-               $newExpire = null;
-               if ( $wgPasswordExpirationDays ) {
-                       $newExpire = wfTimestamp(
-                               TS_MW,
-                               time() + ( $wgPasswordExpirationDays * 24 * 3600 )
-                       );
-               }
-               // Give extensions a chance to force an expiration
-               Hooks::run( 'ResetPasswordExpiration', [ $this, &$newExpire ] );
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->update(
-                       'user',
-                       [ 'user_password_expires' => $dbw->timestampOrNull( $newExpire ) ],
-                       [ 'user_id' => $user->getId() ],
-                       __METHOD__
-               );
-       }
-
-       protected function getDisplayFormat() {
-               return 'ooui';
-       }
-}
diff --git a/includes/specials/pre-authmanager/SpecialCreateAccount.php b/includes/specials/pre-authmanager/SpecialCreateAccount.php
deleted file mode 100644 (file)
index 14f70b5..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-/**
- * Redirect page: Special:CreateAccount --> Special:UserLogin/signup.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-/**
- * Redirect page: Special:CreateAccount --> Special:UserLogin/signup.
- * @todo FIXME: This (and the rest of the login frontend) needs to die a horrible painful death
- *
- * @ingroup SpecialPage
- */
-class SpecialCreateAccountPreAuthManager extends SpecialRedirectToSpecial {
-       function __construct() {
-               parent::__construct(
-                       'CreateAccount',
-                       'Userlogin',
-                       'signup',
-                       [ 'returnto', 'returntoquery', 'uselang' ]
-               );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       // No reason to hide this link on Special:Specialpages
-       public function isListed() {
-               return true;
-       }
-
-       public function isRestricted() {
-               return !User::groupHasPermission( '*', 'createaccount' );
-       }
-
-       public function userCanExecute( User $user ) {
-               return $user->isAllowed( 'createaccount' );
-       }
-
-       protected function getGroupName() {
-               return 'login';
-       }
-}
diff --git a/includes/specials/pre-authmanager/SpecialPasswordReset.php b/includes/specials/pre-authmanager/SpecialPasswordReset.php
deleted file mode 100644 (file)
index e8719a7..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-<?php
-/**
- * Implements Special:PasswordReset
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-/**
- * Special page for requesting a password reset email
- *
- * @ingroup SpecialPage
- */
-class SpecialPasswordResetPreAuthManager extends FormSpecialPage {
-       /**
-        * @var Message
-        */
-       private $email;
-
-       /**
-        * @var User
-        */
-       private $firstUser;
-
-       /**
-        * @var Status
-        */
-       private $result;
-
-       /**
-        * @var string $method Identifies which password reset field was specified by the user.
-        */
-       private $method;
-
-       public function __construct() {
-               parent::__construct( 'PasswordReset', 'editmyprivateinfo' );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       public function userCanExecute( User $user ) {
-               return $this->canChangePassword( $user ) === true && parent::userCanExecute( $user );
-       }
-
-       public function checkExecutePermissions( User $user ) {
-               $error = $this->canChangePassword( $user );
-               if ( is_string( $error ) ) {
-                       throw new ErrorPageError( 'internalerror', $error );
-               } elseif ( !$error ) {
-                       throw new ErrorPageError( 'internalerror', 'resetpass_forbidden' );
-               }
-
-               parent::checkExecutePermissions( $user );
-       }
-
-       protected function getFormFields() {
-               global $wgAuth;
-               $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
-               $a = [];
-               if ( isset( $resetRoutes['username'] ) && $resetRoutes['username'] ) {
-                       $a['Username'] = [
-                               'type' => 'text',
-                               'label-message' => 'passwordreset-username',
-                       ];
-
-                       if ( $this->getUser()->isLoggedIn() ) {
-                               $a['Username']['default'] = $this->getUser()->getName();
-                       }
-               }
-
-               if ( isset( $resetRoutes['email'] ) && $resetRoutes['email'] ) {
-                       $a['Email'] = [
-                               'type' => 'email',
-                               'label-message' => 'passwordreset-email',
-                       ];
-               }
-
-               if ( isset( $resetRoutes['domain'] ) && $resetRoutes['domain'] ) {
-                       $domains = $wgAuth->domainList();
-                       $a['Domain'] = [
-                               'type' => 'select',
-                               'options' => $domains,
-                               'label-message' => 'passwordreset-domain',
-                       ];
-               }
-
-               if ( $this->getUser()->isAllowed( 'passwordreset' ) ) {
-                       $a['Capture'] = [
-                               'type' => 'check',
-                               'label-message' => 'passwordreset-capture',
-                               'help-message' => 'passwordreset-capture-help',
-                       ];
-               }
-
-               return $a;
-       }
-
-       protected function getDisplayFormat() {
-               return 'ooui';
-       }
-
-       public function alterForm( HTMLForm $form ) {
-               $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
-
-               $form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
-
-               $i = 0;
-               if ( isset( $resetRoutes['username'] ) && $resetRoutes['username'] ) {
-                       $i++;
-               }
-               if ( isset( $resetRoutes['email'] ) && $resetRoutes['email'] ) {
-                       $i++;
-               }
-               if ( isset( $resetRoutes['domain'] ) && $resetRoutes['domain'] ) {
-                       $i++;
-               }
-
-               $message = ( $i > 1 ) ? 'passwordreset-text-many' : 'passwordreset-text-one';
-
-               $form->setHeaderText( $this->msg( $message, $i )->parseAsBlock() );
-               $form->setSubmitTextMsg( 'mailmypassword' );
-       }
-
-       /**
-        * Process the form.  At this point we know that the user passes all the criteria in
-        * userCanExecute(), and if the data array contains 'Username', etc, then Username
-        * resets are allowed.
-        * @param array $data
-        * @throws MWException
-        * @throws ThrottledError|PermissionsError
-        * @return bool|array
-        */
-       public function onSubmit( array $data ) {
-               global $wgAuth, $wgMinimalPasswordLength;
-
-               if ( isset( $data['Domain'] ) ) {
-                       if ( $wgAuth->validDomain( $data['Domain'] ) ) {
-                               $wgAuth->setDomain( $data['Domain'] );
-                       } else {
-                               $wgAuth->setDomain( 'invaliddomain' );
-                       }
-               }
-
-               if ( isset( $data['Capture'] ) && !$this->getUser()->isAllowed( 'passwordreset' ) ) {
-                       // The user knows they don't have the passwordreset permission,
-                       // but they tried to spoof the form. That's naughty
-                       throw new PermissionsError( 'passwordreset' );
-               }
-
-               /**
-                * @var $firstUser User
-                * @var $users User[]
-                */
-
-               if ( isset( $data['Username'] ) && $data['Username'] !== '' ) {
-                       $method = 'username';
-                       $users = [ User::newFromName( $data['Username'] ) ];
-               } elseif ( isset( $data['Email'] )
-                       && $data['Email'] !== ''
-                       && Sanitizer::validateEmail( $data['Email'] )
-               ) {
-                       $method = 'email';
-                       $res = wfGetDB( DB_SLAVE )->select(
-                               'user',
-                               User::selectFields(),
-                               [ 'user_email' => $data['Email'] ],
-                               __METHOD__
-                       );
-
-                       if ( $res ) {
-                               $users = [];
-
-                               foreach ( $res as $row ) {
-                                       $users[] = User::newFromRow( $row );
-                               }
-                       } else {
-                               // Some sort of database error, probably unreachable
-                               throw new MWException( 'Unknown database error in ' . __METHOD__ );
-                       }
-               } else {
-                       // The user didn't supply any data
-                       return false;
-               }
-
-               // Check for hooks (captcha etc), and allow them to modify the users list
-               $error = [];
-               if ( !Hooks::run( 'SpecialPasswordResetOnSubmit', [ &$users, $data, &$error ] ) ) {
-                       return [ $error ];
-               }
-
-               $this->method = $method;
-
-               if ( count( $users ) == 0 ) {
-                       if ( $method == 'email' ) {
-                               // Don't reveal whether or not an email address is in use
-                               return true;
-                       } else {
-                               return [ 'noname' ];
-                       }
-               }
-
-               $firstUser = $users[0];
-
-               if ( !$firstUser instanceof User || !$firstUser->getId() ) {
-                       // Don't parse username as wikitext (bug 65501)
-                       return [ [ 'nosuchuser', wfEscapeWikiText( $data['Username'] ) ] ];
-               }
-
-               // Check against the rate limiter
-               if ( $this->getUser()->pingLimiter( 'mailpassword' ) ) {
-                       throw new ThrottledError;
-               }
-
-               // Check against password throttle
-               foreach ( $users as $user ) {
-                       if ( $user->isPasswordReminderThrottled() ) {
-
-                               # Round the time in hours to 3 d.p., in case someone is specifying
-                               # minutes or seconds.
-                               return [ [
-                                       'throttled-mailpassword',
-                                       round( $this->getConfig()->get( 'PasswordReminderResendTime' ), 3 )
-                               ] ];
-                       }
-               }
-
-               // All the users will have the same email address
-               if ( $firstUser->getEmail() == '' ) {
-                       // This won't be reachable from the email route, so safe to expose the username
-                       return [ [ 'noemail', wfEscapeWikiText( $firstUser->getName() ) ] ];
-               }
-
-               // We need to have a valid IP address for the hook, but per bug 18347, we should
-               // send the user's name if they're logged in.
-               $ip = $this->getRequest()->getIP();
-               if ( !$ip ) {
-                       return [ 'badipaddress' ];
-               }
-               $caller = $this->getUser();
-               Hooks::run( 'User::mailPasswordInternal', [ &$caller, &$ip, &$firstUser ] );
-               $username = $caller->getName();
-               $msg = IP::isValid( $username )
-                       ? 'passwordreset-emailtext-ip'
-                       : 'passwordreset-emailtext-user';
-
-               // Send in the user's language; which should hopefully be the same
-               $userLanguage = $firstUser->getOption( 'language' );
-
-               $passwords = [];
-               foreach ( $users as $user ) {
-                       $password = PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength );
-                       $user->setNewpassword( $password );
-                       $user->saveSettings();
-                       $passwords[] = $this->msg( 'passwordreset-emailelement', $user->getName(), $password )
-                               ->inLanguage( $userLanguage )->text(); // We'll escape the whole thing later
-               }
-               $passwordBlock = implode( "\n\n", $passwords );
-
-               $this->email = $this->msg( $msg )->inLanguage( $userLanguage );
-               $this->email->params(
-                       $username,
-                       $passwordBlock,
-                       count( $passwords ),
-                       '<' . Title::newMainPage()->getCanonicalURL() . '>',
-                       round( $this->getConfig()->get( 'NewPasswordExpiry' ) / 86400 )
-               );
-
-               $title = $this->msg( 'passwordreset-emailtitle' )->inLanguage( $userLanguage );
-
-               $this->result = $firstUser->sendMail( $title->text(), $this->email->text() );
-
-               if ( isset( $data['Capture'] ) && $data['Capture'] ) {
-                       // Save the user, will be used if an error occurs when sending the email
-                       $this->firstUser = $firstUser;
-               } else {
-                       // Blank the email if the user is not supposed to see it
-                       $this->email = null;
-               }
-
-               if ( $this->result->isGood() ) {
-                       return true;
-               } elseif ( isset( $data['Capture'] ) && $data['Capture'] ) {
-                       // The email didn't send, but maybe they knew that and that's why they captured it
-                       return true;
-               } else {
-                       // @todo FIXME: The email wasn't sent, but we have already set
-                       // the password throttle timestamp, so they won't be able to try
-                       // again until it expires...  :(
-                       return [ [ 'mailerror', $this->result->getMessage() ] ];
-               }
-       }
-
-       public function onSuccess() {
-               if ( $this->getUser()->isAllowed( 'passwordreset' ) && $this->email != null ) {
-                       // @todo Logging
-
-                       if ( $this->result->isGood() ) {
-                               $this->getOutput()->addWikiMsg( 'passwordreset-emailsent-capture' );
-                       } else {
-                               $this->getOutput()->addWikiMsg( 'passwordreset-emailerror-capture',
-                                       $this->result->getMessage(), $this->firstUser->getName() );
-                       }
-
-                       $this->getOutput()->addHTML( Html::rawElement( 'pre', [], $this->email->escaped() ) );
-               }
-
-               if ( $this->method === 'email' ) {
-                       $this->getOutput()->addWikiMsg( 'passwordreset-emailsentemail' );
-               } else {
-                       $this->getOutput()->addWikiMsg( 'passwordreset-emailsentusername' );
-               }
-
-               $this->getOutput()->returnToMain();
-       }
-
-       protected function canChangePassword( User $user ) {
-               global $wgAuth;
-               $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
-
-               // Maybe password resets are disabled, or there are no allowable routes
-               if ( !is_array( $resetRoutes ) ||
-                       !in_array( true, array_values( $resetRoutes ) )
-               ) {
-                       return 'passwordreset-disabled';
-               }
-
-               // Maybe the external auth plugin won't allow local password changes
-               if ( !$wgAuth->allowPasswordChange() ) {
-                       return 'resetpass_forbidden';
-               }
-
-               // Maybe email features have been disabled
-               if ( !$this->getConfig()->get( 'EnableEmail' ) ) {
-                       return 'passwordreset-emaildisabled';
-               }
-
-               // Maybe the user is blocked (check this here rather than relying on the parent
-               // method as we have a more specific error message to use here
-               if ( $user->isBlocked() ) {
-                       return 'blocked-mailpassword';
-               }
-
-               return true;
-       }
-
-       /**
-        * Hide the password reset page if resets are disabled.
-        * @return bool
-        */
-       function isListed() {
-               if ( $this->canChangePassword( $this->getUser() ) === true ) {
-                       return parent::isListed();
-               }
-
-               return false;
-       }
-
-       protected function getGroupName() {
-               return 'users';
-       }
-}
diff --git a/includes/specials/pre-authmanager/SpecialUserlogin.php b/includes/specials/pre-authmanager/SpecialUserlogin.php
deleted file mode 100644 (file)
index 09132f2..0000000
+++ /dev/null
@@ -1,1847 +0,0 @@
-<?php
-/**
- * Implements Special:UserLogin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-use MediaWiki\Logger\LoggerFactory;
-use Psr\Log\LogLevel;
-use MediaWiki\Session\SessionManager;
-
-/**
- * Implements Special:UserLogin
- *
- * @ingroup SpecialPage
- */
-class LoginFormPreAuthManager extends SpecialPage {
-       const SUCCESS = 0;
-       const NO_NAME = 1;
-       const ILLEGAL = 2;
-       const WRONG_PLUGIN_PASS = 3;
-       const NOT_EXISTS = 4;
-       const WRONG_PASS = 5;
-       const EMPTY_PASS = 6;
-       const RESET_PASS = 7;
-       const ABORTED = 8;
-       const CREATE_BLOCKED = 9;
-       const THROTTLED = 10;
-       const USER_BLOCKED = 11;
-       const NEED_TOKEN = 12;
-       const WRONG_TOKEN = 13;
-       const USER_MIGRATED = 14;
-
-       public static $statusCodes = [
-               self::SUCCESS => 'success',
-               self::NO_NAME => 'no_name',
-               self::ILLEGAL => 'illegal',
-               self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
-               self::NOT_EXISTS => 'not_exists',
-               self::WRONG_PASS => 'wrong_pass',
-               self::EMPTY_PASS => 'empty_pass',
-               self::RESET_PASS => 'reset_pass',
-               self::ABORTED => 'aborted',
-               self::CREATE_BLOCKED => 'create_blocked',
-               self::THROTTLED => 'throttled',
-               self::USER_BLOCKED => 'user_blocked',
-               self::NEED_TOKEN => 'need_token',
-               self::WRONG_TOKEN => 'wrong_token',
-               self::USER_MIGRATED => 'user_migrated',
-       ];
-
-       /**
-        * Valid error and warning messages
-        *
-        * Special:Userlogin can show an error or warning message on the form when
-        * coming from another page. This is done via the ?error= or ?warning= GET
-        * parameters.
-        *
-        * This array is the list of valid message keys. All other values will be
-        * ignored.
-        *
-        * @since 1.24
-        * @var string[]
-        */
-       public static $validErrorMessages = [
-               'exception-nologin-text',
-               'watchlistanontext',
-               'changeemail-no-info',
-               'resetpass-no-info',
-               'confirmemail_needlogin',
-               'prefsnologintext2',
-       ];
-
-       public $mAbortLoginErrorMsg = null;
-       /**
-        * @var int How many seconds user is throttled for
-        * @since 1.27
-        */
-       public $mThrottleWait = '?';
-
-       protected $mUsername;
-       protected $mPassword;
-       protected $mRetype;
-       protected $mReturnTo;
-       protected $mCookieCheck;
-       protected $mPosted;
-       protected $mAction;
-       protected $mCreateaccount;
-       protected $mCreateaccountMail;
-       protected $mLoginattempt;
-       protected $mRemember;
-       protected $mEmail;
-       protected $mDomain;
-       protected $mLanguage;
-       protected $mSkipCookieCheck;
-       protected $mReturnToQuery;
-       protected $mToken;
-       protected $mStickHTTPS;
-       protected $mType;
-       protected $mReason;
-       protected $mRealName;
-       protected $mEntryError = '';
-       protected $mEntryErrorType = 'error';
-
-       private $mTempPasswordUsed;
-       private $mLoaded = false;
-       private $mSecureLoginUrl;
-
-       /** @var WebRequest */
-       private $mOverrideRequest = null;
-
-       /** @var WebRequest Effective request; set at the beginning of load */
-       private $mRequest = null;
-
-       /**
-        * @param WebRequest $request
-        */
-       public function __construct( $request = null ) {
-               global $wgUseMediaWikiUIEverywhere;
-               parent::__construct( 'Userlogin' );
-
-               $this->mOverrideRequest = $request;
-               // Override UseMediaWikiEverywhere to true, to force login and create form to use mw ui
-               $wgUseMediaWikiUIEverywhere = true;
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       /**
-        * Returns an array of all valid error messages.
-        *
-        * @return array
-        */
-       public static function getValidErrorMessages() {
-               static $messages = null;
-               if ( !$messages ) {
-                       $messages = self::$validErrorMessages;
-                       Hooks::run( 'LoginFormValidErrorMessages', [ &$messages ] );
-               }
-
-               return $messages;
-       }
-
-       /**
-        * Loader
-        */
-       function load() {
-               global $wgAuth, $wgHiddenPrefs, $wgEnableEmail;
-
-               if ( $this->mLoaded ) {
-                       return;
-               }
-               $this->mLoaded = true;
-
-               if ( $this->mOverrideRequest === null ) {
-                       $request = $this->getRequest();
-               } else {
-                       $request = $this->mOverrideRequest;
-               }
-               $this->mRequest = $request;
-
-               $this->mType = $request->getText( 'type' );
-               $this->mUsername = $request->getText( 'wpName' );
-               $this->mPassword = $request->getText( 'wpPassword' );
-               $this->mRetype = $request->getText( 'wpRetype' );
-               $this->mDomain = $request->getText( 'wpDomain' );
-               $this->mReason = $request->getText( 'wpReason' );
-               $this->mCookieCheck = $request->getVal( 'wpCookieCheck' );
-               $this->mPosted = $request->wasPosted();
-               $this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' )
-                       && $wgEnableEmail;
-               $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' ) && !$this->mCreateaccountMail;
-               $this->mLoginattempt = $request->getCheck( 'wpLoginattempt' );
-               $this->mAction = $request->getVal( 'action' );
-               $this->mRemember = $request->getCheck( 'wpRemember' );
-               $this->mFromHTTP = $request->getBool( 'fromhttp', false )
-                       || $request->getBool( 'wpFromhttp', false );
-               $this->mStickHTTPS = ( !$this->mFromHTTP && $request->getProtocol() === 'https' )
-                       || $request->getBool( 'wpForceHttps', false );
-               $this->mLanguage = $request->getText( 'uselang' );
-               $this->mSkipCookieCheck = $request->getCheck( 'wpSkipCookieCheck' );
-               $this->mToken = $this->mType == 'signup'
-                       ? $request->getVal( 'wpCreateaccountToken' )
-                       : $request->getVal( 'wpLoginToken' );
-               $this->mReturnTo = $request->getVal( 'returnto', '' );
-               $this->mReturnToQuery = $request->getVal( 'returntoquery', '' );
-
-               // Show an error or warning passed on from a previous page
-               $entryError = $this->msg( $request->getVal( 'error', '' ) );
-               $entryWarning = $this->msg( $request->getVal( 'warning', '' ) );
-               // bc: provide login link as a parameter for messages where the translation
-               // was not updated
-               $loginreqlink = Linker::linkKnown(
-                       $this->getPageTitle(),
-                       $this->msg( 'loginreqlink' )->escaped(),
-                       [],
-                       [
-                               'returnto' => $this->mReturnTo,
-                               'returntoquery' => $this->mReturnToQuery,
-                               'uselang' => $this->mLanguage,
-                               'fromhttp' => $this->mFromHTTP ? '1' : '0',
-                       ]
-               );
-
-               // Only show valid error or warning messages.
-               if ( $entryError->exists()
-                       && in_array( $entryError->getKey(), self::getValidErrorMessages() )
-               ) {
-                       $this->mEntryErrorType = 'error';
-                       $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
-
-               } elseif ( $entryWarning->exists()
-                       && in_array( $entryWarning->getKey(), self::getValidErrorMessages() )
-               ) {
-                       $this->mEntryErrorType = 'warning';
-                       $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
-               }
-
-               if ( $wgEnableEmail ) {
-                       $this->mEmail = $request->getText( 'wpEmail' );
-               } else {
-                       $this->mEmail = '';
-               }
-               if ( !in_array( 'realname', $wgHiddenPrefs ) ) {
-                       $this->mRealName = $request->getText( 'wpRealName' );
-               } else {
-                       $this->mRealName = '';
-               }
-
-               if ( !$wgAuth->validDomain( $this->mDomain ) ) {
-                       $this->mDomain = $wgAuth->getDomain();
-               }
-               $wgAuth->setDomain( $this->mDomain );
-
-               # 1. When switching accounts, it sucks to get automatically logged out
-               # 2. Do not return to PasswordReset after a successful password change
-               #    but goto Wiki start page (Main_Page) instead ( bug 33997 )
-               $returnToTitle = Title::newFromText( $this->mReturnTo );
-               if ( is_object( $returnToTitle )
-                       && ( $returnToTitle->isSpecial( 'Userlogout' )
-                               || $returnToTitle->isSpecial( 'PasswordReset' ) )
-               ) {
-                       $this->mReturnTo = '';
-                       $this->mReturnToQuery = '';
-               }
-       }
-
-       function getDescription() {
-               if ( $this->mType === 'signup' ) {
-                       return $this->msg( 'createaccount' )->text();
-               } else {
-                       return $this->msg( 'login' )->text();
-               }
-       }
-
-       /**
-        * @param string|null $subPage
-        */
-       public function execute( $subPage ) {
-               // Make sure session is persisted
-               $session = SessionManager::getGlobalSession();
-               $session->persist();
-
-               $this->load();
-
-               // Check for [[Special:Userlogin/signup]]. This affects form display and
-               // page title.
-               if ( $subPage == 'signup' ) {
-                       $this->mType = 'signup';
-               }
-               $this->setHeaders();
-
-               // Make sure it's possible to log in
-               if ( $this->mType !== 'signup' && !$session->canSetUser() ) {
-                       throw new ErrorPageError(
-                               'cannotloginnow-title',
-                               'cannotloginnow-text',
-                               [
-                                       $session->getProvider()->describe( RequestContext::getMain()->getLanguage() )
-                               ]
-                       );
-               }
-
-               /**
-                * In the case where the user is already logged in, and was redirected to
-                * the login form from a page that requires login, do not show the login
-                * page. The use case scenario for this is when a user opens a large number
-                * of tabs, is redirected to the login page on all of them, and then logs
-                * in on one, expecting all the others to work properly.
-                *
-                * However, do show the form if it was visited intentionally (no 'returnto'
-                * is present). People who often switch between several accounts have grown
-                * accustomed to this behavior.
-                */
-               if (
-                       $this->mType !== 'signup' &&
-                       !$this->mPosted &&
-                       $this->getUser()->isLoggedIn() &&
-                       ( $this->mReturnTo !== '' || $this->mReturnToQuery !== '' )
-               ) {
-                       $this->successfulLogin();
-               }
-
-               // If logging in and not on HTTPS, either redirect to it or offer a link.
-               global $wgSecureLogin;
-               if ( $this->mRequest->getProtocol() !== 'https' ) {
-                       $title = $this->getFullTitle();
-                       $query = [
-                               'returnto' => $this->mReturnTo !== '' ? $this->mReturnTo : null,
-                               'returntoquery' => $this->mReturnToQuery !== '' ?
-                                       $this->mReturnToQuery : null,
-                               'title' => null,
-                               ( $this->mEntryErrorType === 'error' ? 'error' : 'warning' ) => $this->mEntryError,
-                       ] + $this->mRequest->getQueryValues();
-                       $url = $title->getFullURL( $query, false, PROTO_HTTPS );
-                       if ( $wgSecureLogin
-                               && wfCanIPUseHTTPS( $this->getRequest()->getIP() )
-                               && !$this->mFromHTTP ) // Avoid infinite redirect
-                       {
-                               $url = wfAppendQuery( $url, 'fromhttp=1' );
-                               $this->getOutput()->redirect( $url );
-                               // Since we only do this redir to change proto, always vary
-                               $this->getOutput()->addVaryHeader( 'X-Forwarded-Proto' );
-
-                               return;
-                       } else {
-                               // A wiki without HTTPS login support should set $wgServer to
-                               // http://somehost, in which case the secure URL generated
-                               // above won't actually start with https://
-                               if ( substr( $url, 0, 8 ) === 'https://' ) {
-                                       $this->mSecureLoginUrl = $url;
-                               }
-                       }
-               }
-
-               if ( !is_null( $this->mCookieCheck ) ) {
-                       $this->onCookieRedirectCheck( $this->mCookieCheck );
-
-                       return;
-               } elseif ( $this->mPosted ) {
-                       if ( $this->mCreateaccount ) {
-                               $this->addNewAccount();
-
-                               return;
-                       } elseif ( $this->mCreateaccountMail ) {
-                               $this->addNewAccountMailPassword();
-
-                               return;
-                       } elseif ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
-                               $this->processLogin();
-
-                               return;
-                       }
-               }
-               $this->mainLoginForm( $this->mEntryError, $this->mEntryErrorType );
-       }
-
-       /**
-        * @private
-        */
-       function addNewAccountMailPassword() {
-               if ( $this->mEmail == '' ) {
-                       $this->mainLoginForm( $this->msg( 'noemailcreate' )->escaped() );
-
-                       return;
-               }
-
-               $status = $this->addNewAccountInternal();
-               LoggerFactory::getInstance( 'authmanager' )->info(
-                       'Account creation attempt with mailed password',
-                       [ 'event' => 'accountcreation', 'status' => $status ]
-               );
-               if ( !$status->isGood() ) {
-                       $error = $status->getMessage();
-                       $this->mainLoginForm( $error->toString() );
-
-                       return;
-               }
-
-               /** @var User $u */
-               $u = $status->getValue();
-
-               // Wipe the initial password and mail a temporary one
-               $u->setPassword( null );
-               $u->saveSettings();
-               $result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
-
-               Hooks::run( 'AddNewAccount', [ $u, true ] );
-               $u->addNewUserLogEntry( 'byemail', $this->mReason );
-
-               $out = $this->getOutput();
-               $out->setPageTitle( $this->msg( 'accmailtitle' ) );
-
-               if ( !$result->isGood() ) {
-                       $this->mainLoginForm( $this->msg( 'mailerror', $result->getWikiText() )->text() );
-               } else {
-                       $out->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() );
-                       $this->executeReturnTo( 'success' );
-               }
-       }
-
-       /**
-        * @private
-        * @return bool
-        */
-       function addNewAccount() {
-               global $wgContLang, $wgUser, $wgEmailAuthentication, $wgLoginLanguageSelector;
-
-               # Create the account and abort if there's a problem doing so
-               $status = $this->addNewAccountInternal();
-               LoggerFactory::getInstance( 'authmanager' )->info( 'Account creation attempt', [
-                       'event' => 'accountcreation',
-                       'status' => $status,
-               ] );
-
-               if ( !$status->isGood() ) {
-                       $error = $status->getMessage();
-                       $this->mainLoginForm( $error->toString() );
-
-                       return false;
-               }
-
-               $u = $status->getValue();
-
-               # Only save preferences if the user is not creating an account for someone else.
-               if ( $this->getUser()->isAnon() ) {
-                       # If we showed up language selection links, and one was in use, be
-                       # smart (and sensible) and save that language as the user's preference
-                       if ( $wgLoginLanguageSelector && $this->mLanguage ) {
-                               $u->setOption( 'language', $this->mLanguage );
-                       } else {
-
-                               # Otherwise the user's language preference defaults to $wgContLang,
-                               # but it may be better to set it to their preferred $wgContLang variant,
-                               # based on browser preferences or URL parameters.
-                               $u->setOption( 'language', $wgContLang->getPreferredVariant() );
-                       }
-                       if ( $wgContLang->hasVariants() ) {
-                               $u->setOption( 'variant', $wgContLang->getPreferredVariant() );
-                       }
-               }
-
-               $out = $this->getOutput();
-
-               # Send out an email authentication message if needed
-               if ( $wgEmailAuthentication && Sanitizer::validateEmail( $u->getEmail() ) ) {
-                       $status = $u->sendConfirmationMail();
-                       if ( $status->isGood() ) {
-                               $out->addWikiMsg( 'confirmemail_oncreate' );
-                       } else {
-                               $out->addWikiText( $status->getWikiText( 'confirmemail_sendfailed' ) );
-                       }
-               }
-
-               # Save settings (including confirmation token)
-               $u->saveSettings();
-
-               # If not logged in, assume the new account as the current one and set
-               # session cookies then show a "welcome" message or a "need cookies"
-               # message as needed
-               if ( $this->getUser()->isAnon() ) {
-                       $u->setCookies();
-                       $wgUser = $u;
-                       // This should set it for OutputPage and the Skin
-                       // which is needed or the personal links will be
-                       // wrong.
-                       $this->getContext()->setUser( $u );
-                       Hooks::run( 'AddNewAccount', [ $u, false ] );
-                       $u->addNewUserLogEntry( 'create' );
-                       if ( $this->hasSessionCookie() ) {
-                               $this->successfulCreation();
-                       } else {
-                               $this->cookieRedirectCheck( 'new' );
-                       }
-               } else {
-                       # Confirm that the account was created
-                       $out->setPageTitle( $this->msg( 'accountcreated' ) );
-                       $out->addWikiMsg( 'accountcreatedtext', $u->getName() );
-                       $out->addReturnTo( $this->getPageTitle() );
-                       Hooks::run( 'AddNewAccount', [ $u, false ] );
-                       $u->addNewUserLogEntry( 'create2', $this->mReason );
-               }
-
-               return true;
-       }
-
-       /**
-        * Make a new user account using the loaded data.
-        * @private
-        * @throws PermissionsError|ReadOnlyError
-        * @return Status
-        */
-       public function addNewAccountInternal() {
-               global $wgAuth, $wgAccountCreationThrottle, $wgEmailConfirmToEdit;
-
-               // If the user passes an invalid domain, something is fishy
-               if ( !$wgAuth->validDomain( $this->mDomain ) ) {
-                       return Status::newFatal( 'wrongpassword' );
-               }
-
-               // If we are not allowing users to login locally, we should be checking
-               // to see if the user is actually able to authenticate to the authenti-
-               // cation server before they create an account (otherwise, they can
-               // create a local account and login as any domain user). We only need
-               // to check this for domains that aren't local.
-               if ( 'local' != $this->mDomain && $this->mDomain != '' ) {
-                       if (
-                               !$wgAuth->canCreateAccounts() &&
-                               (
-                                       !$wgAuth->userExists( $this->mUsername ) ||
-                                       !$wgAuth->authenticate( $this->mUsername, $this->mPassword )
-                               )
-                       ) {
-                               return Status::newFatal( 'wrongpassword' );
-                       }
-               }
-
-               if ( wfReadOnly() ) {
-                       throw new ReadOnlyError;
-               }
-
-               # Request forgery checks.
-               $token = self::getCreateaccountToken();
-               if ( $token->wasNew() ) {
-                       return Status::newFatal( 'nocookiesfornew' );
-               }
-
-               # The user didn't pass a createaccount token
-               if ( !$this->mToken ) {
-                       return Status::newFatal( 'sessionfailure' );
-               }
-
-               # Validate the createaccount token
-               if ( !$token->match( $this->mToken ) ) {
-                       return Status::newFatal( 'sessionfailure' );
-               }
-
-               # Check permissions
-               $currentUser = $this->getUser();
-               $creationBlock = $currentUser->isBlockedFromCreateAccount();
-               if ( !$currentUser->isAllowed( 'createaccount' ) ) {
-                       throw new PermissionsError( 'createaccount' );
-               } elseif ( $creationBlock instanceof Block ) {
-                       // Throws an ErrorPageError.
-                       $this->userBlockedMessage( $creationBlock );
-
-                       // This should never be reached.
-                       return false;
-               }
-
-               # Include checks that will include GlobalBlocking (Bug 38333)
-               $permErrors = $this->getPageTitle()->getUserPermissionsErrors(
-                       'createaccount',
-                       $currentUser,
-                       true
-               );
-
-               if ( count( $permErrors ) ) {
-                       throw new PermissionsError( 'createaccount', $permErrors );
-               }
-
-               $ip = $this->getRequest()->getIP();
-               if ( $currentUser->isDnsBlacklisted( $ip, true /* check $wgProxyWhitelist */ ) ) {
-                       return Status::newFatal( 'sorbs_create_account_reason' );
-               }
-
-               # Now create a dummy user ($u) and check if it is valid
-               $u = User::newFromName( $this->mUsername, 'creatable' );
-               if ( !$u ) {
-                       return Status::newFatal( 'noname' );
-               }
-
-               $cache = ObjectCache::getLocalClusterInstance();
-               # Make sure the user does not exist already
-               $lock = $cache->getScopedLock( $cache->makeGlobalKey( 'account', md5( $this->mUsername ) ) );
-               if ( !$lock ) {
-                       return Status::newFatal( 'usernameinprogress' );
-               } elseif ( $u->idForName( User::READ_LOCKING ) ) {
-                       return Status::newFatal( 'userexists' );
-               }
-
-               if ( $this->mCreateaccountMail ) {
-                       # do not force a password for account creation by email
-                       # set invalid password, it will be replaced later by a random generated password
-                       $this->mPassword = null;
-               } else {
-                       if ( $this->mPassword !== $this->mRetype ) {
-                               return Status::newFatal( 'badretype' );
-                       }
-
-                       # check for password validity, return a fatal Status if invalid
-                       $validity = $u->checkPasswordValidity( $this->mPassword, 'create' );
-                       if ( !$validity->isGood() ) {
-                               $validity->ok = false; // make sure this Status is fatal
-                               return $validity;
-                       }
-               }
-
-               # if you need a confirmed email address to edit, then obviously you
-               # need an email address.
-               if ( $wgEmailConfirmToEdit && strval( $this->mEmail ) === '' ) {
-                       return Status::newFatal( 'noemailtitle' );
-               }
-
-               if ( strval( $this->mEmail ) !== '' && !Sanitizer::validateEmail( $this->mEmail ) ) {
-                       return Status::newFatal( 'invalidemailaddress' );
-               }
-
-               # Set some additional data so the AbortNewAccount hook can be used for
-               # more than just username validation
-               $u->setEmail( $this->mEmail );
-               $u->setRealName( $this->mRealName );
-
-               $abortError = '';
-               $abortStatus = null;
-               if ( !Hooks::run( 'AbortNewAccount', [ $u, &$abortError, &$abortStatus ] ) ) {
-                       // Hook point to add extra creation throttles and blocks
-                       wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
-                       if ( $abortStatus === null ) {
-                               // Report back the old string as a raw message status.
-                               // This will report the error back as 'createaccount-hook-aborted'
-                               // with the given string as the message.
-                               // To return a different error code, return a Status object.
-                               $abortError = new Message( 'createaccount-hook-aborted', [ $abortError ] );
-                               $abortError->text();
-
-                               return Status::newFatal( $abortError );
-                       } else {
-                               // For MediaWiki 1.23+ and updated hooks, return the Status object
-                               // returned from the hook.
-                               return $abortStatus;
-                       }
-               }
-
-               // Hook point to check for exempt from account creation throttle
-               if ( !Hooks::run( 'ExemptFromAccountCreationThrottle', [ $ip ] ) ) {
-                       wfDebug( "LoginForm::exemptFromAccountCreationThrottle: a hook " .
-                               "allowed account creation w/o throttle\n" );
-               } else {
-                       if ( ( $wgAccountCreationThrottle && $currentUser->isPingLimitable() ) ) {
-                               $key = wfGlobalCacheKey( 'acctcreate', 'ip', $ip );
-                               $value = $cache->get( $key );
-                               if ( !$value ) {
-                                       $cache->set( $key, 0, $cache::TTL_DAY );
-                               }
-                               if ( $value >= $wgAccountCreationThrottle ) {
-                                       return Status::newFatal( 'acct_creation_throttle_hit', $wgAccountCreationThrottle );
-                               }
-                               $cache->incr( $key );
-                       }
-               }
-
-               if ( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
-                       return Status::newFatal( 'externaldberror' );
-               }
-
-               self::clearCreateaccountToken();
-
-               return $this->initUser( $u, false );
-       }
-
-       /**
-        * Actually add a user to the database.
-        * Give it a User object that has been initialised with a name.
-        *
-        * @param User $u
-        * @param bool $autocreate True if this is an autocreation via auth plugin
-        * @return Status Status object, with the User object in the value member on success
-        * @private
-        */
-       function initUser( $u, $autocreate ) {
-               global $wgAuth;
-
-               $status = $u->addToDatabase();
-               if ( !$status->isOK() ) {
-                       return $status;
-               }
-
-               if ( $wgAuth->allowPasswordChange() ) {
-                       $u->setPassword( $this->mPassword );
-               }
-
-               $u->setEmail( $this->mEmail );
-               $u->setRealName( $this->mRealName );
-               $u->setToken();
-
-               Hooks::run( 'LocalUserCreated', [ $u, $autocreate ] );
-               $oldUser = $u;
-               $wgAuth->initUser( $u, $autocreate );
-               if ( $oldUser !== $u ) {
-                       wfWarn( get_class( $wgAuth ) . '::initUser() replaced the user object' );
-               }
-
-               $u->saveSettings();
-
-               // Update user count
-               DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
-
-               // Watch user's userpage and talk page
-               $u->addWatch( $u->getUserPage(), User::IGNORE_USER_RIGHTS );
-
-               return Status::newGood( $u );
-       }
-
-       /**
-        * Internally authenticate the login request.
-        *
-        * This may create a local account as a side effect if the
-        * authentication plugin allows transparent local account
-        * creation.
-        * @return int
-        */
-       public function authenticateUserData() {
-               global $wgUser, $wgAuth;
-
-               $this->load();
-
-               if ( $this->mUsername == '' ) {
-                       return self::NO_NAME;
-               }
-
-               // We require a login token to prevent login CSRF
-               // Handle part of this before incrementing the throttle so
-               // token-less login attempts don't count towards the throttle
-               // but wrong-token attempts do.
-
-               // If the user doesn't have a login token yet, set one.
-               $token = self::getLoginToken();
-               if ( $token->wasNew() ) {
-                       return self::NEED_TOKEN;
-               }
-               // If the user didn't pass a login token, tell them we need one
-               if ( !$this->mToken ) {
-                       return self::NEED_TOKEN;
-               }
-
-               $throttleCount = self::incrementLoginThrottle( $this->mUsername );
-               if ( $throttleCount ) {
-                       $this->mThrottleWait = $throttleCount['wait'];
-                       return self::THROTTLED;
-               }
-
-               // Validate the login token
-               if ( !$token->match( $this->mToken ) ) {
-                       return self::WRONG_TOKEN;
-               }
-
-               // Load the current user now, and check to see if we're logging in as
-               // the same name. This is necessary because loading the current user
-               // (say by calling getName()) calls the UserLoadFromSession hook, which
-               // potentially creates the user in the database. Until we load $wgUser,
-               // checking for user existence using User::newFromName($name)->getId() below
-               // will effectively be using stale data.
-               if ( $this->getUser()->getName() === $this->mUsername ) {
-                       wfDebug( __METHOD__ . ": already logged in as {$this->mUsername}\n" );
-
-                       return self::SUCCESS;
-               }
-
-               $u = User::newFromName( $this->mUsername );
-               if ( $u === false ) {
-                       return self::ILLEGAL;
-               }
-
-               $msg = null;
-               // Give extensions a way to indicate the username has been updated,
-               // rather than telling the user the account doesn't exist.
-               if ( !Hooks::run( 'LoginUserMigrated', [ $u, &$msg ] ) ) {
-                       $this->mAbortLoginErrorMsg = $msg;
-                       return self::USER_MIGRATED;
-               }
-
-               if ( !User::isUsableName( $u->getName() ) ) {
-                       return self::ILLEGAL;
-               }
-
-               $isAutoCreated = false;
-               if ( $u->getId() == 0 ) {
-                       $status = $this->attemptAutoCreate( $u );
-                       if ( $status !== self::SUCCESS ) {
-                               return $status;
-                       } else {
-                               $isAutoCreated = true;
-                       }
-               } else {
-                       $u->load();
-               }
-
-               // Give general extensions, such as a captcha, a chance to abort logins
-               $abort = self::ABORTED;
-               if ( !Hooks::run( 'AbortLogin', [ $u, $this->mPassword, &$abort, &$msg ] ) ) {
-                       if ( !in_array( $abort, array_keys( self::$statusCodes ), true ) ) {
-                               throw new Exception( 'Invalid status code returned from AbortLogin hook: ' . $abort );
-                       }
-                       $this->mAbortLoginErrorMsg = $msg;
-                       return $abort;
-               }
-
-               global $wgBlockDisablesLogin;
-               if ( !$u->checkPassword( $this->mPassword ) ) {
-                       if ( $u->checkTemporaryPassword( $this->mPassword ) ) {
-                               /**
-                                * The e-mailed temporary password should not be used for actu-
-                                * al logins; that's a very sloppy habit, and insecure if an
-                                * attacker has a few seconds to click "search" on someone's
-                                * open mail reader.
-                                *
-                                * Allow it to be used only to reset the password a single time
-                                * to a new value, which won't be in the user's e-mail ar-
-                                * chives.
-                                *
-                                * For backwards compatibility, we'll still recognize it at the
-                                * login form to minimize surprises for people who have been
-                                * logging in with a temporary password for some time.
-                                *
-                                * As a side-effect, we can authenticate the user's e-mail ad-
-                                * dress if it's not already done, since the temporary password
-                                * was sent via e-mail.
-                                */
-                               if ( !$u->isEmailConfirmed() && !wfReadOnly() ) {
-                                       $u->confirmEmail();
-                                       $u->saveSettings();
-                               }
-
-                               // At this point we just return an appropriate code/ indicating
-                               // that the UI should show a password reset form; bot inter-
-                               // faces etc will probably just fail cleanly here.
-                               $this->mAbortLoginErrorMsg = 'resetpass-temp-emailed';
-                               $this->mTempPasswordUsed = true;
-                               $retval = self::RESET_PASS;
-                       } else {
-                               $retval = ( $this->mPassword == '' ) ? self::EMPTY_PASS : self::WRONG_PASS;
-                       }
-               } elseif ( $wgBlockDisablesLogin && $u->isBlocked() ) {
-                       // If we've enabled it, make it so that a blocked user cannot login
-                       $retval = self::USER_BLOCKED;
-               } elseif ( $this->checkUserPasswordExpired( $u ) == 'hard' ) {
-                       // Force reset now, without logging in
-                       $retval = self::RESET_PASS;
-                       $this->mAbortLoginErrorMsg = 'resetpass-expired';
-               } else {
-                       Hooks::run( 'UserLoggedIn', [ $u ] );
-                       $oldUser = $u;
-                       $wgAuth->updateUser( $u );
-                       if ( $oldUser !== $u ) {
-                               wfWarn( get_class( $wgAuth ) . '::updateUser() replaced the user object' );
-                       }
-                       $wgUser = $u;
-                       // This should set it for OutputPage and the Skin
-                       // which is needed or the personal links will be
-                       // wrong.
-                       $this->getContext()->setUser( $u );
-
-                       // Please reset throttle for successful logins, thanks!
-                       self::clearLoginThrottle( $this->mUsername );
-
-                       if ( $isAutoCreated ) {
-                               // Must be run after $wgUser is set, for correct new user log
-                               Hooks::run( 'AuthPluginAutoCreate', [ $u ] );
-                       }
-
-                       $retval = self::SUCCESS;
-               }
-               Hooks::run( 'LoginAuthenticateAudit', [ $u, $this->mPassword, $retval ] );
-
-               return $retval;
-       }
-
-       /**
-        * Increment the login attempt throttle hit count for the (username,current IP)
-        * tuple unless the throttle was already reached.
-        *
-        * @since 1.27 Return value changed.
-        * @param string $username The user name
-        * @return bool|array false if below limit or an array if above limit
-        *   Array contains keys wait, count, and throttleIndex
-        */
-       public static function incrementLoginThrottle( $username ) {
-               global $wgPasswordAttemptThrottle, $wgRequest;
-               $canUsername = User::getCanonicalName( $username, 'usable' );
-               $username = $canUsername !== false ? $canUsername : $username;
-
-               $throttleCount = 0;
-               if ( is_array( $wgPasswordAttemptThrottle ) ) {
-                       $throttleConfig = $wgPasswordAttemptThrottle;
-                       if ( isset( $wgPasswordAttemptThrottle['count'] ) ) {
-                               // old style. Convert for backwards compat.
-                               $throttleConfig = [ $wgPasswordAttemptThrottle ];
-                       }
-                       foreach ( $throttleConfig as $index => $specificThrottle ) {
-                               if ( isset( $specificThrottle['allIPs'] ) ) {
-                                       $ip = 'All';
-                               } else {
-                                       $ip = $wgRequest->getIP();
-                               }
-                               $throttleKey = wfGlobalCacheKey( 'password-throttle',
-                                       $index, $ip, md5( $username )
-                               );
-                               $count = $specificThrottle['count'];
-                               $period = $specificThrottle['seconds'];
-
-                               $cache = ObjectCache::getLocalClusterInstance();
-                               $throttleCount = $cache->get( $throttleKey );
-                               if ( !$throttleCount ) {
-                                       $cache->add( $throttleKey, 1, $period ); // start counter
-                               } elseif ( $throttleCount < $count ) {
-                                       $cache->incr( $throttleKey );
-                               } elseif ( $throttleCount >= $count ) {
-                                       $logMsg = 'Login attempt rejected because logins to '
-                                               . '{acct} from IP {ip} have been throttled for '
-                                               . '{period} seconds due to {count} failed attempts';
-                                       // If we are hitting a throttle for >= 50 attempts,
-                                       // it is much more likely to be an attack than someone
-                                       // simply forgetting their password, so log it at a
-                                       // higher level.
-                                       $level = $count >= 50 ? LogLevel::WARNING : LogLevel::INFO;
-                                       // It should be noted that once the throttle is hit,
-                                       // every attempt to login will generate the log message
-                                       // until the throttle expires, not just the attempt that
-                                       // puts the throttle over the top.
-                                       LoggerFactory::getInstance( 'password-throttle' )->log(
-                                               $level,
-                                               $logMsg,
-                                               [
-                                                       'ip' => $ip,
-                                                       'period' => $period,
-                                                       'acct' => $username,
-                                                       'count' => $count,
-                                                       'throttleIdentifier' => $index,
-                                                       'method' => __METHOD__
-                                               ]
-                                       );
-
-                                       return [
-                                               'throttleIndex' => $index,
-                                               'wait' => $period,
-                                               'count' => $count
-                                       ];
-                               }
-                       }
-               }
-               return false;
-       }
-
-       /**
-        * Increment the login attempt throttle hit count for the (username,current IP)
-        * tuple unless the throttle was already reached.
-        *
-        * @deprecated Use LoginForm::incrementLoginThrottle instead
-        * @param string $username The user name
-        * @return bool|int true if above throttle, or 0 (prior to 1.27, returned current count)
-        */
-       public static function incLoginThrottle( $username ) {
-               wfDeprecated( __METHOD__, "1.27" );
-               $res = self::incrementLoginThrottle( $username );
-               return is_array( $res ) ? true : 0;
-       }
-
-       /**
-        * Clear the login attempt throttle hit count for the (username,current IP) tuple.
-        * @param string $username The user name
-        * @return void
-        */
-       public static function clearLoginThrottle( $username ) {
-               global $wgRequest, $wgPasswordAttemptThrottle;
-               $canUsername = User::getCanonicalName( $username, 'usable' );
-               $username = $canUsername !== false ? $canUsername : $username;
-
-               if ( is_array( $wgPasswordAttemptThrottle ) ) {
-                       $throttleConfig = $wgPasswordAttemptThrottle;
-                       if ( isset( $wgPasswordAttemptThrottle['count'] ) ) {
-                               // old style. Convert for backwards compat.
-                               $throttleConfig = [ $wgPasswordAttemptThrottle ];
-                       }
-                       foreach ( $throttleConfig as $index => $specificThrottle ) {
-                               if ( isset( $specificThrottle['allIPs'] ) ) {
-                                       $ip = 'All';
-                               } else {
-                                       $ip = $wgRequest->getIP();
-                               }
-                               $throttleKey = wfGlobalCacheKey( 'password-throttle', $index,
-                                       $ip, md5( $username )
-                               );
-                               ObjectCache::getLocalClusterInstance()->delete( $throttleKey );
-                       }
-               }
-       }
-
-       /**
-        * Attempt to automatically create a user on login. Only succeeds if there
-        * is an external authentication method which allows it.
-        *
-        * @param User $user
-        *
-        * @return int Status code
-        */
-       function attemptAutoCreate( $user ) {
-               global $wgAuth;
-
-               if ( $this->getUser()->isBlockedFromCreateAccount() ) {
-                       wfDebug( __METHOD__ . ": user is blocked from account creation\n" );
-
-                       return self::CREATE_BLOCKED;
-               }
-
-               if ( !$wgAuth->autoCreate() ) {
-                       return self::NOT_EXISTS;
-               }
-
-               if ( !$wgAuth->userExists( $user->getName() ) ) {
-                       wfDebug( __METHOD__ . ": user does not exist\n" );
-
-                       return self::NOT_EXISTS;
-               }
-
-               if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) {
-                       wfDebug( __METHOD__ . ": \$wgAuth->authenticate() returned false, aborting\n" );
-
-                       return self::WRONG_PLUGIN_PASS;
-               }
-
-               $abortError = '';
-               if ( !Hooks::run( 'AbortAutoAccount', [ $user, &$abortError ] ) ) {
-                       // Hook point to add extra creation throttles and blocks
-                       wfDebug( "LoginForm::attemptAutoCreate: a hook blocked creation: $abortError\n" );
-                       $this->mAbortLoginErrorMsg = $abortError;
-
-                       return self::ABORTED;
-               }
-
-               wfDebug( __METHOD__ . ": creating account\n" );
-               $status = $this->initUser( $user, true );
-
-               if ( !$status->isOK() ) {
-                       $errors = $status->getErrorsByType( 'error' );
-                       $this->mAbortLoginErrorMsg = $errors[0]['message'];
-
-                       return self::ABORTED;
-               }
-
-               return self::SUCCESS;
-       }
-
-       function processLogin() {
-               global $wgLang, $wgSecureLogin, $wgInvalidPasswordReset;
-
-               $authRes = $this->authenticateUserData();
-               switch ( $authRes ) {
-                       case self::SUCCESS:
-                               # We've verified now, update the real record
-                               $user = $this->getUser();
-                               $user->touch();
-
-                               if ( $user->requiresHTTPS() ) {
-                                       $this->mStickHTTPS = true;
-                               }
-
-                               if ( $wgSecureLogin && !$this->mStickHTTPS ) {
-                                       $user->setCookies( $this->mRequest, false, $this->mRemember );
-                               } else {
-                                       $user->setCookies( $this->mRequest, null, $this->mRemember );
-                               }
-                               self::clearLoginToken();
-
-                               // Reset the throttle
-                               self::clearLoginThrottle( $this->mUsername );
-
-                               $request = $this->getRequest();
-                               if ( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
-                                       /* Replace the language object to provide user interface in
-                                        * correct language immediately on this first page load.
-                                        */
-                                       $code = $request->getVal( 'uselang', $user->getOption( 'language' ) );
-                                       $userLang = Language::factory( $code );
-                                       $wgLang = $userLang;
-                                       RequestContext::getMain()->setLanguage( $userLang );
-                                       $this->getContext()->setLanguage( $userLang );
-                                       // Reset SessionID on Successful login (bug 40995)
-                                       $this->renewSessionId();
-                                       if ( $this->checkUserPasswordExpired( $this->getUser() ) == 'soft' ) {
-                                               $this->resetLoginForm( $this->msg( 'resetpass-expired-soft' ) );
-                                       } elseif ( $wgInvalidPasswordReset
-                                               && !$user->isValidPassword( $this->mPassword )
-                                       ) {
-                                               $status = $user->checkPasswordValidity(
-                                                       $this->mPassword,
-                                                       'login'
-                                               );
-                                               $this->resetLoginForm(
-                                                       $status->getMessage( 'resetpass-validity-soft' )
-                                               );
-                                       } else {
-                                               $this->successfulLogin();
-                                       }
-                               } else {
-                                       $this->cookieRedirectCheck( 'login' );
-                               }
-                               break;
-
-                       case self::NEED_TOKEN:
-                               $error = $this->mAbortLoginErrorMsg ?: 'nocookiesforlogin';
-                               $this->mainLoginForm( $this->msg( $error )->parse() );
-                               break;
-                       case self::WRONG_TOKEN:
-                               $error = $this->mAbortLoginErrorMsg ?: 'sessionfailure';
-                               $this->mainLoginForm( $this->msg( $error )->text() );
-                               break;
-                       case self::NO_NAME:
-                       case self::ILLEGAL:
-                               $error = $this->mAbortLoginErrorMsg ?: 'noname';
-                               $this->mainLoginForm( $this->msg( $error )->text() );
-                               break;
-                       case self::WRONG_PLUGIN_PASS:
-                               $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword';
-                               $this->mainLoginForm( $this->msg( $error )->text() );
-                               break;
-                       case self::NOT_EXISTS:
-                               if ( $this->getUser()->isAllowed( 'createaccount' ) ) {
-                                       $error = $this->mAbortLoginErrorMsg ?: 'nosuchuser';
-                                       $this->mainLoginForm( $this->msg( $error,
-                                               wfEscapeWikiText( $this->mUsername ) )->parse() );
-                               } else {
-                                       $error = $this->mAbortLoginErrorMsg ?: 'nosuchusershort';
-                                       $this->mainLoginForm( $this->msg( $error,
-                                               wfEscapeWikiText( $this->mUsername ) )->text() );
-                               }
-                               break;
-                       case self::WRONG_PASS:
-                               $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword';
-                               $this->mainLoginForm( $this->msg( $error )->text() );
-                               break;
-                       case self::EMPTY_PASS:
-                               $error = $this->mAbortLoginErrorMsg ?: 'wrongpasswordempty';
-                               $this->mainLoginForm( $this->msg( $error )->text() );
-                               break;
-                       case self::RESET_PASS:
-                               $error = $this->mAbortLoginErrorMsg ?: 'resetpass_announce';
-                               $this->resetLoginForm( $this->msg( $error ) );
-                               break;
-                       case self::CREATE_BLOCKED:
-                               $this->userBlockedMessage( $this->getUser()->isBlockedFromCreateAccount() );
-                               break;
-                       case self::THROTTLED:
-                               $error = $this->mAbortLoginErrorMsg ?: 'login-throttled';
-                               $this->mainLoginForm( $this->msg( $error )
-                                       ->durationParams( $this->mThrottleWait )->text()
-                               );
-                               break;
-                       case self::USER_BLOCKED:
-                               $error = $this->mAbortLoginErrorMsg ?: 'login-userblocked';
-                               $this->mainLoginForm( $this->msg( $error, $this->mUsername )->escaped() );
-                               break;
-                       case self::ABORTED:
-                               $error = $this->mAbortLoginErrorMsg ?: 'login-abort-generic';
-                               $this->mainLoginForm( $this->msg( $error,
-                                               wfEscapeWikiText( $this->mUsername ) )->text() );
-                               break;
-                       case self::USER_MIGRATED:
-                               $error = $this->mAbortLoginErrorMsg ?: 'login-migrated-generic';
-                               $params = [];
-                               if ( is_array( $error ) ) {
-                                       $error = array_shift( $this->mAbortLoginErrorMsg );
-                                       $params = $this->mAbortLoginErrorMsg;
-                               }
-                               $this->mainLoginForm( $this->msg( $error, $params )->text() );
-                               break;
-                       default:
-                               throw new MWException( 'Unhandled case value' );
-               }
-
-               LoggerFactory::getInstance( 'authmanager' )->info( 'Login attempt', [
-                       'event' => 'login',
-                       'successful' => $authRes === self::SUCCESS,
-                       'status' => LoginForm::$statusCodes[$authRes],
-               ] );
-       }
-
-       /**
-        * Show the Special:ChangePassword form, with custom message
-        * @param Message $msg
-        */
-       protected function resetLoginForm( Message $msg ) {
-               // Allow hooks to explain this password reset in more detail
-               Hooks::run( 'LoginPasswordResetMessage', [ &$msg, $this->mUsername ] );
-               $reset = new SpecialChangePasswordPreAuthManager();
-               $derivative = new DerivativeContext( $this->getContext() );
-               $derivative->setTitle( $reset->getPageTitle() );
-               $reset->setContext( $derivative );
-               if ( !$this->mTempPasswordUsed ) {
-                       $reset->setOldPasswordMessage( 'oldpassword' );
-               }
-               $reset->setChangeMessage( $msg );
-               $reset->execute( null );
-       }
-
-       /**
-        * @param User $u
-        * @param bool $throttle
-        * @param string $emailTitle Message name of email title
-        * @param string $emailText Message name of email text
-        * @return Status
-        */
-       function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle',
-               $emailText = 'passwordremindertext'
-       ) {
-               global $wgNewPasswordExpiry, $wgMinimalPasswordLength;
-
-               if ( $u->getEmail() == '' ) {
-                       return Status::newFatal( 'noemail', $u->getName() );
-               }
-               $ip = $this->getRequest()->getIP();
-               if ( !$ip ) {
-                       return Status::newFatal( 'badipaddress' );
-               }
-
-               $currentUser = $this->getUser();
-               Hooks::run( 'User::mailPasswordInternal', [ &$currentUser, &$ip, &$u ] );
-
-               $np = PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength );
-               $u->setNewpassword( $np, $throttle );
-               $u->saveSettings();
-               $userLanguage = $u->getOption( 'language' );
-
-               $mainPage = Title::newMainPage();
-               $mainPageUrl = $mainPage->getCanonicalURL();
-
-               $m = $this->msg( $emailText, $ip, $u->getName(), $np, '<' . $mainPageUrl . '>',
-                       round( $wgNewPasswordExpiry / 86400 ) )->inLanguage( $userLanguage )->text();
-               $result = $u->sendMail( $this->msg( $emailTitle )->inLanguage( $userLanguage )->text(), $m );
-
-               return $result;
-       }
-
-       /**
-        * Run any hooks registered for logins, then HTTP redirect to
-        * $this->mReturnTo (or Main Page if that's undefined).  Formerly we had a
-        * nice message here, but that's really not as useful as just being sent to
-        * wherever you logged in from.  It should be clear that the action was
-        * successful, given the lack of error messages plus the appearance of your
-        * name in the upper right.
-        *
-        * @private
-        */
-       function successfulLogin() {
-               # Run any hooks; display injected HTML if any, else redirect
-               $currentUser = $this->getUser();
-               $injected_html = '';
-               $direct = RequestContext::getMain()->getRequest()->wasPosted();
-               Hooks::run( 'UserLoginComplete', [ &$currentUser, &$injected_html, $direct ] );
-
-               if ( $injected_html !== '' ) {
-                       $this->displaySuccessfulAction( 'success', $this->msg( 'loginsuccesstitle' ),
-                               'loginsuccess', $injected_html );
-               } else {
-                       $this->executeReturnTo( 'successredirect' );
-               }
-       }
-
-       /**
-        * Run any hooks registered for logins, then display a message welcoming
-        * the user.
-        *
-        * @private
-        */
-       function successfulCreation() {
-               # Run any hooks; display injected HTML
-               $currentUser = $this->getUser();
-               $injected_html = '';
-               $welcome_creation_msg = 'welcomecreation-msg';
-               $direct = RequestContext::getMain()->getRequest()->wasPosted();
-
-               Hooks::run( 'UserLoginComplete', [ &$currentUser, &$injected_html, $direct ] );
-
-               /**
-                * Let any extensions change what message is shown.
-                * @see https://www.mediawiki.org/wiki/Manual:Hooks/BeforeWelcomeCreation
-                * @since 1.18
-                */
-               Hooks::run( 'BeforeWelcomeCreation', [ &$welcome_creation_msg, &$injected_html ] );
-
-               $this->displaySuccessfulAction(
-                       'signup',
-                       $this->msg( 'welcomeuser', $this->getUser()->getName() ),
-                       $welcome_creation_msg, $injected_html
-               );
-       }
-
-       /**
-        * Display a "successful action" page.
-        *
-        * @param string $type Condition of return to; see `executeReturnTo`
-        * @param string|Message $title Page's title
-        * @param string $msgname
-        * @param string $injected_html
-        */
-       private function displaySuccessfulAction( $type, $title, $msgname, $injected_html ) {
-               $out = $this->getOutput();
-               $out->setPageTitle( $title );
-               if ( $msgname ) {
-                       $out->addWikiMsg( $msgname, wfEscapeWikiText( $this->getUser()->getName() ) );
-               }
-
-               $out->addHTML( $injected_html );
-
-               $this->executeReturnTo( $type );
-       }
-
-       /**
-        * Output a message that informs the user that they cannot create an account because
-        * there is a block on them or their IP which prevents account creation.  Note that
-        * User::isBlockedFromCreateAccount(), which gets this block, ignores the 'hardblock'
-        * setting on blocks (bug 13611).
-        * @param Block $block The block causing this error
-        * @throws ErrorPageError
-        */
-       function userBlockedMessage( Block $block ) {
-               # Let's be nice about this, it's likely that this feature will be used
-               # for blocking large numbers of innocent people, e.g. range blocks on
-               # schools. Don't blame it on the user. There's a small chance that it
-               # really is the user's fault, i.e. the username is blocked and they
-               # haven't bothered to log out before trying to create an account to
-               # evade it, but we'll leave that to their guilty conscience to figure
-               # out.
-               $errorParams = [
-                       $block->getTarget(),
-                       $block->mReason ? $block->mReason : $this->msg( 'blockednoreason' )->text(),
-                       $block->getByName()
-               ];
-
-               if ( $block->getType() === Block::TYPE_RANGE ) {
-                       $errorMessage = 'cantcreateaccount-range-text';
-                       $errorParams[] = $this->getRequest()->getIP();
-               } else {
-                       $errorMessage = 'cantcreateaccount-text';
-               }
-
-               throw new ErrorPageError(
-                       'cantcreateaccounttitle',
-                       $errorMessage,
-                       $errorParams
-               );
-       }
-
-       /**
-        * Add a "return to" link or redirect to it.
-        * Extensions can use this to reuse the "return to" logic after
-        * inject steps (such as redirection) into the login process.
-        *
-        * @param string $type One of the following:
-        *    - error: display a return to link ignoring $wgRedirectOnLogin
-        *    - signup: display a return to link using $wgRedirectOnLogin if needed
-        *    - success: display a return to link using $wgRedirectOnLogin if needed
-        *    - successredirect: send an HTTP redirect using $wgRedirectOnLogin if needed
-        * @param string $returnTo
-        * @param array|string $returnToQuery
-        * @param bool $stickHTTPs Keep redirect link on HTTPs
-        * @since 1.22
-        */
-       public function showReturnToPage(
-               $type, $returnTo = '', $returnToQuery = '', $stickHTTPs = false
-       ) {
-               $this->mReturnTo = $returnTo;
-               $this->mReturnToQuery = $returnToQuery;
-               $this->mStickHTTPS = $stickHTTPs;
-               $this->executeReturnTo( $type );
-       }
-
-       /**
-        * Add a "return to" link or redirect to it.
-        *
-        * @param string $type One of the following:
-        *    - error: display a return to link ignoring $wgRedirectOnLogin
-        *    - signup: display a return to link using $wgRedirectOnLogin if needed
-        *    - success: display a return to link using $wgRedirectOnLogin if needed
-        *    - successredirect: send an HTTP redirect using $wgRedirectOnLogin if needed
-        */
-       private function executeReturnTo( $type ) {
-               global $wgRedirectOnLogin, $wgSecureLogin;
-
-               if ( $type != 'error' && $wgRedirectOnLogin !== null ) {
-                       $returnTo = $wgRedirectOnLogin;
-                       $returnToQuery = [];
-               } else {
-                       $returnTo = $this->mReturnTo;
-                       $returnToQuery = wfCgiToArray( $this->mReturnToQuery );
-               }
-
-               // Allow modification of redirect behavior
-               Hooks::run( 'PostLoginRedirect', [ &$returnTo, &$returnToQuery, &$type ] );
-
-               $returnToTitle = Title::newFromText( $returnTo );
-               if ( !$returnToTitle ) {
-                       $returnToTitle = Title::newMainPage();
-               }
-
-               if ( $wgSecureLogin && !$this->mStickHTTPS ) {
-                       $options = [ 'http' ];
-                       $proto = PROTO_HTTP;
-               } elseif ( $wgSecureLogin ) {
-                       $options = [ 'https' ];
-                       $proto = PROTO_HTTPS;
-               } else {
-                       $options = [];
-                       $proto = PROTO_RELATIVE;
-               }
-
-               if ( $type == 'successredirect' ) {
-                       $redirectUrl = $returnToTitle->getFullURL( $returnToQuery, false, $proto );
-                       $this->getOutput()->redirect( $redirectUrl );
-               } else {
-                       $this->getOutput()->addReturnTo( $returnToTitle, $returnToQuery, null, $options );
-               }
-       }
-
-       /**
-        * @param string $msg
-        * @param string $msgtype
-        * @throws ErrorPageError
-        * @throws Exception
-        * @throws FatalError
-        * @throws MWException
-        * @throws PermissionsError
-        * @throws ReadOnlyError
-        * @private
-        */
-       function mainLoginForm( $msg, $msgtype = 'error' ) {
-               global $wgEnableEmail, $wgEnableUserEmail;
-               global $wgHiddenPrefs, $wgLoginLanguageSelector;
-               global $wgAuth, $wgEmailConfirmToEdit;
-               global $wgSecureLogin, $wgPasswordResetRoutes;
-               global $wgExtendedLoginCookieExpiration, $wgCookieExpiration;
-
-               $titleObj = $this->getPageTitle();
-               $user = $this->getUser();
-               $out = $this->getOutput();
-
-               if ( $this->mType == 'signup' ) {
-                       // Block signup here if in readonly. Keeps user from
-                       // going through the process (filling out data, etc)
-                       // and being informed later.
-                       $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $user, true );
-                       if ( count( $permErrors ) ) {
-                               throw new PermissionsError( 'createaccount', $permErrors );
-                       } elseif ( $user->isBlockedFromCreateAccount() ) {
-                               $this->userBlockedMessage( $user->isBlockedFromCreateAccount() );
-
-                               return;
-                       } elseif ( wfReadOnly() ) {
-                               throw new ReadOnlyError;
-                       }
-               }
-
-               // Pre-fill username (if not creating an account, bug 44775).
-               if ( $this->mUsername == '' && $this->mType != 'signup' ) {
-                       if ( $user->isLoggedIn() ) {
-                               $this->mUsername = $user->getName();
-                       } else {
-                               $this->mUsername = $this->getRequest()->getSession()->suggestLoginUsername();
-                       }
-               }
-
-               // Generic styles and scripts for both login and signup form
-               $out->addModuleStyles( [
-                       'mediawiki.ui',
-                       'mediawiki.ui.button',
-                       'mediawiki.ui.checkbox',
-                       'mediawiki.ui.input',
-                       'mediawiki.special.userlogin.common.styles'
-               ] );
-
-               if ( $this->mType == 'signup' ) {
-                       // Additional styles and scripts for signup form
-                       $out->addModules( [
-                               'mediawiki.special.userlogin.signup.js'
-                       ] );
-                       $out->addModuleStyles( [
-                               'mediawiki.special.userlogin.signup.styles'
-                       ] );
-
-                       $template = new UsercreateTemplate( $this->getConfig() );
-
-                       // Must match number of benefits defined in messages
-                       $template->set( 'benefitCount', 3 );
-
-                       $q = 'action=submitlogin&type=signup';
-                       $linkq = 'type=login';
-               } else {
-                       // Additional styles for login form
-                       $out->addModuleStyles( [
-                               'mediawiki.special.userlogin.login.styles'
-                       ] );
-
-                       $template = new UserloginTemplate( $this->getConfig() );
-
-                       $q = 'action=submitlogin&type=login';
-                       $linkq = 'type=signup';
-               }
-
-               if ( $this->mReturnTo !== '' ) {
-                       $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo );
-                       if ( $this->mReturnToQuery !== '' ) {
-                               $returnto .= '&returntoquery=' .
-                                       wfUrlencode( $this->mReturnToQuery );
-                       }
-                       $q .= $returnto;
-                       $linkq .= $returnto;
-               }
-
-               # Don't show a "create account" link if the user can't.
-               if ( $this->showCreateOrLoginLink( $user ) ) {
-                       # Pass any language selection on to the mode switch link
-                       if ( $wgLoginLanguageSelector && $this->mLanguage ) {
-                               $linkq .= '&uselang=' . $this->mLanguage;
-                       }
-                       // Supply URL, login template creates the button.
-                       $template->set( 'createOrLoginHref', $titleObj->getLocalURL( $linkq ) );
-               } else {
-                       $template->set( 'link', '' );
-               }
-
-               $resetLink = $this->mType == 'signup'
-                       ? null
-                       : is_array( $wgPasswordResetRoutes ) && in_array( true, array_values( $wgPasswordResetRoutes ) );
-
-               $template->set( 'header', '' );
-               $template->set( 'formheader', '' );
-               $template->set( 'skin', $this->getSkin() );
-               $template->set( 'name', $this->mUsername );
-               $template->set( 'password', $this->mPassword );
-               $template->set( 'retype', $this->mRetype );
-               $template->set( 'createemailset', $this->mCreateaccountMail );
-               $template->set( 'email', $this->mEmail );
-               $template->set( 'realname', $this->mRealName );
-               $template->set( 'domain', $this->mDomain );
-               $template->set( 'reason', $this->mReason );
-
-               $template->set( 'action', $titleObj->getLocalURL( $q ) );
-               $template->set( 'message', $msg );
-               $template->set( 'messagetype', $msgtype );
-               $template->set( 'createemail', $wgEnableEmail && $user->isLoggedIn() );
-               $template->set( 'userealname', !in_array( 'realname', $wgHiddenPrefs ) );
-               $template->set( 'useemail', $wgEnableEmail );
-               $template->set( 'emailrequired', $wgEmailConfirmToEdit );
-               $template->set( 'emailothers', $wgEnableUserEmail );
-               $template->set( 'canreset', $wgAuth->allowPasswordChange() );
-               $template->set( 'resetlink', $resetLink );
-               $template->set( 'canremember', $wgExtendedLoginCookieExpiration === null ?
-                       ( $wgCookieExpiration > 0 ) :
-                       ( $wgExtendedLoginCookieExpiration > 0 ) );
-               $template->set( 'usereason', $user->isLoggedIn() );
-               $template->set( 'remember', $this->mRemember );
-               $template->set( 'cansecurelogin', ( $wgSecureLogin === true ) );
-               $template->set( 'stickhttps', (int)$this->mStickHTTPS );
-               $template->set( 'loggedin', $user->isLoggedIn() );
-               $template->set( 'loggedinuser', $user->getName() );
-
-               if ( $this->mType == 'signup' ) {
-                       $template->set( 'token', self::getCreateaccountToken()->toString() );
-               } else {
-                       $template->set( 'token', self::getLoginToken()->toString() );
-               }
-
-               # Prepare language selection links as needed
-               if ( $wgLoginLanguageSelector ) {
-                       $template->set( 'languages', $this->makeLanguageSelector() );
-                       if ( $this->mLanguage ) {
-                               $template->set( 'uselang', $this->mLanguage );
-                       }
-               }
-
-               $template->set( 'secureLoginUrl', $this->mSecureLoginUrl );
-               // Use signupend-https for HTTPS requests if it's not blank, signupend otherwise
-               $usingHTTPS = $this->mRequest->getProtocol() == 'https';
-               $signupendHTTPS = $this->msg( 'signupend-https' );
-               if ( $usingHTTPS && !$signupendHTTPS->isBlank() ) {
-                       $template->set( 'signupend', $signupendHTTPS->parse() );
-               } else {
-                       $template->set( 'signupend', $this->msg( 'signupend' )->parse() );
-               }
-
-               // If using HTTPS coming from HTTP, then the 'fromhttp' parameter must be preserved
-               if ( $usingHTTPS ) {
-                       $template->set( 'fromhttp', $this->mFromHTTP );
-               }
-
-               // Give authentication and captcha plugins a chance to modify the form
-               $wgAuth->modifyUITemplate( $template, $this->mType );
-               if ( $this->mType == 'signup' ) {
-                       Hooks::run( 'UserCreateForm', [ &$template ] );
-               } else {
-                       Hooks::run( 'UserLoginForm', [ &$template ] );
-               }
-
-               $out->disallowUserJs(); // just in case...
-               $out->addTemplate( $template );
-       }
-
-       /**
-        * Whether the login/create account form should display a link to the
-        * other form (in addition to whatever the skin provides).
-        *
-        * @param User $user
-        * @return bool
-        */
-       private function showCreateOrLoginLink( &$user ) {
-               if ( $this->mType == 'signup' ) {
-                       return true;
-               } elseif ( $user->isAllowed( 'createaccount' ) ) {
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * Check if a session cookie is present.
-        *
-        * This will not pick up a cookie set during _this_ request, but is meant
-        * to ensure that the client is returning the cookie which was set on a
-        * previous pass through the system.
-        *
-        * @private
-        * @return bool
-        */
-       function hasSessionCookie() {
-               global $wgDisableCookieCheck, $wgInitialSessionId;
-
-               return $wgDisableCookieCheck || (
-                       $wgInitialSessionId &&
-                       $this->getRequest()->getSession()->getId() === (string)$wgInitialSessionId
-               );
-       }
-
-       /**
-        * Get the login token from the current session
-        * @since 1.27 returns a MediaWiki\Session\Token instead of a string
-        * @return MediaWiki\Session\Token
-        */
-       public static function getLoginToken() {
-               global $wgRequest;
-               return $wgRequest->getSession()->getToken( '', 'login' );
-       }
-
-       /**
-        * Formerly randomly generated a login token that would be returned by
-        * $this->getLoginToken().
-        *
-        * Since 1.27, this is a no-op. The token is generated as necessary by
-        * $this->getLoginToken().
-        *
-        * @deprecated since 1.27
-        */
-       public static function setLoginToken() {
-               wfDeprecated( __METHOD__, '1.27' );
-       }
-
-       /**
-        * Remove any login token attached to the current session
-        */
-       public static function clearLoginToken() {
-               global $wgRequest;
-               $wgRequest->getSession()->resetToken( 'login' );
-       }
-
-       /**
-        * Get the createaccount token from the current session
-        * @since 1.27 returns a MediaWiki\Session\Token instead of a string
-        * @return MediaWiki\Session\Token
-        */
-       public static function getCreateaccountToken() {
-               global $wgRequest;
-               return $wgRequest->getSession()->getToken( '', 'createaccount' );
-       }
-
-       /**
-        * Formerly randomly generated a createaccount token that would be returned
-        * by $this->getCreateaccountToken().
-        *
-        * Since 1.27, this is a no-op. The token is generated as necessary by
-        * $this->getCreateaccountToken().
-        *
-        * @deprecated since 1.27
-        */
-       public static function setCreateaccountToken() {
-               wfDeprecated( __METHOD__, '1.27' );
-       }
-
-       /**
-        * Remove any createaccount token attached to the current session
-        */
-       public static function clearCreateaccountToken() {
-               global $wgRequest;
-               $wgRequest->getSession()->resetToken( 'createaccount' );
-       }
-
-       /**
-        * Renew the user's session id, using strong entropy
-        */
-       private function renewSessionId() {
-               global $wgSecureLogin, $wgCookieSecure;
-               if ( $wgSecureLogin && !$this->mStickHTTPS ) {
-                       $wgCookieSecure = false;
-               }
-
-               SessionManager::getGlobalSession()->resetId();
-               SessionManager::getGlobalSession()->resetAllTokens();
-       }
-
-       /**
-        * @param string $type
-        * @private
-        */
-       function cookieRedirectCheck( $type ) {
-               $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
-               $query = [ 'wpCookieCheck' => $type ];
-               if ( $this->mReturnTo !== '' ) {
-                       $query['returnto'] = $this->mReturnTo;
-                       $query['returntoquery'] = $this->mReturnToQuery;
-               }
-               $check = $titleObj->getFullURL( $query );
-
-               $this->getOutput()->redirect( $check );
-       }
-
-       /**
-        * @param string $type
-        * @private
-        */
-       function onCookieRedirectCheck( $type ) {
-               if ( !$this->hasSessionCookie() ) {
-                       if ( $type == 'new' ) {
-                               $this->mainLoginForm( $this->msg( 'nocookiesnew' )->parse() );
-                       } elseif ( $type == 'login' ) {
-                               $this->mainLoginForm( $this->msg( 'nocookieslogin' )->parse() );
-                       } else {
-                               # shouldn't happen
-                               $this->mainLoginForm( $this->msg( 'error' )->text() );
-                       }
-               } else {
-                       $this->successfulLogin();
-               }
-       }
-
-       /**
-        * Produce a bar of links which allow the user to select another language
-        * during login/registration but retain "returnto"
-        *
-        * @return string
-        */
-       function makeLanguageSelector() {
-               $msg = $this->msg( 'loginlanguagelinks' )->inContentLanguage();
-               if ( $msg->isBlank() ) {
-                       return '';
-               }
-               $langs = explode( "\n", $msg->text() );
-               $links = [];
-               foreach ( $langs as $lang ) {
-                       $lang = trim( $lang, '* ' );
-                       $parts = explode( '|', $lang );
-                       if ( count( $parts ) >= 2 ) {
-                               $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
-                       }
-               }
-
-               return count( $links ) > 0 ? $this->msg( 'loginlanguagelabel' )->rawParams(
-                       $this->getLanguage()->pipeList( $links ) )->escaped() : '';
-       }
-
-       /**
-        * Create a language selector link for a particular language
-        * Links back to this page preserving type and returnto
-        *
-        * @param string $text Link text
-        * @param string $lang Language code
-        * @return string
-        */
-       function makeLanguageSelectorLink( $text, $lang ) {
-               if ( $this->getLanguage()->getCode() == $lang ) {
-                       // no link for currently used language
-                       return htmlspecialchars( $text );
-               }
-               $query = [ 'uselang' => $lang ];
-               if ( $this->mType == 'signup' ) {
-                       $query['type'] = 'signup';
-               }
-               if ( $this->mReturnTo !== '' ) {
-                       $query['returnto'] = $this->mReturnTo;
-                       $query['returntoquery'] = $this->mReturnToQuery;
-               }
-
-               $attr = [];
-               $targetLanguage = Language::factory( $lang );
-               $attr['lang'] = $attr['hreflang'] = $targetLanguage->getHtmlCode();
-
-               return Linker::linkKnown(
-                       $this->getPageTitle(),
-                       htmlspecialchars( $text ),
-                       $attr,
-                       $query
-               );
-       }
-
-       protected function getGroupName() {
-               return 'login';
-       }
-
-       /**
-        * Private function to check password expiration, until AuthManager comes
-        * along to handle that.
-        * @param User $user
-        * @return string|bool
-        */
-       private function checkUserPasswordExpired( User $user ) {
-               global $wgPasswordExpireGrace;
-               $dbr = wfGetDB( DB_SLAVE );
-               $ts = $dbr->selectField( 'user', 'user_password_expires', [ 'user_id' => $user->getId() ] );
-
-               $expired = false;
-               $now = wfTimestamp();
-               $expUnix = wfTimestamp( TS_UNIX, $ts );
-               if ( $ts !== null && $expUnix < $now ) {
-                       $expired = ( $expUnix + $wgPasswordExpireGrace < $now ) ? 'hard' : 'soft';
-               }
-               return $expired;
-       }
-
-       protected function getSubpagesForPrefixSearch() {
-               return [ 'signup' ];
-       }
-}
diff --git a/includes/specials/pre-authmanager/SpecialUserlogout.php b/includes/specials/pre-authmanager/SpecialUserlogout.php
deleted file mode 100644 (file)
index 6d6a714..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-/**
- * Implements Special:Userlogout
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-/**
- * Implements Special:Userlogout
- *
- * @ingroup SpecialPage
- */
-class SpecialUserlogoutPreAuthManager extends UnlistedSpecialPage {
-       function __construct() {
-               parent::__construct( 'Userlogout' );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       function execute( $par ) {
-               /**
-                * Some satellite ISPs use broken precaching schemes that log people out straight after
-                * they're logged in (bug 17790). Luckily, there's a way to detect such requests.
-                */
-               if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], '&amp;' ) !== false ) {
-                       wfDebug( "Special:Userlogout request {$_SERVER['REQUEST_URI']} looks suspicious, denying.\n" );
-                       throw new HttpError( 400, $this->msg( 'suspicious-userlogout' ), $this->msg( 'loginerror' ) );
-               }
-
-               $this->setHeaders();
-               $this->outputHeader();
-
-               // Make sure it's possible to log out
-               $session = MediaWiki\Session\SessionManager::getGlobalSession();
-               if ( !$session->canSetUser() ) {
-                       throw new ErrorPageError(
-                               'cannotlogoutnow-title',
-                               'cannotlogoutnow-text',
-                               [
-                                       $session->getProvider()->describe( RequestContext::getMain()->getLanguage() )
-                               ]
-                       );
-               }
-
-               $user = $this->getUser();
-               $oldName = $user->getName();
-               $user->logout();
-
-               $loginURL = SpecialPage::getTitleFor( 'Userlogin' )->getFullURL(
-                       $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
-
-               $out = $this->getOutput();
-               $out->addWikiMsg( 'logouttext', $loginURL );
-
-               // Hook.
-               $injected_html = '';
-               Hooks::run( 'UserLogoutComplete', [ &$user, &$injected_html, $oldName ] );
-               $out->addHTML( $injected_html );
-
-               $out->returnToMain();
-       }
-
-       protected function getGroupName() {
-               return 'login';
-       }
-}
diff --git a/includes/templates/Usercreate.php b/includes/templates/Usercreate.php
deleted file mode 100644 (file)
index 0a5aa61..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-<?php
-// @codingStandardsIgnoreFile
-/**
- * Html form for account creation (since 1.22 with VForm appearance).
- *
- * 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 Templates
- * @deprecated Will be removed when AuthManager lands.
- *   The signup form will be generated via HTMLForm.
- */
-
-class UsercreateTemplate extends BaseTemplate {
-       /**
-        * Extensions (AntiSpoof and TitleBlacklist) call this in response to
-        * UserCreateForm hook to add checkboxes to the create account form.
-        */
-       function addInputItem( $name, $value, $type, $msg, $helptext = false ) {
-               $this->data['extraInput'][] = [
-                       'name' => $name,
-                       'value' => $value,
-                       'type' => $type,
-                       'msg' => $msg,
-                       'helptext' => $helptext,
-               ];
-       }
-
-       function execute() {
-?>
-<div class="mw-ui-container">
-       <?php if ( $this->haveData( 'languages' ) ) { ?>
-               <div id="languagelinks">
-                       <p><?php $this->html( 'languages' ); ?></p>
-               </div>
-       <?php }
-             if ( !wfMessage( 'signupstart' )->isDisabled() ) { ?>
-               <div id="signupstart"><?php $this->msgWiki( 'signupstart' ); ?></div>
-       <?php } ?>
-       <div id="userloginForm">
-               <form name="userlogin2" id="userlogin2" class="mw-ui-vform" method="post" action="<?php $this->text( 'action' ); ?>">
-                       <section class="mw-form-header">
-                               <?php $this->html( 'header' ); ?>
-                       </section>
-                       <!-- This element is used by the mediawiki.special.userlogin.signup.js module. -->
-                       <div
-                               id="mw-createacct-status-area"
-                               <?php if ( $this->data['message'] ) { ?>
-                                       class="<?php echo $this->data['messagetype']; ?>box"
-                               <?php } else { ?>
-                                       style="display: none;"
-                               <?php } ?>
-                       >
-                       <?php if ( $this->data['message'] ) { ?>
-                                       <?php if ( $this->data['messagetype'] == 'error' ) { ?>
-                                               <strong><?php $this->msg( 'createacct-error' ); ?></strong>
-                                               <br />
-                                       <?php } ?>
-                                       <?php $this->html( 'message' ); ?>
-                       <?php } ?>
-                       </div>
-
-                       <?php if ( $this->data['formheader'] ) { ?>
-                               <div class="mw-form-formheader">
-                                       <?php $this->html( 'formheader' ); /* extensions such as MobileFrontend add html here */ ?>
-                               </div>
-                       <?php } ?>
-
-                       <div class="mw-ui-vform-field">
-                               <label for='wpName2'>
-                                       <?php $this->msg( 'userlogin-yourname' ); ?>
-
-                                       <span class="mw-ui-flush-right"><?php echo $this->getMsg( 'createacct-helpusername' )->parse(); ?></span>
-                               </label>
-                               <?php
-                               echo Html::input( 'wpName', $this->data['name'], 'text', [
-                                       'class' => 'mw-ui-input loginText',
-                                       'id' => 'wpName2',
-                                       'tabindex' => '1',
-                                       'size' => '20',
-                                       'required',
-                                       'placeholder' => $this->getMsg( $this->data['loggedin'] ?
-                                               'createacct-another-username-ph' : 'userlogin-yourname-ph' )->text(),
-                               ] );
-                               ?>
-                       </div>
-
-                       <div class="mw-ui-vform-field">
-                               <?php if ( $this->data['createemail'] ) { ?>
-                                       <div class="mw-ui-checkbox">
-                                               <input name="wpCreateaccountMail" type="checkbox" value="1" id="wpCreateaccountMail" tabindex="2"
-                                                       <?php if ( $this->data['createemailset'] ) {
-                                                               echo 'checked="checked"';
-                                                       } ?>
-                                               ><label for="wpCreateaccountMail">
-                                                       <?php $this->msg( 'createaccountmail' ); ?>
-                                               </label>
-                                       </div>
-                               <?php } ?>
-                       </div>
-
-                       <div class="mw-ui-vform-field mw-row-password">
-                               <label for='wpPassword2'><?php $this->msg( 'userlogin-yourpassword' ); ?></label>
-                               <?php
-                               echo Html::input( 'wpPassword', null, 'password', [
-                                       'class' => 'mw-ui-input loginPassword',
-                                       'id' => 'wpPassword2',
-                                       'tabindex' => '3',
-                                       'size' => '20',
-                                       'required',
-                                       'placeholder' => $this->getMsg( 'createacct-yourpassword-ph' )->text()
-                               ] + User::passwordChangeInputAttribs() );
-                               ?>
-                       </div>
-
-                       <?php
-                       if ( $this->data['usedomain'] ) {
-                               $select = new XmlSelect( 'wpDomain', false, $this->data['domain'] );
-                               $select->setAttribute( 'tabindex', 4 );
-                               foreach ( $this->data['domainnames'] as $dom ) {
-                                       $select->addOption( $dom );
-                               }
-                       ?>
-                               <div class="mw-ui-vform-field" id="mw-user-domain-section">
-                                       <label for="wpDomain"><?php $this->msg( 'yourdomainname' ); ?></label>
-                                       <div>
-                                               <?php echo $select->getHTML(); ?>
-                                       </div>
-                               </div>
-                       <?php } ?>
-
-                       <div class="mw-ui-vform-field mw-row-password">
-                               <label for='wpRetype'><?php $this->msg( 'createacct-yourpasswordagain' ); ?></label>
-                               <?php
-                               echo Html::input( 'wpRetype', null, 'password', [
-                                       'class' => 'mw-ui-input loginPassword',
-                                       'id' => 'wpRetype',
-                                       'tabindex' => '5',
-                                       'size' => '20',
-                                       'required',
-                                       'placeholder' => $this->getMsg( 'createacct-yourpasswordagain-ph' )->text()
-                               ] + User::passwordChangeInputAttribs() );
-                               ?>
-                       </div>
-
-                       <div class="mw-ui-vform-field">
-                               <?php if ( $this->data['useemail'] ) { ?>
-                                       <label for='wpEmail'>
-                                               <?php
-                                                       $this->msg( $this->data['emailrequired'] ?
-                                                               'createacct-emailrequired' :
-                                                               'createacct-emailoptional'
-                                                       );
-                                               ?>
-                                       </label>
-                                       <?php
-                                               echo Html::input( 'wpEmail', $this->data['email'], 'email', [
-                                                       'class' => 'mw-ui-input loginText',
-                                                       'id' => 'wpEmail',
-                                                       'tabindex' => '6',
-                                                       'size' => '20',
-                                                       'required' => $this->data['emailrequired'],
-                                                       'placeholder' => $this->getMsg( $this->data['loggedin'] ?
-                                                               'createacct-another-email-ph' : 'createacct-email-ph' )->text()
-                                               ] );
-                                       ?>
-                               <?php } ?>
-                       </div>
-
-                       <?php if ( $this->data['userealname'] ) { ?>
-                               <div class="mw-ui-vform-field">
-                                       <label for='wpRealName'><?php $this->msg( 'createacct-realname' ); ?></label>
-                                       <input type='text' class='mw-ui-input loginText' name="wpRealName" id="wpRealName"
-                                               tabindex="7"
-                                               value="<?php $this->text( 'realname' ); ?>" size='20' />
-                                       <div class="prefsectiontip">
-                                               <?php $this->msgWiki( $this->data['loggedin'] ? 'createacct-another-realname-tip' : 'prefs-help-realname' ); ?>
-                                       </div>
-                               </div>
-                       <?php } ?>
-
-                       <?php if ( $this->data['usereason'] ) { ?>
-                               <div class="mw-ui-vform-field">
-                                       <label for='wpReason'><?php $this->msg( 'createacct-reason' ); ?></label>
-                                       <?php echo Html::input( 'wpReason', $this->data['reason'], 'text', [
-                                               'class' => 'mw-ui-input loginText',
-                                               'id' => 'wpReason',
-                                               'tabindex' => '8',
-                                               'size' => '20',
-                                               'placeholder' => $this->getMsg( 'createacct-reason-ph' )->text()
-                                       ] ); ?>
-                               </div>
-                       <?php } ?>
-
-                       <?php
-                       $tabIndex = 9;
-                       if ( isset( $this->data['extraInput'] ) && is_array( $this->data['extraInput'] ) ) {
-                               foreach ( $this->data['extraInput'] as $inputItem ) { ?>
-                                       <div class="mw-ui-vform-field">
-                                               <?php
-                                               // If it's a checkbox, output the whole thing (assume it has a msg).
-                                               if ( $inputItem['type'] == 'checkbox' ) {
-                                               ?>
-                                                       <div class="mw-ui-checkbox">
-                                                               <input
-                                                                       name="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"
-                                                                       id="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"
-                                                                       type="checkbox" value="1"
-                                                                       tabindex="<?php echo $tabIndex++; ?>"
-                                                                       <?php if ( !empty( $inputItem['value'] ) ) {
-                                                                               echo 'checked="checked"';
-                                                                       } ?>
-                                                               ><label for="<?php echo htmlspecialchars( $inputItem['name'] ); ?>">
-                                                                       <?php $this->msg( $inputItem['msg'] ); ?>
-                                                               </label>
-                                                       </div>
-                                               <?php
-                                               } else {
-                                                       // Not a checkbox.
-                                                       // TODO (bug 31909) support other input types, e.g. select boxes.
-                                               ?>
-                                                       <?php if ( !empty( $inputItem['msg'] ) ) { ?>
-                                                               <label for="<?php echo htmlspecialchars( $inputItem['name'] ); ?>">
-                                                                       <?php $this->msgWiki( $inputItem['msg'] ); ?>
-                                                               </label>
-                                                       <?php } ?>
-                                                       <input
-                                                               type="<?php echo htmlspecialchars( $inputItem['type'] ); ?>"
-                                                               class="mw-ui-input"
-                                                               name="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"
-                                                               tabindex="<?php echo $tabIndex++; ?>"
-                                                               value="<?php echo htmlspecialchars( $inputItem['value'] ); ?>"
-                                                               id="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"
-                                                       />
-                                               <?php } ?>
-                                               <?php if ( $inputItem['helptext'] !== false ) { ?>
-                                                       <div class="prefsectiontip">
-                                                               <?php $this->msgWiki( $inputItem['helptext'] ); ?>
-                                                       </div>
-                                               <?php } ?>
-                                       </div>
-                               <?php
-                               }
-                       }
-
-                       // A separate placeholder for any inserting any extrafields, e.g used by ConfirmEdit extension
-                       if ( $this->haveData( 'extrafields' ) ) {
-                               echo $this->data['extrafields'];
-                       }
-                       // skip one index.
-                       $tabIndex++;
-                       ?>
-                       <div class="mw-ui-vform-field mw-submit">
-                               <?php
-                               echo Html::submitButton(
-                                       $this->getMsg( $this->data['loggedin'] ? 'createacct-another-submit' : 'createacct-submit' ),
-                                       [
-                                               'id' => 'wpCreateaccount',
-                                               'name' => 'wpCreateaccount',
-                                               'tabindex' => $tabIndex++
-                                       ],
-                                       [
-                                               'mw-ui-block',
-                                               'mw-ui-constructive',
-                                       ]
-                               );
-                               ?>
-                       </div>
-                       <?php if ( $this->haveData( 'uselang' ) ) { ?><input type="hidden" name="uselang" value="<?php $this->text( 'uselang' ); ?>" /><?php } ?>
-                       <?php if ( $this->haveData( 'token' ) ) { ?><input type="hidden" name="wpCreateaccountToken" value="<?php $this->text( 'token' ); ?>" /><?php } ?>
-               </form>
-               <?php if ( !wfMessage( 'signupend' )->isDisabled() ) { ?>
-                       <div id="signupend"><?php $this->html( 'signupend' ); ?></div>
-               <?php } ?>
-       </div>
-       <div class="mw-createacct-benefits-container">
-               <h2><?php $this->msg( 'createacct-benefit-heading' ); ?></h2>
-               <div class="mw-createacct-benefits-list">
-                       <?php
-                       for ( $benefitIdx = 1; $benefitIdx <= $this->data['benefitCount']; $benefitIdx++ ) {
-                               // Pass each benefit's head text (by default a number) as a parameter to the body's message for PLURAL handling.
-                               $headUnescaped = $this->getMsg( "createacct-benefit-head$benefitIdx" )->text();
-                       ?>
-                               <div class="mw-number-text <?php $this->msg( "createacct-benefit-icon$benefitIdx" ); ?>">
-                                       <h3><?php $this->msg( "createacct-benefit-head$benefitIdx" ); ?></h3>
-                                       <p><?php echo $this->getMsg( "createacct-benefit-body$benefitIdx" )->params( $headUnescaped )->escaped(); ?></p>
-                               </div>
-                       <?php } ?>
-               </div>
-       </div>
-</div>
-<?php
-
-       }
-}
diff --git a/includes/templates/Userlogin.php b/includes/templates/Userlogin.php
deleted file mode 100644 (file)
index e816b62..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-<?php
-// @codingStandardsIgnoreFile
-/**
- * HTML form for user login (since 1.22 with VForm appearance).
- *
- * 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 Templates
- * @deprecated Will be removed when AuthManager lands.
- *   The login form will be generated via HTMLForm.
- */
-
-class UserloginTemplate extends BaseTemplate {
-
-       function execute() {
-               global $wgCookieExpiration;
-               $expirationDays = ceil( $wgCookieExpiration / ( 3600 * 24 ) );
-?>
-<div class="mw-ui-container">
-       <div id="userloginprompt"><?php $this->msgWiki('loginprompt') ?></div>
-       <?php if ( $this->haveData( 'languages' ) ) { ?>
-               <div id="languagelinks">
-                       <p><?php $this->html( 'languages' ); ?></p>
-               </div>
-       <?php } ?>
-       <div id="userloginForm">
-               <form name="userlogin" class="mw-ui-vform" method="post" action="<?php $this->text( 'action' ); ?>">
-                       <?php if ( $this->data['loggedin'] ) { ?>
-                               <div class="warningbox">
-                                       <?php echo $this->getMsg( 'userlogin-loggedin' )->params( $this->data['loggedinuser'] )->parse(); ?>
-                               </div>
-                       <?php } ?>
-                       <section class="mw-form-header">
-                               <?php $this->html( 'header' ); /* extensions such as ConfirmEdit add form HTML here */ ?>
-                       </section>
-
-                       <?php if ( $this->data['message'] ) { ?>
-                               <div class="<?php $this->text( 'messagetype' ); ?>box">
-                                       <?php if ( $this->data['messagetype'] == 'error' ) { ?>
-                                               <strong><?php $this->msg( 'loginerror' ); ?></strong>
-                                               <br />
-                                       <?php } ?>
-                                       <?php $this->html( 'message' ); ?>
-                               </div>
-                       <?php } ?>
-
-                       <?php if ( $this->data['formheader'] ) { ?>
-                               <div class="mw-form-formheader">
-                                       <?php $this->html( 'formheader' ); /* extensions such as MobileFrontend add HTML here */ ?>
-                               </div>
-                       <?php } ?>
-                       <div class="mw-ui-vform-field">
-                               <label for="wpName1">
-                                       <?php
-                                       $this->msg( 'userlogin-yourname' );
-
-                                       if ( $this->data['secureLoginUrl'] ) {
-                                               echo Html::element( 'a', [
-                                                       'href' => $this->data['secureLoginUrl'],
-                                                       'class' => 'mw-ui-flush-right mw-secure',
-                                               ], $this->getMsg( 'userlogin-signwithsecure' )->text() );
-                                       }
-                                       ?>
-                               </label>
-                               <?php
-                               echo Html::input( 'wpName', $this->data['name'], 'text', [
-                                       'class' => 'loginText mw-ui-input',
-                                       'id' => 'wpName1',
-                                       'tabindex' => '1',
-                                       // 'required' is blacklisted for now in Html.php due to browser issues.
-                                       // Keeping here in case that changes.
-                                       'required' => true,
-                                       // Set focus to this field if it's blank.
-                                       'autofocus' => !$this->data['name'],
-                                       'placeholder' => $this->getMsg( 'userlogin-yourname-ph' )->text()
-                               ] );
-                               ?>
-                       </div>
-
-                       <div class="mw-ui-vform-field">
-                               <label for="wpPassword1">
-                                       <?php
-                                       $this->msg( 'userlogin-yourpassword' );
-                                       ?>
-                               </label>
-                               <?php
-                               echo Html::input( 'wpPassword', null, 'password', [
-                                       'class' => 'loginPassword mw-ui-input',
-                                       'id' => 'wpPassword1',
-                                       'tabindex' => '2',
-                                       // Set focus to this field if username is filled in.
-                                       'autofocus' => (bool)$this->data['name'],
-                                       'placeholder' => $this->getMsg( 'userlogin-yourpassword-ph' )->text()
-                               ] );
-                               ?>
-                       </div>
-
-                       <?php
-                       if ( isset( $this->data['usedomain'] ) && $this->data['usedomain'] ) {
-                               $select = new XmlSelect( 'wpDomain', false, $this->data['domain'] );
-                               $select->setAttribute( 'tabindex', 3 );
-                               foreach ( $this->data['domainnames'] as $dom ) {
-                                       $select->addOption( $dom );
-                               }
-                       ?>
-                               <div class="mw-ui-vform-field" id="mw-user-domain-section">
-                                       <label for="wpDomain"><?php $this->msg( 'yourdomainname' ); ?></label>
-                                       <?php echo $select->getHTML(); ?>
-                               </div>
-                       <?php } ?>
-
-                       <?php
-                       if ( $this->haveData( 'extrafields' ) ) {
-                               echo $this->data['extrafields'];
-                       }
-                       ?>
-
-                       <div class="mw-ui-vform-field">
-                               <?php if ( $this->data['canremember'] ) { ?>
-                                       <div class="mw-ui-checkbox">
-                                               <input name="wpRemember" type="checkbox" value="1" id="wpRemember" tabindex="4"
-                                                       <?php if ( $this->data['remember'] ) {
-                                                               echo 'checked="checked"';
-                                                       } ?>
-                                               ><label for="wpRemember">
-                                                       <?php echo $this->getMsg( 'userlogin-remembermypassword' )->numParams( $expirationDays )->escaped(); ?></label>
-                                       </div>
-                               <?php } ?>
-                       </div>
-
-                       <div class="mw-ui-vform-field">
-                               <?php
-                               $attrs = [
-                                       'id' => 'wpLoginAttempt',
-                                       'name' => 'wpLoginAttempt',
-                                       'tabindex' => '6',
-                               ];
-                               $modifiers = [
-                                       'mw-ui-progressive',
-                               ];
-                               echo Html::submitButton( $this->getMsg( 'pt-login-button' )->text(), $attrs, $modifiers );
-                               ?>
-                       </div>
-
-                       <div class="mw-ui-vform-field mw-form-related-link-container" id="mw-userlogin-help">
-                               <?php
-                               echo Html::element(
-                                       'a',
-                                       [
-                                               'href' => Skin::makeInternalOrExternalUrl(
-                                                       wfMessage( 'helplogin-url' )->inContentLanguage()->text()
-                                               ),
-                                       ],
-                                       $this->getMsg( 'userlogin-helplink2' )->text()
-                               );
-                               ?>
-                       </div>
-                       <?php
-
-                       if ( $this->data['useemail'] && $this->data['canreset'] && $this->data['resetlink'] === true ) {
-                               echo Html::rawElement(
-                                       'div',
-                                       [
-                                               'class' => 'mw-ui-vform-field mw-form-related-link-container',
-                                       ],
-                                       Linker::link(
-                                               SpecialPage::getTitleFor( 'PasswordReset' ),
-                                               $this->getMsg( 'userlogin-resetpassword-link' )->escaped()
-                                       )
-                               );
-                       }
-
-                       if ( $this->haveData( 'createOrLoginHref' ) ) {
-                               if ( $this->data['loggedin'] ) { ?>
-                                       <div class="mw-form-related-link-container mw-ui-vform-field">
-                                               <a href="<?php $this->text( 'createOrLoginHref' ); ?>" id="mw-createaccount-join" tabindex="7"><?php $this->msg( 'userlogin-createanother' ); ?></a>
-                                       </div>
-                               <?php } else { ?>
-                                       <div id="mw-createaccount-cta" class="mw-ui-vform-field">
-                                               <?php $this->msg( 'userlogin-noaccount' ); ?><a href="<?php $this->text( 'createOrLoginHref' ); ?>" id="mw-createaccount-join" tabindex="7" class="mw-ui-button"><?php $this->msg( 'userlogin-joinproject' ); ?></a>
-                                       </div>
-                               <?php
-                               }
-                       }
-
-                       // Hidden fields
-                       $fields = '';
-                       if ( $this->haveData( 'uselang' ) ) {
-                               $fields .= Html::hidden( 'uselang', $this->data['uselang'] );
-                       }
-                       if ( $this->haveData( 'token' ) ) {
-                               $fields .= Html::hidden( 'wpLoginToken', $this->data['token'] );
-                       }
-                       if ( $this->data['cansecurelogin'] ) {
-                               $fields .= Html::hidden( 'wpForceHttps', $this->data['stickhttps'] );
-                       }
-                       if ( $this->data['cansecurelogin'] && $this->haveData( 'fromhttp' ) ) {
-                               $fields .= Html::hidden( 'wpFromhttp', $this->data['fromhttp'] );
-                       }
-                       echo $fields;
-
-                       ?>
-               </form>
-       </div>
-</div>
-<?php
-
-       }
-}
index b2d6ba1..666f3f9 100644 (file)
@@ -32,31 +32,31 @@ use \IteratorAggregate;
 use \ReverseArrayIterator;
 use \Sanitizer;
 
-# A note for future librarization[1] -- this file is a good candidate
-# for splitting into an independent library, except that it is currently
-# highly optimized for MediaWiki use.  It only implements the portions
-# of the HTML5 tree builder used by tags supported by MediaWiki, and
-# does not contain a true tokenizer pass, instead relying on
-# comment stripping, attribute normalization, and escaping done by
-# the MediaWiki Sanitizer.  It also deliberately avoids building
-# a true DOM in memory, instead serializing elements to an output string
-# as soon as possible (usually as soon as the tag is closed) to reduce
-# its memory footprint.
-
-# We've been gradually lifting some of these restrictions to handle
-# non-sanitized output generated by extensions, but we shortcut the tokenizer
-# for speed (primarily by splitting on `<`) and so rely on syntactic
-# well-formedness.
-
-# On the other hand, I've been pretty careful to note with comments in the
-# code the places where this implementation omits features of the spec or
-# depends on the MediaWiki Sanitizer.  Perhaps in the future we'll want to
-# implement the missing pieces and make this a standalone PHP HTML5 parser.
-# In order to do so, some sort of MediaWiki-specific API will need
-# to be added to (a) allow the Balancer to bypass the tokenizer,
-# and (b) support on-the-fly flattening instead of DOM node creation.
-
-# [1]: https://www.mediawiki.org/wiki/Library_infrastructure_for_MediaWiki
+// A note for future librarization[1] -- this file is a good candidate
+// for splitting into an independent library, except that it is currently
+// highly optimized for MediaWiki use.  It only implements the portions
+// of the HTML5 tree builder used by tags supported by MediaWiki, and
+// does not contain a true tokenizer pass, instead relying on
+// comment stripping, attribute normalization, and escaping done by
+// the MediaWiki Sanitizer.  It also deliberately avoids building
+// a true DOM in memory, instead serializing elements to an output string
+// as soon as possible (usually as soon as the tag is closed) to reduce
+// its memory footprint.
+
+// We've been gradually lifting some of these restrictions to handle
+// non-sanitized output generated by extensions, but we shortcut the tokenizer
+// for speed (primarily by splitting on `<`) and so rely on syntactic
+// well-formedness.
+
+// On the other hand, I've been pretty careful to note with comments in the
+// code the places where this implementation omits features of the spec or
+// depends on the MediaWiki Sanitizer.  Perhaps in the future we'll want to
+// implement the missing pieces and make this a standalone PHP HTML5 parser.
+// In order to do so, some sort of MediaWiki-specific API will need
+// to be added to (a) allow the Balancer to bypass the tokenizer,
+// and (b) support on-the-fly flattening instead of DOM node creation.
+
+// [1]: https://www.mediawiki.org/wiki/Library_infrastructure_for_MediaWiki
 
 /**
  * Utility constants and sets for the HTML5 tree building algorithm.
@@ -464,20 +464,23 @@ class BalanceElement {
         * by the HTML serialization specification, and replace this node
         * in its parent by that string.
         *
+        * @param array $config Balancer configuration; see Balancer::__construct().
+        *
         * @see __toString()
         */
-       public function flatten( $tidyCompat = false ) {
+       public function flatten( array $config ) {
                Assert::parameter( $this->parent !== null, '$this', 'must be a child' );
                Assert::parameter( $this->parent !== 'flat', '$this', 'already flat' );
                $idx = array_search( $this, $this->parent->children, true );
                Assert::parameter(
                        $idx !== false, '$this', 'must be a child of its parent'
                );
+               $tidyCompat = $config['tidyCompat'];
                if ( $tidyCompat ) {
                        $blank = true;
                        foreach ( $this->children as $elt ) {
                                if ( !is_string( $elt ) ) {
-                                       $elt = $elt->flatten( $tidyCompat );
+                                       $elt = $elt->flatten( $config );
                                }
                                if ( $blank && preg_match( '/[^\t\n\f\r ]/', $elt ) ) {
                                        $blank = false;
@@ -500,7 +503,7 @@ class BalanceElement {
                        $flat = "{$this}";
                }
                $this->parent->children[$idx] = $flat;
-               $this->parent = 'flat'; # for assertion checking
+               $this->parent = 'flat'; // for assertion checking
                return $flat;
        }
 
@@ -544,7 +547,7 @@ class BalanceElement {
                return $out;
        }
 
-       # Utility functions on BalanceElements.
+       // Utility functions on BalanceElements.
 
        /**
         * Determine if $this represents a specific HTML tag, is a member of
@@ -561,7 +564,7 @@ class BalanceElement {
                        return isset( $set[$this->namespaceURI] ) &&
                                isset( $set[$this->namespaceURI][$this->localName] );
                } else {
-                       # assume this is an HTML element name.
+                       // assume this is an HTML element name.
                        return $this->isHtml() && $this->localName === $set;
                }
        }
@@ -661,9 +664,11 @@ class BalanceStack implements IteratorAggregate {
         */
        public $fosterParentMode = false;
        /**
-        * Tidy compatibility mode, determines behavior of body/blockquote
+        * Configuration options governing flattening.
+        * @var array $config
+        * @see Balancer::__construct()
         */
-       public $tidyCompat = false;
+       private $config;
        /**
         * Reference to the current element
         */
@@ -672,14 +677,16 @@ class BalanceStack implements IteratorAggregate {
        /**
         * Create a new BalanceStack with a single BalanceElement on it,
         * representing the root &lt;html&gt; node.
+        * @param array $config Balancer configuration; see Balancer::_construct().
         */
-       public function __construct() {
-               # always a root <html> element on the stack
+       public function __construct( array $config ) {
+               // always a root <html> element on the stack
                array_push(
                        $this->elements,
                        new BalanceElement( BalanceSets::HTML_NAMESPACE, 'html', [] )
                );
                $this->currentNode = $this->elements[0];
+               $this->config = $config;
        }
 
        /**
@@ -692,7 +699,7 @@ class BalanceStack implements IteratorAggregate {
                $out = '';
                foreach ( $this->elements[0]->children as $elt ) {
                        $out .= is_string( $elt ) ? $elt :
-                               $elt->flatten( $this->tidyCompat );
+                               $elt->flatten( $this->config );
                }
                return $out;
        }
@@ -719,7 +726,7 @@ class BalanceStack implements IteratorAggregate {
                ) {
                        $this->fosterParent( $value );
                } elseif (
-                       $this->tidyCompat && !$isComment &&
+                       $this->config['tidyCompat'] && !$isComment &&
                        $this->currentNode->isA( BalanceSets::$tidyPWrapSet )
                ) {
                        $this->insertHTMLELement( 'mw:p-wrap', [] );
@@ -970,7 +977,7 @@ class BalanceStack implements IteratorAggregate {
                        $this->currentNode = null;
                }
                if ( !$elt->isHtmlNamed( 'mw:p-wrap' ) ) {
-                       $elt->flatten( $this->tidyCompat );
+                       $elt->flatten( $this->config );
                }
        }
 
@@ -980,7 +987,6 @@ class BalanceStack implements IteratorAggregate {
         * @param int $idx
         */
        public function popTo( $idx ) {
-               $length = count( $this->elements );
                for ( $length = count( $this->elements ); $length > $idx; $length-- ) {
                        $this->pop();
                }
@@ -1045,7 +1051,7 @@ class BalanceStack implements IteratorAggregate {
                        // otherwise, it will eventually serialize when the parent
                        // is serialized, we just hold onto the memory for its
                        // tree of objects a little longer.
-                       $elt->flatten( $this->tidyCompat );
+                       $elt->flatten( $this->config );
                }
                Assert::postcondition(
                        array_search( $elt, $this->elements, true ) === false,
@@ -1069,7 +1075,7 @@ class BalanceStack implements IteratorAggregate {
                }
        }
 
-       # Fostering and adoption.
+       // Fostering and adoption.
 
        /**
         * Foster parent the given $elt in the stack of open elements.
@@ -1086,7 +1092,7 @@ class BalanceStack implements IteratorAggregate {
                        $parent = $this->elements[$lastTemplate];
                } elseif ( $lastTable >= 0 ) {
                        $parent = $this->elements[$lastTable]->parent;
-                       # Assume all tables have parents, since we're not running scripts!
+                       // Assume all tables have parents, since we're not running scripts!
                        Assert::invariant(
                                $parent !== null, "All tables should have parents"
                        );
@@ -1095,7 +1101,7 @@ class BalanceStack implements IteratorAggregate {
                        $parent = $this->elements[0]; // the `html` element.
                }
 
-               if ( $this->tidyCompat ) {
+               if ( $this->config['tidyCompat'] ) {
                        if ( is_string( $elt ) ) {
                                // We're fostering text: do we need a p-wrapper?
                                if ( $parent->isA( BalanceSets::$tidyPWrapSet ) ) {
@@ -1151,34 +1157,28 @@ class BalanceStack implements IteratorAggregate {
                        return true; // no more handling required
                }
 
-               // Let outer loop counter be zero.
-               $outer = 0;
-
                // Outer loop: If outer loop counter is greater than or
                // equal to eight, then abort these steps.
-               while ( $outer < 8 ) {
-                       // Increment outer loop counter by one.
-                       $outer++;
-
+               for ( $outer = 0; $outer < 8; $outer++ ) {
                        // Let the formatting element be the last element in the list
                        // of active formatting elements that: is between the end of
                        // the list and the last scope marker in the list, if any, or
                        // the start of the list otherwise, and has the same tag name
                        // as the token.
-                       $fmtelt = $afe->findElementByTag( $tag );
+                       $fmtElt = $afe->findElementByTag( $tag );
 
                        // If there is no such node, then abort these steps and instead
                        // act as described in the "any other end tag" entry below.
-                       if ( !$fmtelt ) {
+                       if ( !$fmtElt ) {
                                return false; // false means handle by the default case
                        }
 
                        // Otherwise, if there is such a node, but that node is not in
                        // the stack of open elements, then this is a parse error;
                        // remove the element from the list, and abort these steps.
-                       $index = $this->indexOf( $fmtelt );
+                       $index = $this->indexOf( $fmtElt );
                        if ( $index < 0 ) {
-                               $afe->remove( $fmtelt );
+                               $afe->remove( $fmtElt );
                                return true;   // true means no more handling required
                        }
 
@@ -1186,7 +1186,7 @@ class BalanceStack implements IteratorAggregate {
                        // the stack of open elements, but the element is not in scope,
                        // then this is a parse error; ignore the token, and abort
                        // these steps.
-                       if ( !$this->inScope( $fmtelt ) ) {
+                       if ( !$this->inScope( $fmtElt ) ) {
                                return true;
                        }
 
@@ -1194,13 +1194,13 @@ class BalanceStack implements IteratorAggregate {
                        // open elements that is lower in the stack than the formatting
                        // element, and is an element in the special category. There
                        // might not be one.
-                       $furthestblock = null;
-                       $furthestblockindex = -1;
-                       $stacklen = $this->length();
-                       for ( $i = $index+1; $i < $stacklen; $i++ ) {
+                       $furthestBlock = null;
+                       $furthestBlockIndex = -1;
+                       $stackLength = $this->length();
+                       for ( $i = $index+1; $i < $stackLength; $i++ ) {
                                if ( $this->node( $i )->isA( BalanceSets::$specialSet ) ) {
-                                       $furthestblock = $this->node( $i );
-                                       $furthestblockindex = $i;
+                                       $furthestBlock = $this->node( $i );
+                                       $furthestBlockIndex = $i;
                                        break;
                                }
                        }
@@ -1211,140 +1211,134 @@ class BalanceStack implements IteratorAggregate {
                        // up to and including the formatting element, and remove the
                        // formatting element from the list of active formatting
                        // elements.
-                       if ( !$furthestblock ) {
-                               $this->popTag( $fmtelt );
-                               $afe->remove( $fmtelt );
-                               return true;
-                       } else {
-                               // Let the common ancestor be the element immediately above
-                               // the formatting element in the stack of open elements.
-                               $ancestor = $this->node( $index-1 );
-
-                               // Let a bookmark note the position of the formatting
-                               // element in the list of active formatting elements
-                               // relative to the elements on either side of it in the
-                               // list.
-                               $BOOKMARK = new BalanceElement( '[bookmark]', '[bookmark]', [] );
-                               $afe->insertAfter( $fmtelt, $BOOKMARK );
-
-                               // Let node and last node be the furthest block.
-                               $node = $furthestblock;
-                               $lastnode = $furthestblock;
-                               $nodeindex = $furthestblockindex;
-                               $isAFE = false;
-
-                               // Let inner loop counter be zero.
-                               $inner = 0;
-
-                               while ( true ) {
-
-                                       // Increment inner loop counter by one.
-                                       $inner++;
-
-                                       // Let node be the element immediately above node in
-                                       // the stack of open elements, or if node is no longer
-                                       // in the stack of open elements (e.g. because it got
-                                       // removed by this algorithm), the element that was
-                                       // immediately above node in the stack of open elements
-                                       // before node was removed.
-                                       $node = $this->node( --$nodeindex );
-
-                                       // If node is the formatting element, then go
-                                       // to the next step in the overall algorithm.
-                                       if ( $node === $fmtelt ) break;
-
-                                       // If the inner loop counter is greater than three and node
-                                       // is in the list of active formatting elements, then remove
-                                       // node from the list of active formatting elements.
-                                       $isAFE = $afe->isInList( $node );
-                                       if ( $inner > 3 && $isAFE ) {
-                                               $afe->remove( $node );
-                                               $isAFE = false;
-                                       }
-
-                                       // If node is not in the list of active formatting
-                                       // elements, then remove node from the stack of open
-                                       // elements and then go back to the step labeled inner
-                                       // loop.
-                                       if ( !$isAFE ) {
-                                               // Don't flatten here, since we're about to relocate
-                                               // parts of this $node.
-                                               $this->removeElement( $node, false );
-                                               continue;
-                                       }
-
-                                       // Create an element for the token for which the
-                                       // element node was created with common ancestor as
-                                       // the intended parent, replace the entry for node
-                                       // in the list of active formatting elements with an
-                                       // entry for the new element, replace the entry for
-                                       // node in the stack of open elements with an entry for
-                                       // the new element, and let node be the new element.
-                                       $newelt = new BalanceElement(
-                                               $node->namespaceURI, $node->localName, $node->attribs );
-                                       $afe->replace( $node, $newelt );
-                                       $this->replaceAt( $nodeindex, $newelt );
-                                       $node = $newelt;
-
-                                       // If last node is the furthest block, then move the
-                                       // aforementioned bookmark to be immediately after the
-                                       // new node in the list of active formatting elements.
-                                       if ( $lastnode === $furthestblock ) {
-                                               $afe->remove( $BOOKMARK );
-                                               $afe->insertAfter( $newelt, $BOOKMARK );
-                                       }
-
-                                       // Insert last node into node, first removing it from
-                                       // its previous parent node if any.
-                                       $node->appendChild( $lastnode );
-
-                                       // Let last node be node.
-                                       $lastnode = $node;
-                               }
-
-                               // If the common ancestor node is a table, tbody, tfoot,
-                               // thead, or tr element, then, foster parent whatever last
-                               // node ended up being in the previous step, first removing
-                               // it from its previous parent node if any.
-                               if (
-                                       $this->fosterParentMode &&
-                                       $ancestor->isA( BalanceSets::$tableSectionRowSet )
-                               ) {
-                                       $this->fosterParent( $lastnode );
-                               } else {
-                                       // Otherwise, append whatever last node ended up being in
-                                       // the previous step to the common ancestor node, first
-                                       // removing it from its previous parent node if any.
-                                       $ancestor->appendChild( $lastnode );
+                       if ( !$furthestBlock ) {
+                               $this->popTag( $fmtElt );
+                               $afe->remove( $fmtElt );
+                               return true;
+                       }
+
+                       // Let the common ancestor be the element immediately above
+                       // the formatting element in the stack of open elements.
+                       $ancestor = $this->node( $index-1 );
+
+                       // Let a bookmark note the position of the formatting
+                       // element in the list of active formatting elements
+                       // relative to the elements on either side of it in the
+                       // list.
+                       $BOOKMARK = new BalanceElement( '[bookmark]', '[bookmark]', [] );
+                       $afe->insertAfter( $fmtElt, $BOOKMARK );
+
+                       // Let node and last node be the furthest block.
+                       $node = $furthestBlock;
+                       $lastNode = $furthestBlock;
+                       $nodeIndex = $furthestBlockIndex;
+                       $isAFE = false;
+
+                       // Inner loop
+                       for ( $inner = 1; true; $inner++ ) {
+                               // Let node be the element immediately above node in
+                               // the stack of open elements, or if node is no longer
+                               // in the stack of open elements (e.g. because it got
+                               // removed by this algorithm), the element that was
+                               // immediately above node in the stack of open elements
+                               // before node was removed.
+                               $node = $this->node( --$nodeIndex );
+
+                               // If node is the formatting element, then go
+                               // to the next step in the overall algorithm.
+                               if ( $node === $fmtElt ) break;
+
+                               // If the inner loop counter is greater than three and node
+                               // is in the list of active formatting elements, then remove
+                               // node from the list of active formatting elements.
+                               $isAFE = $afe->isInList( $node );
+                               if ( $inner > 3 && $isAFE ) {
+                                       $afe->remove( $node );
+                                       $isAFE = false;
+                               }
+
+                               // If node is not in the list of active formatting
+                               // elements, then remove node from the stack of open
+                               // elements and then go back to the step labeled inner
+                               // loop.
+                               if ( !$isAFE ) {
+                                       // Don't flatten here, since we're about to relocate
+                                       // parts of this $node.
+                                       $this->removeElement( $node, false );
+                                       continue;
                                }
 
                                // Create an element for the token for which the
-                               // formatting element was created, with furthest block
-                               // as the intended parent.
-                               $newelt2 = new BalanceElement(
-                                       $fmtelt->namespaceURI, $fmtelt->localName, $fmtelt->attribs );
+                               // element node was created with common ancestor as
+                               // the intended parent, replace the entry for node
+                               // in the list of active formatting elements with an
+                               // entry for the new element, replace the entry for
+                               // node in the stack of open elements with an entry for
+                               // the new element, and let node be the new element.
+                               $newElt = new BalanceElement(
+                                       $node->namespaceURI, $node->localName, $node->attribs );
+                               $afe->replace( $node, $newElt );
+                               $this->replaceAt( $nodeIndex, $newElt );
+                               $node = $newElt;
+
+                               // If last node is the furthest block, then move the
+                               // aforementioned bookmark to be immediately after the
+                               // new node in the list of active formatting elements.
+                               if ( $lastNode === $furthestBlock ) {
+                                       $afe->remove( $BOOKMARK );
+                                       $afe->insertAfter( $newElt, $BOOKMARK );
+                               }
+
+                               // Insert last node into node, first removing it from
+                               // its previous parent node if any.
+                               $node->appendChild( $lastNode );
+
+                               // Let last node be node.
+                               $lastNode = $node;
+                       }
+
+                       // If the common ancestor node is a table, tbody, tfoot,
+                       // thead, or tr element, then, foster parent whatever last
+                       // node ended up being in the previous step, first removing
+                       // it from its previous parent node if any.
+                       if (
+                               $this->fosterParentMode &&
+                               $ancestor->isA( BalanceSets::$tableSectionRowSet )
+                       ) {
+                               $this->fosterParent( $lastNode );
+                       } else {
+                               // Otherwise, append whatever last node ended up being in
+                               // the previous step to the common ancestor node, first
+                               // removing it from its previous parent node if any.
+                               $ancestor->appendChild( $lastNode );
+                       }
 
-                               // Take all of the child nodes of the furthest block and
-                               // append them to the element created in the last step.
-                               $newelt2->adoptChildren( $furthestblock );
+                       // Create an element for the token for which the
+                       // formatting element was created, with furthest block
+                       // as the intended parent.
+                       $newElt2 = new BalanceElement(
+                               $fmtElt->namespaceURI, $fmtElt->localName, $fmtElt->attribs );
 
-                               // Append that new element to the furthest block.
-                               $furthestblock->appendChild( $newelt2 );
+                       // Take all of the child nodes of the furthest block and
+                       // append them to the element created in the last step.
+                       $newElt2->adoptChildren( $furthestBlock );
 
-                               // Remove the formatting element from the list of active
-                               // formatting elements, and insert the new element into the
-                               // list of active formatting elements at the position of
-                               // the aforementioned bookmark.
-                               $afe->remove( $fmtelt );
-                               $afe->replace( $BOOKMARK, $newelt2 );
+                       // Append that new element to the furthest block.
+                       $furthestBlock->appendChild( $newElt2 );
 
-                               // Remove the formatting element from the stack of open
-                               // elements, and insert the new element into the stack of
-                               // open elements immediately below the position of the
-                               // furthest block in that stack.
-                               $this->removeElement( $fmtelt );
-                               $this->insertAfter( $furthestblock, $newelt2 );
-                       }
+                       // Remove the formatting element from the list of active
+                       // formatting elements, and insert the new element into the
+                       // list of active formatting elements at the position of
+                       // the aforementioned bookmark.
+                       $afe->remove( $fmtElt );
+                       $afe->replace( $BOOKMARK, $newElt2 );
+
+                       // Remove the formatting element from the stack of open
+                       // elements, and insert the new element into the stack of
+                       // open elements immediately below the position of the
+                       // furthest block in that stack.
+                       $this->removeElement( $fmtElt );
+                       $this->insertAfter( $furthestBlock, $newElt2 );
                }
 
                return true;
@@ -1677,11 +1671,11 @@ class BalanceActiveFormattingElements {
 
                // Loop backward through the list until we find a marker or an
                // open element
-               $foundit = false;
+               $foundIt = false;
                while ( $entry->prevAFE ) {
                        $entry = $entry->prevAFE;
                        if ( $entry instanceof BalanceMarker || $stack->indexOf( $entry ) >= 0 ) {
-                               $foundit = true;
+                               $foundIt = true;
                                break;
                        }
                }
@@ -1690,7 +1684,7 @@ class BalanceActiveFormattingElements {
                // the first element if we didn't find a marker or open element),
                // recreating formatting elements and pushing them back onto the list
                // of open elements.
-               if ( $foundit ) {
+               if ( $foundIt ) {
                        $entry = $entry->nextAFE;
                }
                do {
@@ -1771,7 +1765,7 @@ class BalanceActiveFormattingElements {
  *     <style>/<noframes> want RAWTEXT modes which we only loosely emulate.)
  *
  *   We generally mark places where we omit cases from the spec due to
- *   disallowed elements with a comment: `# OMITTED: <element-name>`.
+ *   disallowed elements with a comment: `// OMITTED: <element-name>`.
  *
  *   The HTML spec keeps a flag during the parsing process to track
  *   whether or not a "parse error" has been encountered.  We don't
@@ -1789,8 +1783,8 @@ class Balancer {
        private $afe;
        private $stack;
        private $strict;
-       private $tidyCompat;
        private $allowComments;
+       private $config;
 
        private $textIntegrationMode;
        private $pendingTableText;
@@ -1857,7 +1851,7 @@ class Balancer {
         *         false to get a bit more performance.
         */
        public function __construct( array $config = [] ) {
-               $config = $config + [
+               $this->config = $config = $config + [
                        'strict' => false,
                        'allowedHtmlElements' => null,
                        'tidyCompat' => false,
@@ -1865,10 +1859,9 @@ class Balancer {
                ];
                $this->allowedHtmlElements = $config['allowedHtmlElements'];
                $this->strict = $config['strict'];
-               $this->tidyCompat = $config['tidyCompat'];
                $this->allowComments = $config['allowComments'];
                if ( $this->allowedHtmlElements !== null ) {
-                       # Sanity check!
+                       // Sanity check!
                        $bad = array_uintersect_assoc(
                                $this->allowedHtmlElements,
                                BalanceSets::$unsupportedSet[BalanceSets::HTML_NAMESPACE],
@@ -1905,8 +1898,7 @@ class Balancer {
                $this->parseMode = 'inBodyMode';
                $this->bitsIterator = new ExplodeIterator( '<', $text );
                $this->afe = new BalanceActiveFormattingElements();
-               $this->stack = new BalanceStack();
-               $this->stack->tidyCompat = $this->tidyCompat;
+               $this->stack = new BalanceStack( $this->config );
                $this->processingCallback = $processingCallback;
                $this->processingArgs = $processingArgs;
 
@@ -1915,8 +1907,8 @@ class Balancer {
                        $this->inRCDATA =
                        $this->inRAWTEXT = false;
 
-               # The stack is constructed with an <html> element already on it.
-               # Set this up as a fragment parsed with <body> as the context.
+               // The stack is constructed with an <html> element already on it.
+               // Set this up as a fragment parsed with <body> as the context.
                $this->fragmentContext =
                        new BalanceElement( BalanceSets::HTML_NAMESPACE, 'body', [] );
                $this->resetInsertionMode();
@@ -1951,12 +1943,12 @@ class Balancer {
         * Pass a token to the tree builder.  The $token will be one of the
         * strings "tag", "endtag", or "text".
         */
-       private function insertToken( $token, $value, $attribs = null, $selfclose = false ) {
+       private function insertToken( $token, $value, $attribs = null, $selfClose = false ) {
                // validate tags against $unsupportedSet
                if ( $token === 'tag' || $token === 'endtag' ) {
                        if ( isset( BalanceSets::$unsupportedSet[BalanceSets::HTML_NAMESPACE][$value] ) ) {
-                               # As described in "simplifications" above, these tags are
-                               # not supported in the balancer.
+                               // As described in "simplifications" above, these tags are
+                               // not supported in the balancer.
                                Assert::invariant(
                                        !$this->strict,
                                        "Unsupported $token <$value> found."
@@ -1964,7 +1956,7 @@ class Balancer {
                                return false;
                        }
                } elseif ( $token === 'text' && $value === '' ) {
-                       # Don't actually inject the empty string as a text token.
+                       // Don't actually inject the empty string as a text token.
                        return true;
                }
                // Support pre/listing/textarea by suppressing initial linefeed
@@ -1973,7 +1965,7 @@ class Balancer {
                        if ( $token === 'text' ) {
                                if ( $value[0] === "\n" ) {
                                        if ( $value === "\n" ) {
-                                               # Nothing would be left, don't inject the empty string.
+                                               // Nothing would be left, don't inject the empty string.
                                                return true;
                                        }
                                        $value = substr( $value, 1 );
@@ -2012,14 +2004,14 @@ class Balancer {
                        $isForeign = false;
                }
                if ( $isForeign ) {
-                       return $this->insertForeignToken( $token, $value, $attribs, $selfclose );
+                       return $this->insertForeignToken( $token, $value, $attribs, $selfClose );
                } else {
                        $func = $this->parseMode;
-                       return $this->$func( $token, $value, $attribs, $selfclose );
+                       return $this->$func( $token, $value, $attribs, $selfClose );
                }
        }
 
-       private function insertForeignToken( $token, $value, $attribs = null, $selfclose = false ) {
+       private function insertForeignToken( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        $this->stack->insertText( $value );
                        return true;
@@ -2032,7 +2024,7 @@ class Balancer {
                                ) {
                                        break;
                                }
-                               /* otherwise, fall through */
+                               // otherwise, fall through
                        case 'b':
                        case 'big':
                        case 'blockquote':
@@ -2091,7 +2083,7 @@ class Balancer {
                                                break;
                                        }
                                }
-                               return $this->insertToken( $token, $value, $attribs, $selfclose );
+                               return $this->insertToken( $token, $value, $attribs, $selfClose );
                        }
                        // "Any other start tag"
                        $adjusted = ( $this->fragmentContext && $this->stack->length()===1 ) ?
@@ -2099,7 +2091,7 @@ class Balancer {
                        $this->stack->insertForeignElement(
                                $adjusted->namespaceURI, $value, $attribs
                        );
-                       if ( $selfclose ) {
+                       if ( $selfClose ) {
                                $this->stack->pop();
                        }
                        return true;
@@ -2109,7 +2101,7 @@ class Balancer {
                                if ( $node->isHtml() && !$first ) {
                                        // process the end tag as HTML
                                        $func = $this->parseMode;
-                                       return $this->$func( $token, $value, $attribs, $selfclose );
+                                       return $this->$func( $token, $value, $attribs, $selfClose );
                                } elseif ( $i === 0 ) {
                                        return true;
                                } elseif ( $node->localName === $value ) {
@@ -2129,13 +2121,13 @@ class Balancer {
                $x = $this->bitsIterator->current();
                $this->bitsIterator->next();
                $regs = [];
-               # Handle comments.  These won't be generated by mediawiki (they
-               # are stripped in the Sanitizer) but may be generated by extensions.
+               // Handle comments.  These won't be generated by mediawiki (they
+               // are stripped in the Sanitizer) but may be generated by extensions.
                if (
                        $this->allowComments &&
                        !( $this->inRCDATA || $this->inRAWTEXT ) &&
                        preg_match( Balancer::VALID_COMMENT_REGEX, $x, $regs, PREG_OFFSET_CAPTURE ) &&
-                       /* verify EOF condition where necessary */
+                       // verify EOF condition where necessary
                        ( $regs[4][1] < 0 || !$this->bitsIterator->valid() )
                ) {
                        $contents = $regs[2][0];
@@ -2144,16 +2136,16 @@ class Balancer {
                        $this->insertToken( 'text', str_replace( '>', '&gt;', $rest ) );
                        return;
                }
-               # $slash: Does the current element start with a '/'?
-               # $t: Current element name
-               # $attribStr: String between element name and >
-               # $brace: Ending '>' or '/>'
-               # $rest: Everything until the next element from the $bitsIterator
+               // $slash: Does the current element start with a '/'?
+               // $t: Current element name
+               // $attribStr: String between element name and >
+               // $brace: Ending '>' or '/>'
+               // $rest: Everything until the next element from the $bitsIterator
                if ( preg_match( Sanitizer::ELEMENT_BITS_REGEX, $x, $regs ) ) {
                        list( /* $qbar */, $slash, $t, $attribStr, $brace, $rest ) = $regs;
                        $t = strtolower( $t );
                        if ( $this->strict ) {
-                               /* Verify that attributes are all properly double-quoted */
+                               // Verify that attributes are all properly double-quoted
                                Assert::invariant(
                                        preg_match(
                                                '/^( [:_A-Z0-9][-.:_A-Z0-9]*="[^"]*")*[ ]*$/i', $attribStr
@@ -2167,13 +2159,13 @@ class Balancer {
                        );
                        $slash = $t = $attribStr = $brace = $rest = null;
                }
-               $goodtag = $t;
+               $goodTag = $t;
                if ( $this->inRCDATA ) {
                        if ( $slash && $t === $this->inRCDATA ) {
                                $this->inRCDATA = false;
                        } else {
                                // No tags allowed; this emulates the "rcdata" tokenizer mode.
-                               $goodtag = false;
+                               $goodTag = false;
                        }
                }
                if ( $this->inRAWTEXT ) {
@@ -2181,39 +2173,39 @@ class Balancer {
                                $this->inRAWTEXT = false;
                        } else {
                                // No tags allowed, no entity-escaping done.
-                               $goodtag = false;
+                               $goodTag = false;
                        }
                }
                $sanitize = $this->allowedHtmlElements !== null;
                if ( $sanitize ) {
-                       $goodtag = $t && isset( $this->allowedHtmlElements[$t] );
+                       $goodTag = $t && isset( $this->allowedHtmlElements[$t] );
                }
-               if ( $goodtag ) {
+               if ( $goodTag ) {
                        if ( is_callable( $this->processingCallback ) ) {
                                call_user_func_array( $this->processingCallback, [ &$attribStr, $this->processingArgs ] );
                        }
                        if ( $sanitize ) {
-                               $goodtag = Sanitizer::validateTag( $attribStr, $t );
+                               $goodTag = Sanitizer::validateTag( $attribStr, $t );
                        }
                }
-               if ( $goodtag ) {
+               if ( $goodTag ) {
                        if ( $sanitize ) {
                                $attribs = Sanitizer::decodeTagAttributes( $attribStr );
                                $attribs = Sanitizer::validateTagAttributes( $attribs, $t );
                        } else {
                                $attribs = Sanitizer::decodeTagAttributes( $attribStr );
                        }
-                       $goodtag = $this->insertToken(
+                       $goodTag = $this->insertToken(
                                $slash ? 'endtag' : 'tag', $t, $attribs, $brace === '/>'
                        );
                }
-               if ( $goodtag ) {
+               if ( $goodTag ) {
                        $rest = str_replace( '>', '&gt;', $rest );
                        $this->insertToken( 'text', str_replace( '>', '&gt;', $rest ) );
                } elseif ( $this->inRAWTEXT ) {
                        $this->insertToken( 'text', "<$x" );
                } else {
-                       # bad tag; serialize entire thing as text.
+                       // bad tag; serialize entire thing as text.
                        $this->insertToken( 'text', '&lt;' . str_replace( '>', '&gt;', $x ) );
                }
        }
@@ -2227,9 +2219,9 @@ class Balancer {
                return $oldMode;
        }
 
-       private function switchModeAndReprocess( $mode, $token, $value, $attribs, $selfclose ) {
+       private function switchModeAndReprocess( $mode, $token, $value, $attribs, $selfClose ) {
                $this->switchMode( $mode );
-               return $this->insertToken( $token, $value, $attribs, $selfclose );
+               return $this->insertToken( $token, $value, $attribs, $selfClose );
        }
 
        private function resetInsertionMode() {
@@ -2244,9 +2236,9 @@ class Balancer {
                        if ( $node->isHtml() ) {
                                switch ( $node->localName ) {
                                case 'select':
-                                       $stacklen = $this->stack->length();
-                                       for ( $j = $i + 1; $j < $stacklen-1; $j++ ) {
-                                               $ancestor = $this->stack->node( $stacklen-$j-1 );
+                                       $stackLength = $this->stack->length();
+                                       for ( $j = $i + 1; $j < $stackLength-1; $j++ ) {
+                                               $ancestor = $this->stack->node( $stackLength-$j-1 );
                                                if ( $ancestor->isHtmlNamed( 'template' ) ) {
                                                        break;
                                                }
@@ -2282,12 +2274,12 @@ class Balancer {
                                case 'body':
                                        $this->switchMode( 'inBodyMode' );
                                        return;
-                               # OMITTED: <frameset>
-                               # OMITTED: <html>
-                               # OMITTED: <head>
+                               // OMITTED: <frameset>
+                               // OMITTED: <html>
+                               // OMITTED: <head>
                                default:
                                        if ( !$last ) {
-                                               # OMITTED: <head>
+                                               // OMITTED: <head>
                                                if ( $node->isA( BalanceSets::$tableCellSet ) ) {
                                                        $this->switchMode( 'inCellMode' );
                                                        return;
@@ -2303,14 +2295,14 @@ class Balancer {
        }
 
        private function stopParsing() {
-               # Most of the spec methods are inapplicable, other than step 2:
-               # "pop all the nodes off the stack of open elements".
-               # We're going to keep the top-most <html> element on the stack, though.
-
-               # Clear the AFE list first, otherwise the element objects will stay live
-               # during serialization, potentially using O(N^2) memory. Note that
-               # popping the stack will never result in reconstructing the active
-               # formatting elements.
+               // Most of the spec methods are inapplicable, other than step 2:
+               // "pop all the nodes off the stack of open elements".
+               // We're going to keep the top-most <html> element on the stack, though.
+
+               // Clear the AFE list first, otherwise the element objects will stay live
+               // during serialization, potentially using O(N^2) memory. Note that
+               // popping the stack will never result in reconstructing the active
+               // formatting elements.
                $this->afe = null;
                $this->stack->popTo( 1 );
        }
@@ -2322,14 +2314,14 @@ class Balancer {
                return true;
        }
 
-       private function inTextMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inTextMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        $this->stack->insertText( $value );
                        return true;
                } elseif ( $token === 'eof' ) {
                        $this->stack->pop();
                        return $this->switchModeAndReprocess(
-                               $this->originalInsertionMode, $token, $value, $attribs, $selfclose
+                               $this->originalInsertionMode, $token, $value, $attribs, $selfClose
                        );
                } elseif ( $token === 'endtag' ) {
                        $this->stack->pop();
@@ -2339,7 +2331,7 @@ class Balancer {
                return true;
        }
 
-       private function inHeadMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inHeadMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        if ( preg_match( '/^[\x09\x0A\x0C\x0D\x20]+/', $value, $matches ) ) {
                                $this->stack->insertText( $matches[0] );
@@ -2352,9 +2344,9 @@ class Balancer {
                } elseif ( $token === 'tag' ) {
                        switch ( $value ) {
                        case 'meta':
-                               # OMITTED: in a full HTML parser, this might change the encoding.
-                               /* falls through */
-                       # OMITTED: <html>
+                               // OMITTED: in a full HTML parser, this might change the encoding.
+                               // falls through
+                       // OMITTED: <html>
                        case 'base':
                        case 'basefont':
                        case 'bgsound':
@@ -2362,26 +2354,26 @@ class Balancer {
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->stack->pop();
                                return true;
-                       # OMITTED: <title>
-                       # OMITTED: <noscript>
+                       // OMITTED: <title>
+                       // OMITTED: <noscript>
                        case 'noframes':
                        case 'style':
                                return $this->parseRawText( $value, $attribs );
-                       # OMITTED: <script>
+                       // OMITTED: <script>
                        case 'template':
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->afe->insertMarker();
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                $this->switchMode( 'inTemplateMode' );
                                $this->templateInsertionModes[] = $this->parseMode;
                                return true;
-                       # OMITTED: <head>
+                       // OMITTED: <head>
                        }
                } elseif ( $token === 'endtag' ) {
                        switch ( $value ) {
-                       # OMITTED: <head>
-                       # OMITTED: <body>
-                       # OMITTED: <html>
+                       // OMITTED: <head>
+                       // OMITTED: <body>
+                       // OMITTED: <html>
                        case 'br':
                                break; // handle at the bottom of the function
                        case 'template':
@@ -2406,36 +2398,36 @@ class Balancer {
                // If not handled above
                $this->inHeadMode( 'endtag', 'head' ); // synthetic </head>
                // Then redo this one
-               return $this->insertToken( $token, $value, $attribs, $selfclose );
+               return $this->insertToken( $token, $value, $attribs, $selfClose );
        }
 
-       private function inBodyMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inBodyMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        $this->afe->reconstruct( $this->stack );
                        $this->stack->insertText( $value );
                        return true;
                } elseif ( $token === 'eof' ) {
                        if ( !empty( $this->templateInsertionModes ) ) {
-                               return $this->inTemplateMode( $token, $value, $attribs, $selfclose );
+                               return $this->inTemplateMode( $token, $value, $attribs, $selfClose );
                        }
                        $this->stopParsing();
                        return true;
                } elseif ( $token === 'tag' ) {
                        switch ( $value ) {
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'base':
                        case 'basefont':
                        case 'bgsound':
                        case 'link':
                        case 'meta':
                        case 'noframes':
-                       # OMITTED: <script>
+                       // OMITTED: <script>
                        case 'style':
                        case 'template':
-                       # OMITTED: <title>
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
-                       # OMITTED: <body>
-                       # OMITTED: <frameset>
+                       // OMITTED: <title>
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
+                       // OMITTED: <body>
+                       // OMITTED: <frameset>
 
                        case 'address':
                        case 'article':
@@ -2489,7 +2481,7 @@ class Balancer {
                                }
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->ignoreLinefeed = true;
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                return true;
 
                        case 'form':
@@ -2509,7 +2501,7 @@ class Balancer {
                                return true;
 
                        case 'li':
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                foreach ( $this->stack as $node ) {
                                        if ( $node->isHtmlNamed( 'li' ) ) {
                                                $this->inBodyMode( 'endtag', 'li' );
@@ -2530,7 +2522,7 @@ class Balancer {
 
                        case 'dd':
                        case 'dt':
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                foreach ( $this->stack as $node ) {
                                        if ( $node->isHtmlNamed( 'dd' ) ) {
                                                $this->inBodyMode( 'endtag', 'dd' );
@@ -2553,12 +2545,12 @@ class Balancer {
                                $this->stack->insertHTMLElement( $value, $attribs );
                                return true;
 
-                       # OMITTED: <plaintext>
+                       // OMITTED: <plaintext>
 
                        case 'button':
                                if ( $this->stack->inScope( 'button' ) ) {
                                        $this->inBodyMode( 'endtag', 'button' );
-                                       return $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       return $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                $this->afe->reconstruct( $this->stack );
                                $this->stack->insertHTMLElement( $value, $attribs );
@@ -2576,7 +2568,7 @@ class Balancer {
                                                $this->stack->removeElement( $activeElement, false );
                                        }
                                }
-                               /* Falls through */
+                               // Falls through
                        case 'b':
                        case 'big':
                        case 'code':
@@ -2608,17 +2600,17 @@ class Balancer {
                                $this->afe->reconstruct( $this->stack );
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->afe->insertMarker();
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                return true;
 
                        case 'table':
-                               # The document is never in "quirks mode"; see simplifications
-                               # above.
+                               // The document is never in "quirks mode"; see simplifications
+                               // above.
                                if ( $this->stack->inButtonScope( 'p' ) ) {
                                        $this->inBodyMode( 'endtag', 'p' );
                                }
                                $this->stack->insertHTMLElement( $value, $attribs );
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                $this->switchMode( 'inTableMode' );
                                return true;
 
@@ -2631,15 +2623,15 @@ class Balancer {
                                $this->afe->reconstruct( $this->stack );
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->stack->pop();
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                return true;
 
                        case 'input':
                                $this->afe->reconstruct( $this->stack );
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->stack->pop();
-                               # OMITTED: frameset_ok
-                               # (hence we don't need to examine the tag's "type" attribute)
+                               // OMITTED: frameset_ok
+                               // (hence we don't need to examine the tag's "type" attribute)
                                return true;
 
                        case 'menuitem':
@@ -2659,22 +2651,22 @@ class Balancer {
                                return true;
 
                        case 'image':
-                               # warts!
-                               return $this->inBodyMode( $token, 'img', $attribs, $selfclose );
+                               // warts!
+                               return $this->inBodyMode( $token, 'img', $attribs, $selfClose );
 
-                       # OMITTED: <isindex>
+                       // OMITTED: <isindex>
 
                        case 'textarea':
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->ignoreLinefeed = true;
                                $this->inRCDATA = $value; // emulate rcdata tokenizer mode
-                               # OMITTED: frameset_ok
+                               // OMITTED: frameset_ok
                                return true;
 
-                       # OMITTED: <xmp>
-                       # OMITTED: <iframe>
-                       # OMITTED: <noembed>
-                       # OMITTED: <noscript>
+                       // OMITTED: <xmp>
+                       // OMITTED: <iframe>
+                       // OMITTED: <noembed>
+                       // OMITTED: <noscript>
 
                        case 'select':
                                $this->afe->reconstruct( $this->stack );
@@ -2719,30 +2711,30 @@ class Balancer {
 
                        case 'math':
                                $this->afe->reconstruct( $this->stack );
-                               # We skip the spec's "adjust MathML attributes" and
-                               # "adjust foreign attributes" steps, since the browser will
-                               # do this later when it parses the output and it doesn't affect
-                               # balancing.
+                               // We skip the spec's "adjust MathML attributes" and
+                               // "adjust foreign attributes" steps, since the browser will
+                               // do this later when it parses the output and it doesn't affect
+                               // balancing.
                                $this->stack->insertForeignElement(
                                        BalanceSets::MATHML_NAMESPACE, $value, $attribs
                                );
-                               if ( $selfclose ) {
-                                       # emit explicit </math> tag.
+                               if ( $selfClose ) {
+                                       // emit explicit </math> tag.
                                        $this->stack->pop();
                                }
                                return true;
 
                        case 'svg':
                                $this->afe->reconstruct( $this->stack );
-                               # We skip the spec's "adjust SVG attributes" and
-                               # "adjust foreign attributes" steps, since the browser will
-                               # do this later when it parses the output and it doesn't affect
-                               # balancing.
+                               // We skip the spec's "adjust SVG attributes" and
+                               // "adjust foreign attributes" steps, since the browser will
+                               // do this later when it parses the output and it doesn't affect
+                               // balancing.
                                $this->stack->insertForeignElement(
                                        BalanceSets::SVG_NAMESPACE, $value, $attribs
                                );
-                               if ( $selfclose ) {
-                                       # emit explicit </svg> tag.
+                               if ( $selfClose ) {
+                                       // emit explicit </svg> tag.
                                        $this->stack->pop();
                                }
                                return true;
@@ -2750,7 +2742,7 @@ class Balancer {
                        case 'caption':
                        case 'col':
                        case 'colgroup':
-                       # OMITTED: <frame>
+                       // OMITTED: <frame>
                        case 'head':
                        case 'tbody':
                        case 'td':
@@ -2768,10 +2760,10 @@ class Balancer {
                        return true;
                } elseif ( $token === 'endtag' ) {
                        switch ( $value ) {
-                       # </body>,</html> are unsupported.
+                       // </body>,</html> are unsupported.
 
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
 
                        case 'address':
                        case 'article':
@@ -2831,7 +2823,7 @@ class Balancer {
                        case 'p':
                                if ( !$this->stack->inButtonScope( 'p' ) ) {
                                        $this->inBodyMode( 'tag', 'p', [] );
-                                       return $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       return $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                $this->stack->generateImpliedEndTags( $value );
                                $this->stack->popTag( $value );
@@ -2839,7 +2831,7 @@ class Balancer {
 
                        case 'li':
                                if ( !$this->stack->inListItemScope( $value ) ) {
-                                       return true; # ignore
+                                       return true; // ignore
                                }
                                $this->stack->generateImpliedEndTags( $value );
                                $this->stack->popTag( $value );
@@ -2848,7 +2840,7 @@ class Balancer {
                        case 'dd':
                        case 'dt':
                                if ( !$this->stack->inScope( $value ) ) {
-                                       return true; # ignore
+                                       return true; // ignore
                                }
                                $this->stack->generateImpliedEndTags( $value );
                                $this->stack->popTag( $value );
@@ -2861,14 +2853,14 @@ class Balancer {
                        case 'h5':
                        case 'h6':
                                if ( !$this->stack->inScope( BalanceSets::$headingSet ) ) {
-                                       return true; # ignore
+                                       return true; // ignore
                                }
                                $this->stack->generateImpliedEndTags();
                                $this->stack->popTag( BalanceSets::$headingSet );
                                return true;
 
                        case 'sarcasm':
-                               # Take a deep breath, then:
+                               // Take a deep breath, then:
                                break;
 
                        case 'a':
@@ -2886,15 +2878,15 @@ class Balancer {
                        case 'tt':
                        case 'u':
                                if ( $this->stack->adoptionAgency( $value, $this->afe ) ) {
-                                       return true; # If we did something, we're done.
+                                       return true; // If we did something, we're done.
                                }
-                               break; # Go to the "any other end tag" case.
+                               break; // Go to the "any other end tag" case.
 
                        case 'applet':
                        case 'marquee':
                        case 'object':
                                if ( !$this->stack->inScope( $value ) ) {
-                                       return true; # ignore
+                                       return true; // ignore
                                }
                                $this->stack->generateImpliedEndTags();
                                $this->stack->popTag( $value );
@@ -2902,7 +2894,7 @@ class Balancer {
                                return true;
 
                        case 'br':
-                               # Turn </br> into <br>
+                               // Turn </br> into <br>
                                return $this->inBodyMode( 'tag', $value, [] );
                        }
 
@@ -2910,7 +2902,7 @@ class Balancer {
                        foreach ( $this->stack as $i => $node ) {
                                if ( $node->isHtmlNamed( $value ) ) {
                                        $this->stack->generateImpliedEndTags( $value );
-                                       $this->stack->popTo( $i ); # including $i
+                                       $this->stack->popTo( $i ); // including $i
                                        break;
                                } elseif ( $node->isA( BalanceSets::$specialSet ) ) {
                                        return true; // ignore this close token.
@@ -2925,14 +2917,15 @@ class Balancer {
                }
        }
 
-       private function inTableMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inTableMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        if ( $this->textIntegrationMode ) {
-                               return $this->inBodyMode( $token, $value, $attribs, $selfclose );
+                               return $this->inBodyMode( $token, $value, $attribs, $selfClose );
                        } elseif ( $this->stack->currentNode->isA( BalanceSets::$tableSectionRowSet ) ) {
                                $this->pendingTableText = '';
                                $this->originalInsertionMode = $this->parseMode;
-                               return $this->switchModeAndReprocess( 'inTableTextMode', $token, $value, $attribs, $selfclose );
+                               return $this->switchModeAndReprocess( 'inTableTextMode',
+                                       $token, $value, $attribs, $selfClose );
                        }
                        // fall through to default case.
                } elseif ( $token === 'eof' ) {
@@ -2952,7 +2945,7 @@ class Balancer {
                                return true;
                        case 'col':
                                $this->inTableMode( 'tag', 'colgroup', [] );
-                               return $this->insertToken( $token, $value, $attribs, $selfclose );
+                               return $this->insertToken( $token, $value, $attribs, $selfClose );
                        case 'tbody':
                        case 'tfoot':
                        case 'thead':
@@ -2964,18 +2957,18 @@ class Balancer {
                        case 'th':
                        case 'tr':
                                $this->inTableMode( 'tag', 'tbody', [] );
-                               return $this->insertToken( $token, $value, $attribs, $selfclose );
+                               return $this->insertToken( $token, $value, $attribs, $selfClose );
                        case 'table':
                                if ( !$this->stack->inTableScope( $value ) ) {
                                        return true; // Ignore this tag.
                                }
                                $this->inTableMode( 'endtag', $value );
-                               return $this->insertToken( $token, $value, $attribs, $selfclose );
+                               return $this->insertToken( $token, $value, $attribs, $selfClose );
 
                        case 'style':
-                       # OMITTED: <script>
+                       // OMITTED: <script>
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
 
                        case 'input':
                                if ( !isset( $attribs['type'] ) || strcasecmp( $attribs['type'], 'hidden' ) !== 0 ) {
@@ -3007,11 +3000,11 @@ class Balancer {
                                $this->stack->popTag( $value );
                                $this->resetInsertionMode();
                                return true;
-                       # OMITTED: <body>
+                       // OMITTED: <body>
                        case 'caption':
                        case 'col':
                        case 'colgroup':
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'tbody':
                        case 'td':
                        case 'tfoot':
@@ -3020,7 +3013,7 @@ class Balancer {
                        case 'tr':
                                return true; // Ignore the token.
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
                        }
                        // Fall through for "anything else" clause.
                } elseif ( $token === 'comment' ) {
@@ -3029,12 +3022,12 @@ class Balancer {
                }
                // This is the "anything else" case:
                $this->stack->fosterParentMode = true;
-               $this->inBodyMode( $token, $value, $attribs, $selfclose );
+               $this->inBodyMode( $token, $value, $attribs, $selfClose );
                $this->stack->fosterParentMode = false;
                return true;
        }
 
-       private function inTableTextMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inTableTextMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        $this->pendingTableText .= $value;
                        return true;
@@ -3052,7 +3045,7 @@ class Balancer {
                        $this->stack->insertText( $text );
                }
                return $this->switchModeAndReprocess(
-                       $this->originalInsertionMode, $token, $value, $attribs, $selfclose
+                       $this->originalInsertionMode, $token, $value, $attribs, $selfClose
                );
        }
 
@@ -3068,7 +3061,7 @@ class Balancer {
                return true;
        }
 
-       private function inCaptionMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inCaptionMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'tag' ) {
                        switch ( $value ) {
                        case 'caption':
@@ -3081,7 +3074,7 @@ class Balancer {
                        case 'thead':
                        case 'tr':
                                if ( $this->endCaption() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        }
@@ -3093,13 +3086,13 @@ class Balancer {
                                return true;
                        case 'table':
                                if ( $this->endCaption() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        case 'body':
                        case 'col':
                        case 'colgroup':
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'tbody':
                        case 'td':
                        case 'tfoot':
@@ -3112,10 +3105,10 @@ class Balancer {
                        // Fall through to "anything else" case.
                }
                // The Anything Else case
-               return $this->inBodyMode( $token, $value, $attribs, $selfclose );
+               return $this->inBodyMode( $token, $value, $attribs, $selfClose );
        }
 
-       private function inColumnGroupMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inColumnGroupMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        if ( preg_match( '/^[\x09\x0A\x0C\x0D\x20]+/', $value, $matches ) ) {
                                $this->stack->insertText( $matches[0] );
@@ -3127,13 +3120,13 @@ class Balancer {
                        // Fall through to handle non-whitespace below.
                } elseif ( $token === 'tag' ) {
                        switch ( $value ) {
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'col':
                                $this->stack->insertHTMLElement( $value, $attribs );
                                $this->stack->pop();
                                return true;
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
                        }
                        // Fall through for "anything else".
                } elseif ( $token === 'endtag' ) {
@@ -3148,11 +3141,11 @@ class Balancer {
                        case 'col':
                                return true; // Ignore the token.
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
                        }
                        // Fall through for "anything else".
                } elseif ( $token === 'eof' ) {
-                       return $this->inBodyMode( $token, $value, $attribs, $selfclose );
+                       return $this->inBodyMode( $token, $value, $attribs, $selfClose );
                } elseif ( $token === 'comment' ) {
                        $this->stack->insertComment( $value );
                        return true;
@@ -3163,7 +3156,7 @@ class Balancer {
                        return true; // Ignore the token.
                }
                $this->inColumnGroupMode( 'endtag', 'colgroup' );
-               return $this->insertToken( $token, $value, $attribs, $selfclose );
+               return $this->insertToken( $token, $value, $attribs, $selfClose );
        }
 
        // Helper function for inTableBodyMode
@@ -3180,7 +3173,7 @@ class Balancer {
                $this->switchMode( 'inTableMode' );
                return true;
        }
-       private function inTableBodyMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inTableBodyMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'tag' ) {
                        switch ( $value ) {
                        case 'tr':
@@ -3191,7 +3184,7 @@ class Balancer {
                        case 'th':
                        case 'td':
                                $this->inTableBodyMode( 'tag', 'tr', [] );
-                               $this->insertToken( $token, $value, $attribs, $selfclose );
+                               $this->insertToken( $token, $value, $attribs, $selfClose );
                                return true;
                        case 'caption':
                        case 'col':
@@ -3200,7 +3193,7 @@ class Balancer {
                        case 'tfoot':
                        case 'thead':
                                if ( $this->endSection() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        }
@@ -3208,7 +3201,7 @@ class Balancer {
                        switch ( $value ) {
                        case 'table':
                                if ( $this->endSection() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        case 'tbody':
@@ -3218,11 +3211,11 @@ class Balancer {
                                        $this->endSection();
                                }
                                return true;
-                       # OMITTED: <body>
+                       // OMITTED: <body>
                        case 'caption':
                        case 'col':
                        case 'colgroup':
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'td':
                        case 'th':
                        case 'tr':
@@ -3230,7 +3223,7 @@ class Balancer {
                        }
                }
                // Anything else:
-               return $this->inTableMode( $token, $value, $attribs, $selfclose );
+               return $this->inTableMode( $token, $value, $attribs, $selfClose );
        }
 
        // Helper function for inRowMode
@@ -3243,7 +3236,7 @@ class Balancer {
                $this->switchMode( 'inTableBodyMode' );
                return true;
        }
-       private function inRowMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inRowMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'tag' ) {
                        switch ( $value ) {
                        case 'th':
@@ -3261,7 +3254,7 @@ class Balancer {
                        case 'thead':
                        case 'tr':
                                if ( $this->endRow() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        }
@@ -3272,7 +3265,7 @@ class Balancer {
                                return true;
                        case 'table':
                                if ( $this->endRow() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        case 'tbody':
@@ -3282,21 +3275,21 @@ class Balancer {
                                        $this->stack->inTableScope( $value ) &&
                                        $this->endRow()
                                ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
-                       # OMITTED: <body>
+                       // OMITTED: <body>
                        case 'caption':
                        case 'col':
                        case 'colgroup':
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'td':
                        case 'th':
                                return true; // Ignore the token.
                        }
                }
                // Anything else:
-               return $this->inTableMode( $token, $value, $attribs, $selfclose );
+               return $this->inTableMode( $token, $value, $attribs, $selfClose );
        }
 
        // Helper for inCellMode
@@ -3311,7 +3304,7 @@ class Balancer {
                        return false;
                }
        }
-       private function inCellMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inCellMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'tag' ) {
                        switch ( $value ) {
                        case 'caption':
@@ -3324,7 +3317,7 @@ class Balancer {
                        case 'thead':
                        case 'tr':
                                if ( $this->endCell() ) {
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        }
@@ -3339,11 +3332,11 @@ class Balancer {
                                        $this->switchMode( 'inRowMode' );
                                }
                                return true;
-                       # OMITTED: <body>
+                       // OMITTED: <body>
                        case 'caption':
                        case 'col':
                        case 'colgroup':
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                                return true;
 
                        case 'table':
@@ -3356,24 +3349,24 @@ class Balancer {
                                        $this->stack->popTag( BalanceSets::$tableCellSet );
                                        $this->afe->clearToMarker();
                                        $this->switchMode( 'inRowMode' );
-                                       $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        }
                }
                // Anything else:
-               return $this->inBodyMode( $token, $value, $attribs, $selfclose );
+               return $this->inBodyMode( $token, $value, $attribs, $selfClose );
        }
 
-       private function inSelectMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inSelectMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' ) {
                        $this->stack->insertText( $value );
                        return true;
                } elseif ( $token === 'eof' ) {
-                       return $this->inBodyMode( $token, $value, $attribs, $selfclose );
+                       return $this->inBodyMode( $token, $value, $attribs, $selfClose );
                } elseif ( $token === 'tag' ) {
                        switch ( $value ) {
-                       # OMITTED: <html>
+                       // OMITTED: <html>
                        case 'option':
                                if ( $this->stack->currentNode->isHtmlNamed( 'option' ) ) {
                                        $this->stack->pop();
@@ -3399,10 +3392,10 @@ class Balancer {
                                        return true; // ignore token (fragment case)
                                }
                                $this->inSelectMode( 'endtag', 'select' );
-                               return $this->insertToken( $token, $value, $attribs, $selfclose );
+                               return $this->insertToken( $token, $value, $attribs, $selfClose );
                        case 'script':
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
                        }
                } elseif ( $token === 'endtag' ) {
                        switch ( $value ) {
@@ -3431,7 +3424,7 @@ class Balancer {
                                $this->resetInsertionMode();
                                return true;
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
                        }
                } elseif ( $token === 'comment' ) {
                        $this->stack->insertComment( $value );
@@ -3441,7 +3434,7 @@ class Balancer {
                return true;
        }
 
-       private function inSelectInTableMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inSelectInTableMode( $token, $value, $attribs = null, $selfClose = false ) {
                switch ( $value ) {
                case 'caption':
                case 'table':
@@ -3453,22 +3446,22 @@ class Balancer {
                case 'th':
                        if ( $token === 'tag' ) {
                                $this->inSelectInTableMode( 'endtag', 'select' );
-                               return $this->insertToken( $token, $value, $attribs, $selfclose );
+                               return $this->insertToken( $token, $value, $attribs, $selfClose );
                        } elseif ( $token === 'endtag' ) {
                                if ( $this->stack->inTableScope( $value ) ) {
                                        $this->inSelectInTableMode( 'endtag', 'select' );
-                                       return $this->insertToken( $token, $value, $attribs, $selfclose );
+                                       return $this->insertToken( $token, $value, $attribs, $selfClose );
                                }
                                return true;
                        }
                }
                // anything else
-               return $this->inSelectMode( $token, $value, $attribs, $selfclose );
+               return $this->inSelectMode( $token, $value, $attribs, $selfClose );
        }
 
-       private function inTemplateMode( $token, $value, $attribs = null, $selfclose = false ) {
+       private function inTemplateMode( $token, $value, $attribs = null, $selfClose = false ) {
                if ( $token === 'text' || $token === 'comment' ) {
-                       return $this->inBodyMode( $token, $value, $attribs, $selfclose );
+                       return $this->inBodyMode( $token, $value, $attribs, $selfClose );
                } elseif ( $token === 'eof' ) {
                        if ( $this->stack->indexOf( 'template' ) < 0 ) {
                                $this->stopParsing();
@@ -3477,7 +3470,7 @@ class Balancer {
                                $this->afe->clearToMarker();
                                array_pop( $this->templateInsertionModes );
                                $this->resetInsertionMode();
-                               $this->insertToken( $token, $value, $attribs, $selfclose );
+                               $this->insertToken( $token, $value, $attribs, $selfClose );
                        }
                        return true;
                } elseif ( $token === 'tag' ) {
@@ -3488,11 +3481,11 @@ class Balancer {
                        case 'link':
                        case 'meta':
                        case 'noframes':
-                       # OMITTED: <script>
+                       // OMITTED: <script>
                        case 'style':
                        case 'template':
-                       # OMITTED: <title>
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                       // OMITTED: <title>
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
 
                        case 'caption':
                        case 'colgroup':
@@ -3500,32 +3493,32 @@ class Balancer {
                        case 'tfoot':
                        case 'thead':
                                return $this->switchModeAndReprocess(
-                                       'inTableMode', $token, $value, $attribs, $selfclose
+                                       'inTableMode', $token, $value, $attribs, $selfClose
                                );
 
                        case 'col':
                                return $this->switchModeAndReprocess(
-                                       'inColumnGroupMode', $token, $value, $attribs, $selfclose
+                                       'inColumnGroupMode', $token, $value, $attribs, $selfClose
                                );
 
                        case 'tr':
                                return $this->switchModeAndReprocess(
-                                       'inTableBodyMode', $token, $value, $attribs, $selfclose
+                                       'inTableBodyMode', $token, $value, $attribs, $selfClose
                                );
 
                        case 'td':
                        case 'th':
                                return $this->switchModeAndReprocess(
-                                       'inRowMode', $token, $value, $attribs, $selfclose
+                                       'inRowMode', $token, $value, $attribs, $selfClose
                                );
                        }
                        return $this->switchModeAndReprocess(
-                               'inBodyMode', $token, $value, $attribs, $selfclose
+                               'inBodyMode', $token, $value, $attribs, $selfClose
                        );
                } elseif ( $token === 'endtag' ) {
                        switch ( $value ) {
                        case 'template':
-                               return $this->inHeadMode( $token, $value, $attribs, $selfclose );
+                               return $this->inHeadMode( $token, $value, $attribs, $selfClose );
                        }
                        return true;
                } else {
index 5320673..b620132 100644 (file)
@@ -958,6 +958,9 @@ abstract class UploadBase {
         *
         * @param User $user
         * @return UploadStashFile Stashed file
+        * @throws UploadStashBadPathException
+        * @throws UploadStashFileException
+        * @throws UploadStashNotLoggedInException
         */
        public function stashFile( User $user = null ) {
                $stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash( $user );
index c46836b..36526d7 100644 (file)
@@ -648,8 +648,6 @@ class User implements IDBAccessObject {
         * @since 1.27
         */
        public static function newSystemUser( $name, $options = [] ) {
-               global $wgDisableAuthManager;
-
                $options += [
                        'validate' => 'valid',
                        'create' => true,
@@ -662,9 +660,6 @@ class User implements IDBAccessObject {
                }
 
                $fields = self::selectFields();
-               if ( $wgDisableAuthManager ) {
-                       $fields = array_merge( $fields, [ 'user_password', 'user_newpassword' ] );
-               }
 
                $dbw = wfGetDB( DB_MASTER );
                $row = $dbw->selectRow(
@@ -681,49 +676,15 @@ class User implements IDBAccessObject {
 
                // A user is considered to exist as a non-system user if it can
                // authenticate, or has an email set, or has a non-invalid token.
-               if ( !$user->mEmail && $user->mToken === self::INVALID_TOKEN ) {
-                       if ( $wgDisableAuthManager ) {
-                               $passwordFactory = new PasswordFactory();
-                               $passwordFactory->init( RequestContext::getMain()->getConfig() );
-                               try {
-                                       $password = $passwordFactory->newFromCiphertext( $row->user_password );
-                               } catch ( PasswordError $e ) {
-                                       wfDebug( 'Invalid password hash found in database.' );
-                                       $password = PasswordFactory::newInvalidPassword();
-                               }
-                               try {
-                                       $newpassword = $passwordFactory->newFromCiphertext( $row->user_newpassword );
-                               } catch ( PasswordError $e ) {
-                                       wfDebug( 'Invalid password hash found in database.' );
-                                       $newpassword = PasswordFactory::newInvalidPassword();
-                               }
-                               $canAuthenticate = !$password instanceof InvalidPassword ||
-                                       !$newpassword instanceof InvalidPassword;
-                       } else {
-                               $canAuthenticate = AuthManager::singleton()->userCanAuthenticate( $name );
-                       }
-               }
-               if ( $user->mEmail || $user->mToken !== self::INVALID_TOKEN || $canAuthenticate ) {
+               if ( $user->mEmail || $user->mToken !== self::INVALID_TOKEN ||
+                       AuthManager::singleton()->userCanAuthenticate( $name )
+               ) {
                        // User exists. Steal it?
                        if ( !$options['steal'] ) {
                                return null;
                        }
 
-                       if ( $wgDisableAuthManager ) {
-                               $nopass = PasswordFactory::newInvalidPassword()->toString();
-                               $dbw->update(
-                                       'user',
-                                       [
-                                               'user_password' => $nopass,
-                                               'user_newpassword' => $nopass,
-                                               'user_newpass_time' => null,
-                                       ],
-                                       [ 'user_id' => $user->getId() ],
-                                       __METHOD__
-                               );
-                       } else {
-                               AuthManager::singleton()->revokeAccessForUser( $name );
-                       }
+                       AuthManager::singleton()->revokeAccessForUser( $name );
 
                        $user->invalidateEmail();
                        $user->mToken = self::INVALID_TOKEN;
@@ -1387,8 +1348,6 @@ class User implements IDBAccessObject {
         */
        protected function loadFromUserObject( $user ) {
                $user->load();
-               $user->loadGroups();
-               $user->loadOptions();
                foreach ( self::$mCacheVars as $var ) {
                        $this->$var = $user->$var;
                }
@@ -2510,31 +2469,7 @@ class User implements IDBAccessObject {
         * @return bool
         */
        public function setPassword( $str ) {
-               global $wgAuth, $wgDisableAuthManager;
-
-               if ( !$wgDisableAuthManager ) {
-                       return $this->setPasswordInternal( $str );
-               }
-
-               if ( $str !== null ) {
-                       if ( !$wgAuth->allowPasswordChange() ) {
-                               throw new PasswordError( wfMessage( 'password-change-forbidden' )->text() );
-                       }
-
-                       $status = $this->checkPasswordValidity( $str );
-                       if ( !$status->isGood() ) {
-                               throw new PasswordError( $status->getMessage()->text() );
-                       }
-               }
-
-               if ( !$wgAuth->setPassword( $this, $str ) ) {
-                       throw new PasswordError( wfMessage( 'externaldberror' )->text() );
-               }
-
-               $this->setOption( 'watchlisttoken', false );
-               $this->setPasswordInternal( $str );
-
-               return true;
+               return $this->setPasswordInternal( $str );
        }
 
        /**
@@ -2546,16 +2481,7 @@ class User implements IDBAccessObject {
         *  through the web interface.
         */
        public function setInternalPassword( $str ) {
-               global $wgAuth, $wgDisableAuthManager;
-
-               if ( !$wgDisableAuthManager ) {
-                       $this->setPasswordInternal( $str );
-               }
-
-               if ( $wgAuth->allowSetLocalPassword() ) {
-                       $this->setOption( 'watchlisttoken', false );
-                       $this->setPasswordInternal( $str );
-               }
+               $this->setPasswordInternal( $str );
        }
 
        /**
@@ -2567,55 +2493,26 @@ class User implements IDBAccessObject {
         * @return bool Success
         */
        private function setPasswordInternal( $str ) {
-               global $wgDisableAuthManager;
-
-               if ( $wgDisableAuthManager ) {
-                       $id = self::idFromName( $this->getName(), self::READ_LATEST );
-                       if ( $id == 0 ) {
-                               throw new LogicException( 'Cannot set a password for a user that is not in the database.' );
-                       }
-
-                       $passwordFactory = new PasswordFactory();
-                       $passwordFactory->init( RequestContext::getMain()->getConfig() );
-                       $dbw = wfGetDB( DB_MASTER );
-                       $dbw->update(
-                               'user',
-                               [
-                                       'user_password' => $passwordFactory->newFromPlaintext( $str )->toString(),
-                                       'user_newpassword' => PasswordFactory::newInvalidPassword()->toString(),
-                                       'user_newpass_time' => $dbw->timestampOrNull( null ),
-                               ],
-                               [
-                                       'user_id' => $id,
-                               ],
-                               __METHOD__
-                       );
-
-                       // When the main password is changed, invalidate all bot passwords too
-                       BotPassword::invalidateAllPasswordsForUser( $this->getName() );
-               } else {
-                       $manager = AuthManager::singleton();
-
-                       // If the user doesn't exist yet, fail
-                       if ( !$manager->userExists( $this->getName() ) ) {
-                               throw new LogicException( 'Cannot set a password for a user that is not in the database.' );
-                       }
+               $manager = AuthManager::singleton();
 
-                       $status = $this->changeAuthenticationData( [
-                               'username' => $this->getName(),
-                               'password' => $str,
-                               'retype' => $str,
-                       ] );
-                       if ( !$status->isGood() ) {
-                               \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
-                                       ->info( __METHOD__ . ': Password change rejected: '
-                                               . $status->getWikiText( null, null, 'en' ) );
-                               return false;
-                       }
+               // If the user doesn't exist yet, fail
+               if ( !$manager->userExists( $this->getName() ) ) {
+                       throw new LogicException( 'Cannot set a password for a user that is not in the database.' );
+               }
 
-                       $this->setOption( 'watchlisttoken', false );
+               $status = $this->changeAuthenticationData( [
+                       'username' => $this->getName(),
+                       'password' => $str,
+                       'retype' => $str,
+               ] );
+               if ( !$status->isGood() ) {
+                       \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
+                               ->info( __METHOD__ . ': Password change rejected: '
+                                       . $status->getWikiText( null, null, 'en' ) );
+                       return false;
                }
 
+               $this->setOption( 'watchlisttoken', false );
                SessionManager::singleton()->invalidateSessionsForUser( $this );
 
                return true;
@@ -2634,12 +2531,6 @@ class User implements IDBAccessObject {
         * @since 1.27
         */
        public function changeAuthenticationData( array $data ) {
-               global $wgDisableAuthManager;
-               if ( $wgDisableAuthManager ) {
-                       throw new LogicException( __METHOD__ . ' cannot be called when $wgDisableAuthManager '
-                               . 'is true' );
-               }
-
                $manager = AuthManager::singleton();
                $reqs = $manager->getAuthenticationRequests( AuthManager::ACTION_CHANGE, $this );
                $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
@@ -2725,32 +2616,7 @@ class User implements IDBAccessObject {
         * @param bool $throttle If true, reset the throttle timestamp to the present
         */
        public function setNewpassword( $str, $throttle = true ) {
-               global $wgDisableAuthManager;
-
-               if ( $wgDisableAuthManager ) {
-                       $id = $this->getId();
-                       if ( $id == 0 ) {
-                               throw new LogicException( 'Cannot set new password for a user that is not in the database.' );
-                       }
-
-                       $dbw = wfGetDB( DB_MASTER );
-
-                       $passwordFactory = new PasswordFactory();
-                       $passwordFactory->init( RequestContext::getMain()->getConfig() );
-                       $update = [
-                               'user_newpassword' => $passwordFactory->newFromPlaintext( $str )->toString(),
-                       ];
-
-                       if ( $str === null ) {
-                               $update['user_newpass_time'] = null;
-                       } elseif ( $throttle ) {
-                               $update['user_newpass_time'] = $dbw->timestamp();
-                       }
-
-                       $dbw->update( 'user', $update, [ 'user_id' => $id ], __METHOD__ );
-               } else {
-                       throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
-               }
+               throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
        }
 
        /**
@@ -2760,33 +2626,7 @@ class User implements IDBAccessObject {
         * @return bool
         */
        public function isPasswordReminderThrottled() {
-               global $wgPasswordReminderResendTime, $wgDisableAuthManager;
-
-               if ( $wgDisableAuthManager ) {
-                       if ( !$wgPasswordReminderResendTime ) {
-                               return false;
-                       }
-
-                       $this->load();
-
-                       $db = ( $this->queryFlagsUsed & self::READ_LATEST )
-                               ? wfGetDB( DB_MASTER )
-                               : wfGetDB( DB_SLAVE );
-                       $newpassTime = $db->selectField(
-                               'user',
-                               'user_newpass_time',
-                               [ 'user_id' => $this->getId() ],
-                               __METHOD__
-                       );
-
-                       if ( $newpassTime === null ) {
-                               return false;
-                       }
-                       $expiry = wfTimestamp( TS_UNIX, $newpassTime ) + $wgPasswordReminderResendTime * 3600;
-                       return time() < $expiry;
-               } else {
-                       throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
-               }
+               throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
        }
 
        /**
@@ -4282,87 +4122,27 @@ class User implements IDBAccessObject {
         * @return bool True if the given password is correct, otherwise False
         */
        public function checkPassword( $password ) {
-               global $wgAuth, $wgLegacyEncoding, $wgDisableAuthManager;
-
-               if ( $wgDisableAuthManager ) {
-                       $this->load();
-
-                       // Some passwords will give a fatal Status, which means there is
-                       // some sort of technical or security reason for this password to
-                       // be completely invalid and should never be checked (e.g., T64685)
-                       if ( !$this->checkPasswordValidity( $password )->isOK() ) {
-                               return false;
-                       }
-
-                       // Certain authentication plugins do NOT want to save
-                       // domain passwords in a mysql database, so we should
-                       // check this (in case $wgAuth->strict() is false).
-                       if ( $wgAuth->authenticate( $this->getName(), $password ) ) {
+               $manager = AuthManager::singleton();
+               $reqs = AuthenticationRequest::loadRequestsFromSubmission(
+                       $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN ),
+                       [
+                               'username' => $this->getName(),
+                               'password' => $password,
+                       ]
+               );
+               $res = AuthManager::singleton()->beginAuthentication( $reqs, 'null:' );
+               switch ( $res->status ) {
+                       case AuthenticationResponse::PASS:
                                return true;
-                       } elseif ( $wgAuth->strict() ) {
-                               // Auth plugin doesn't allow local authentication
-                               return false;
-                       } elseif ( $wgAuth->strictUserAuth( $this->getName() ) ) {
-                               // Auth plugin doesn't allow local authentication for this user name
+                       case AuthenticationResponse::FAIL:
+                               // Hope it's not a PreAuthenticationProvider that failed...
+                               \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
+                                       ->info( __METHOD__ . ': Authentication failed: ' . $res->message->plain() );
                                return false;
-                       }
-
-                       $passwordFactory = new PasswordFactory();
-                       $passwordFactory->init( RequestContext::getMain()->getConfig() );
-                       $db = ( $this->queryFlagsUsed & self::READ_LATEST )
-                               ? wfGetDB( DB_MASTER )
-                               : wfGetDB( DB_SLAVE );
-
-                       try {
-                               $mPassword = $passwordFactory->newFromCiphertext( $db->selectField(
-                                       'user', 'user_password', [ 'user_id' => $this->getId() ], __METHOD__
-                               ) );
-                       } catch ( PasswordError $e ) {
-                               wfDebug( 'Invalid password hash found in database.' );
-                               $mPassword = PasswordFactory::newInvalidPassword();
-                       }
-
-                       if ( !$mPassword->equals( $password ) ) {
-                               if ( $wgLegacyEncoding ) {
-                                       // Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted
-                                       // Check for this with iconv
-                                       $cp1252Password = iconv( 'UTF-8', 'WINDOWS-1252//TRANSLIT', $password );
-                                       if ( $cp1252Password === $password || !$mPassword->equals( $cp1252Password ) ) {
-                                               return false;
-                                       }
-                               } else {
-                                       return false;
-                               }
-                       }
-
-                       if ( $passwordFactory->needsUpdate( $mPassword ) && !wfReadOnly() ) {
-                               $this->setPasswordInternal( $password );
-                       }
-
-                       return true;
-               } else {
-                       $manager = AuthManager::singleton();
-                       $reqs = AuthenticationRequest::loadRequestsFromSubmission(
-                               $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN ),
-                               [
-                                       'username' => $this->getName(),
-                                       'password' => $password,
-                               ]
-                       );
-                       $res = AuthManager::singleton()->beginAuthentication( $reqs, 'null:' );
-                       switch ( $res->status ) {
-                               case AuthenticationResponse::PASS:
-                                       return true;
-                               case AuthenticationResponse::FAIL:
-                                       // Hope it's not a PreAuthenticationProvider that failed...
-                                       \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
-                                               ->info( __METHOD__ . ': Authentication failed: ' . $res->message->plain() );
-                                       return false;
-                               default:
-                                       throw new BadMethodCallException(
-                                               'AuthManager returned a response unsupported by ' . __METHOD__
-                                       );
-                       }
+                       default:
+                               throw new BadMethodCallException(
+                                       'AuthManager returned a response unsupported by ' . __METHOD__
+                               );
                }
        }
 
@@ -4375,43 +4155,8 @@ class User implements IDBAccessObject {
         * @return bool True if matches, false otherwise
         */
        public function checkTemporaryPassword( $plaintext ) {
-               global $wgNewPasswordExpiry, $wgDisableAuthManager;
-
-               if ( $wgDisableAuthManager ) {
-                       $this->load();
-
-                       $passwordFactory = new PasswordFactory();
-                       $passwordFactory->init( RequestContext::getMain()->getConfig() );
-                       $db = ( $this->queryFlagsUsed & self::READ_LATEST )
-                               ? wfGetDB( DB_MASTER )
-                               : wfGetDB( DB_SLAVE );
-
-                       $row = $db->selectRow(
-                               'user',
-                               [ 'user_newpassword', 'user_newpass_time' ],
-                               [ 'user_id' => $this->getId() ],
-                               __METHOD__
-                       );
-                       try {
-                               $newPassword = $passwordFactory->newFromCiphertext( $row->user_newpassword );
-                       } catch ( PasswordError $e ) {
-                               wfDebug( 'Invalid password hash found in database.' );
-                               $newPassword = PasswordFactory::newInvalidPassword();
-                       }
-
-                       if ( $newPassword->equals( $plaintext ) ) {
-                               if ( is_null( $row->user_newpass_time ) ) {
-                                       return true;
-                               }
-                               $expiry = wfTimestamp( TS_UNIX, $row->user_newpass_time ) + $wgNewPasswordExpiry;
-                               return ( time() < $expiry );
-                       } else {
-                               return false;
-                       }
-               } else {
-                       // Can't check the temporary password individually.
-                       return $this->checkPassword( $plaintext );
-               }
+               // Can't check the temporary password individually.
+               return $this->checkPassword( $plaintext );
        }
 
        /**
@@ -5161,12 +4906,20 @@ class User implements IDBAccessObject {
                                // If we actually have a slave server, the count is
                                // at least one behind because the current transaction
                                // has not been committed and replicated.
-                               $this->initEditCount( 1 );
+                               $this->mEditCount = $this->initEditCount( 1 );
                        } else {
                                // But if DB_SLAVE is selecting the master, then the
                                // count we just read includes the revision that was
                                // just added in the working transaction.
-                               $this->initEditCount();
+                               $this->mEditCount = $this->initEditCount();
+                       }
+               } else {
+                       if ( $this->mEditCount === null ) {
+                               $this->getEditCount();
+                               $dbr = wfGetDB( DB_SLAVE );
+                               $this->mEditCount += ( $dbr !== $dbw ) ? 1 : 0;
+                       } else {
+                               $this->mEditCount++;
                        }
                }
                // Edit count in user cache too
@@ -5280,45 +5033,10 @@ class User implements IDBAccessObject {
         *     - false will be converted to 'create' if this object is the same as
         *       $wgUser and to 'create2' otherwise
         * @param string $reason User supplied reason
-        * @return int|bool True if not $wgNewUserLog or not $wgDisableAuthManager;
-        *   otherwise ID of log item or 0 on failure
+        * @return bool true
         */
        public function addNewUserLogEntry( $action = false, $reason = '' ) {
-               global $wgUser, $wgNewUserLog, $wgDisableAuthManager;
-               if ( !$wgDisableAuthManager || empty( $wgNewUserLog ) ) {
-                       return true; // disabled
-               }
-
-               if ( $action === true ) {
-                       $action = 'byemail';
-               } elseif ( $action === false ) {
-                       if ( $this->equals( $wgUser ) ) {
-                               $action = 'create';
-                       } else {
-                               $action = 'create2';
-                       }
-               }
-
-               if ( $action === 'create' || $action === 'autocreate' ) {
-                       $performer = $this;
-               } else {
-                       $performer = $wgUser;
-               }
-
-               $logEntry = new ManualLogEntry( 'newusers', $action );
-               $logEntry->setPerformer( $performer );
-               $logEntry->setTarget( $this->getUserPage() );
-               $logEntry->setComment( $reason );
-               $logEntry->setParameters( [
-                       '4::userid' => $this->getId(),
-               ] );
-               $logid = $logEntry->insert();
-
-               if ( $action !== 'autocreate' ) {
-                       $logEntry->publish( $logid );
-               }
-
-               return (int)$logid;
+               return true; // disabled
        }
 
        /**
index de52cd9..2ebc9ed 100644 (file)
@@ -229,7 +229,7 @@ EOD;
 
                $fileinfo = $this->getTargetFileinfo();
 
-               if ( $fileinfo['type'] === AutoloadGenerator::FILETYPE_JSON ) {
+               if ( $fileinfo['type'] === self::FILETYPE_JSON ) {
                        return $this->generateJsonAutoload( $fileinfo['filename'] );
                } else {
                        return $this->generatePHPAutoload( $commandName, $fileinfo['filename'] );
@@ -247,17 +247,17 @@ EOD;
        public function getTargetFileinfo() {
                $fileinfo = [
                        'filename' => $this->basepath . '/autoload.php',
-                       'type' => AutoloadGenerator::FILETYPE_PHP
+                       'type' => self::FILETYPE_PHP
                ];
                if ( file_exists( $this->basepath . '/extension.json' ) ) {
                        $fileinfo = [
                                'filename' => $this->basepath . '/extension.json',
-                               'type' => AutoloadGenerator::FILETYPE_JSON
+                               'type' => self::FILETYPE_JSON
                        ];
                } elseif ( file_exists( $this->basepath . '/skin.json' ) ) {
                        $fileinfo = [
                                'filename' => $this->basepath . '/skin.json',
-                               'type' => AutoloadGenerator::FILETYPE_JSON
+                               'type' => self::FILETYPE_JSON
                        ];
                }
 
index c7bd395..9fc2431 100644 (file)
@@ -217,7 +217,7 @@ class BatchRowIterator implements RecursiveIterator {
         * `=` conditions while the final key uses a `>` condition
         *
         * Example output:
-        *        array( '( foo = 42 AND bar > 7 ) OR ( foo > 42 )' )
+        *        [ '( foo = 42 AND bar > 7 ) OR ( foo > 42 )' ]
         *
         * @return array The SQL conditions necessary to select the next set
         *  of rows in the batched query
index f3d72e8..dd3ea1b 100644 (file)
@@ -324,7 +324,7 @@ class MWCryptRand {
                                ": Falling back to using a pseudo random state to generate randomness.\n" );
                }
                while ( strlen( $buffer ) < $bytes ) {
-                       $buffer .= MWCryptHash::hmac( $this->randomState(), mt_rand() );
+                       $buffer .= MWCryptHash::hmac( $this->randomState(), strval( mt_rand() ) );
                        // This code is never really cryptographically strong, if we use it
                        // at all, then set strong to false.
                        $this->strong = false;
index 43acd83..62946bb 100644 (file)
        "createacct-email-ph": "أدخل عنوان بريدك الإلكتروني",
        "createacct-another-email-ph": "أدخل عنوان البريد الإلكتروني",
        "createaccountmail": "استخدم كلمة سر عشوائية مؤقتة وارسلها إلى عنوان البريد الإلكتروني المحدد أدناه",
+       "createaccountmail-help": "يمكن استخدامه لإنشاء حساب لشخص آخر من دون معرفة كلمة المرور.",
        "createacct-realname": "الاسم الحقيقي (اختياري)",
        "createaccountreason": "السبب:",
        "createacct-reason": "السبب",
        "createacct-reason-ph": "لماذا تقوم بإنشاء حساب آخر",
+       "createacct-reason-help": "رسالة تظهر في سجل إنشاء الحسابات",
        "createacct-submit": "افتح الحساب",
        "createacct-another-submit": "أنشئ حسابا",
        "createacct-continue-submit": "مواصلة إنشاء الحساب",
        "ipb-unblock": "رفع المنع عن مستخدم أو عنوان أيبي",
        "ipb-blocklist": "عرض حالات المنع الحالية",
        "ipb-blocklist-contribs": "مساهمات $1",
+       "ipb-blocklist-duration-left": "يتبقى $1",
        "unblockip": "رفع المنع عن المستخدم",
        "unblockiptext": "استخدم الاستمارة أدناه لاسترجاع صلاحية الكتابة الخاصة بعنوان أيبي أو مستخدم تم سحبها منه مسبقا.",
        "ipusubmit": "ارفع هذا المنع",
        "lockdbsuccesstext": "لقد أغلقت قاعدة البيانات.<br />\nتذكر أن [[Special:UnlockDB|تزيل الغلق]] بعد اكتمال أعمال الصيانة.",
        "unlockdbsuccesstext": "تم إعادة فتح قاعدة البيانات",
        "lockfilenotwritable": "ملف غلق قاعدة البيانات لا يمكن الكتابة عليه.\nلغلق قاعدة البيانات أو إزالة الغلق يجب أن يكون هذا الملف قابلاً للكتابة من قبل خادوم الويب.",
+       "databaselocked": "قاعدة البيانات مقفلة بالفعل.",
        "databasenotlocked": "قاعدة البيانات ليست مغلقة.",
        "lockedbyandtime": "(من $1 على $2 في $3 )",
        "move-page": "نقل $1",
        "confirm-watch-top": "إضافة هذه الصفحة إلى قائمة مراقبتك؟",
        "confirm-unwatch-button": "موافق",
        "confirm-unwatch-top": "إزالة هذه الصفحة من قائمة مراقبتك؟",
+       "confirm-rollback-button": "موافق",
        "semicolon-separator": "؛&#32;",
        "comma-separator": "،&#32;",
        "quotation-marks": "«$1»",
        "log-action-filter-block-reblock": "منع التعديل",
        "log-action-filter-block-unblock": "رفع المنع",
        "log-action-filter-delete-delete": "حذف الصفحات",
+       "log-action-filter-delete-restore": "استرجاع الصفحات",
        "log-action-filter-delete-event": "حذف السجلات",
        "log-action-filter-delete-revision": "حذف المراجعات",
        "log-action-filter-import-interwiki": "استيراد عابر للويكي",
        "log-action-filter-upload-overwrite": "إعادة الرفع",
        "authmanager-create-disabled": "إنشاء الحسابات معطل.",
        "authmanager-create-from-login": "لإنشاء حساب، برجاء ملء الحقول أدناه.",
+       "authmanager-retype-help": "كلمة المرور مرة أخرى للتأكيد.",
        "authmanager-email-label": "البريد الإلكتروني",
        "authmanager-email-help": "عنوان البريد الإلكتروني",
        "authmanager-realname-label": "الاسم الحقيقي",
        "authprovider-resetpass-skip-label": "تخطى",
        "authprovider-resetpass-skip-help": "تخطي إعادة تعيين كلمة المرور",
        "cannotauth-not-allowed-title": "الإذن مرفوض",
+       "changecredentials": "تغيير الاعتماد",
+       "changecredentials-submit": "تغيير الاعتماد",
+       "removecredentials": "إزالة الاعتماد",
+       "removecredentials-submit": "إزالة الاعتماد",
        "credentialsform-account": "اسم الحساب:",
        "cannotlink-no-provider-title": "لا توجد حسابات قابلة للربط",
        "cannotlink-no-provider": "لا توجد حسابات قابلة للربط",
index 16bf5bc..8554e0b 100644 (file)
        "minoredit": "Kiçik redaktə",
        "watchthis": "Bu səhifəni izlə",
        "savearticle": "Səhifəni qeyd et",
+       "publishpage": "Səhifəni yayımla",
+       "publishchanges": "Dəyişiklikləri yayımla",
        "preview": "Sınaq görüntüsü",
        "showpreview": "Sınaq göstərişi",
        "showdiff": "Dəyişiklikləri göstər",
index 641156e..84abebd 100644 (file)
        "wlshowtime": "Күрһәтеү өсөн ваҡыт арауығы",
        "wlshowhideminor": "Әҙ генә үҙгәрештәр",
        "wlshowhidebots": "Бот",
-       "wlshowhideliu": "Ñ\82анÑ\8bлÒ\93ан Ò¡Ñ\83лланÑ\8bÑ\83Ñ\81Ñ\8bлаÑ\80",
+       "wlshowhideliu": "Ñ\82еÑ\80кÓ\99лгÓ\99н Ò¡Ð°Ñ\82наÑ\88Ñ\8bÑ\83Ñ\81Ñ\8b",
        "wlshowhideanons": "Аноним ҡулланыусылар",
        "wlshowhidepatr": "Тикшерелгән төҙәтеүҙәр",
        "wlshowhidemine": "Минең үҙгәртеүҙәр",
        "logentry-delete-delete": "$1 $3 битен {{GENDER:$2|юйҙы}}",
        "logentry-delete-restore": "$1 $3 битен {{GENDER:$2|тергеҙҙе}}",
        "logentry-delete-event": "$1 журналдағы {{PLURAL:$5|яҙманы}} $3: $4 {{GENDER:$2|үҙгәртте}}",
-       "logentry-delete-revision": "$1 {{PLURAL:$5|$5 версияның}} күренеүсәнлеген   $3: $4 битендә {{GENDER:$2|үҙгәртте}}",
+       "logentry-delete-revision": "Ҡатнашыусы $1 $3: $4 битенең {{PLURAL:$5|$5 версиялары|$5 версияларының|1=версиялар}} күренешен {{GENDER:$2|үҙгәртте|үҙгәртте}}.",
        "logentry-delete-event-legacy": "$1  $3 журналы яҙмаларының күренеүсәнлеген {{GENDER:$2|үҙгәртте}}",
        "logentry-delete-revision-legacy": "$1  $3 битендә версияларҙың күренеүсәнлеген {{GENDER:$2|үҙгәртте}}",
        "logentry-suppress-delete": "$1 $3 битен {{GENDER:$2|баҫырылдырҙы}}",
index 2eba576..2396035 100644 (file)
@@ -16,7 +16,8 @@
                        "아라",
                        "Matthias Klostermayr",
                        "Macofe",
-                       "George Animal"
+                       "George Animal",
+                       "Lokal Profil"
                ]
        },
        "tog-underline": "Links unterstreichen:",
        "accountcreated": "Benytzerkonto is erstöid worn",
        "accountcreatedtext": "'s Benytzerkonto $1 is aigrichtt worn.",
        "loginlanguagelabel": "Sproch: $1",
+       "pt-login": "Eilogga",
        "changepassword": "Posswort ändern",
        "oldpassword": "Oids Posswort:",
        "newpassword": "Neichs Posswort:",
index 3f68674..a5c5a14 100644 (file)
        "watchnologin": "আপনি প্রবেশ করেননি",
        "addwatch": "নজরতালিকায় যোগ করো",
        "addedwatchtext": "\"[[:$1]]\" ও এর আলোচনা পাতাটি আপনার [[Special:Watchlist|নজরতালিকাতে]] যোগ করা হয়েছে।",
+       "addedwatchtext-talk": "\"[[:$1]]\" ও এর সাথে জড়িত পাতা আপনার [[Special:Watchlist|নজরতালিকাতে]] যোগ করা হয়েছে।",
        "addedwatchtext-short": "\"$1\" পাতাটি আপনার নজরতালিকায় যোগ করা হয়েছে।",
        "removewatch": "নজরতালিকা থেকে অপসারণ",
        "removedwatchtext": "\"[[:$1]]\" ও এর আলোচনা পাতাটি আপনার [[Special:Watchlist|নজরতালিকা]] থেকে সরানো হয়েছে।",
+       "removedwatchtext-talk": "\"[[:$1]]\" ও এর সাথে জড়িত পাতা আপনার [[Special:Watchlist|নজরতালিকা]] থেকে সরানো হয়েছে।",
        "removedwatchtext-short": "\"$1\" পাতাটি আপনার নজরতালিকা থেকে সরিয়ে নেয়া হয়েছে।",
        "watch": "নজর রাখুন",
        "watchthispage": "নজরে রাখুন",
index 2c0b040..82c9d61 100644 (file)
        "minoredit": "Ovo je manja izmjena",
        "watchthis": "Prati ovu stranicu",
        "savearticle": "Sačuvaj stranicu",
+       "publishpage": "Objavi stranicu",
+       "publishchanges": "Objavi izmjene",
        "preview": "Pregled stranice",
        "showpreview": "Prikaži izgled",
        "showdiff": "Prikaži izmjene",
index 0e238f1..86a7951 100644 (file)
        "content-model-css": "CSS",
        "content-json-empty-object": "Prázdný objekt",
        "content-json-empty-array": "Prázdné pole",
-       "deprecated-self-close-category": "Stránky s neplatnými sebeuzavírajícími se HTML značkami",
-       "deprecated-self-close-category-desc": "Stránka obsahuje neplatné sebeuzavírající se HTML značky, například <code>&lt;b/></code> nebo <code>&lt;span/></code>. Jejich chování se v zájmu konzistence se specifikací HTML5 brzy změní, proto je jejich použití ve wikitextu zastaralé.",
+       "deprecated-self-close-category": "Stránky s neplatnými sebeuzavírajícími HTML značkami",
+       "deprecated-self-close-category-desc": "Stránka obsahuje neplatné sebeuzavírající HTML značky, například <code>&lt;b/></code> nebo <code>&lt;span/></code>. Jejich chování se v zájmu konzistence se specifikací HTML5 brzy změní, proto je jejich použití ve wikitextu zastaralé.",
        "duplicate-args-warning": "<strong>Upozornění:</strong> Stránka [[:$1]] volá [[:$2]] s více než jednou hodnotou parametru „$3“. Použije se jen poslední uvedená hodnota.",
        "duplicate-args-category": "Stránky s duplicitními argumenty ve voláních šablon",
        "duplicate-args-category-desc": "Stránka obsahuje volání šablony, které používá duplicitní argumenty, např. <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> nebo <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "watchnologin": "Nejste přihlášen(a)",
        "addwatch": "Přidat do sledovaných stránek",
        "addedwatchtext": "Stránka „[[:$1]]“ a její diskusní stránka byly přidány mezi [[Special:Watchlist|stránky, které sledujete]].",
+       "addedwatchtext-talk": "„[[:$1]]“ a související stránka byly přidány mezi [[Special:Watchlist|stránky, které sledujete]].",
        "addedwatchtext-short": "Stránka „$1“ byla přidána mezi stránky, které sledujete.",
        "removewatch": "Vyřadit ze sledovaných stránek",
-       "removedwatchtext": "Stránka „[[:$1]]“ a její diskusní stránka byly vyřazeny z vašeho [[Special:Watchlist|seznamu sledovaných stránek]].",
+       "removedwatchtext": "Stránka „[[:$1]]“ a její diskusní stránka byly vyřazeny ze [[Special:Watchlist|stránek, které sledujete]]",
+       "removedwatchtext-talk": "„[[:$1]]“ a související stránka byly vyřazeny ze [[Special:Watchlist|stránek, které sledujete]].",
        "removedwatchtext-short": "Stránka „$1“ byla vyřazena z vašeho seznamu sledovaných stránek.",
        "watch": "Sledovat",
        "watchthispage": "Sledovat tuto stránku",
index 415559a..60e8456 100644 (file)
        "watchnologin": "Du bist nicht angemeldet",
        "addwatch": "Zur Beobachtungsliste hinzufügen",
        "addedwatchtext": "„[[:$1]]“ und die Diskussionsseite wurden zu deiner [[Special:Watchlist|Beobachtungsliste]] hinzugefügt.",
+       "addedwatchtext-talk": "„[[:$1]]“ und ihre dazugehörige Seite wurden zu deiner [[Special:Watchlist|Beobachtungsliste]] hinzugefügt.",
        "addedwatchtext-short": "Die Seite „$1“ wurde zu deiner Beobachtungsliste hinzugefügt.",
        "removewatch": "Von der Beobachtungsliste entfernen",
        "removedwatchtext": "„[[:$1]]“ und die Diskussionsseite wurden von deiner [[Special:Watchlist|Beobachtungsliste]] entfernt.",
+       "removedwatchtext-talk": "„[[:$1]]“ und ihre dazugehörige Seite wurden von deiner [[Special:Watchlist|Beobachtungsliste]] entfernt.",
        "removedwatchtext-short": "Die Seite „$1“ wurde von deiner Beobachtungsliste entfernt.",
        "watch": "Beobachten",
        "watchthispage": "Seite beobachten",
index a08968f..11b289a 100644 (file)
        "cannotdelete-title": "Şıma nêşenê pela \"$1\" besterê",
        "delete-hook-aborted": "Esterıtışi terefê çengeli ra ibtal bi.\nQet tesrih beyan nêbi.",
        "no-null-revision": "Qandé \"$1\" zew rewizyono newe névıraziya.",
-       "badtitle": "Sernameo xırabın",
+       "badtitle": "Sernameyo xırabın",
        "badtitletext": "Sernameyê pela ke şıma waşt, nêvêrd, vengo ya zi zıwano miyanêno ğelet gırêdaye ya zi sernameyê wiki.\nBeno ke, tede yew ya zi zêdê işareti estê ke sernameyan de nêxebetiyenê.",
        "perfcached": "Datay cı ver hazır biye. No semedê ra nıkayin niyo! tewr zaf {{PLURAL:$1|netice|$1 netice}} debêno de",
        "perfcachedts": "Cêr de malumatê nımıteyi esti, demdê newe kerdışo peyın: $1. Tewr zaf {{PLURAL:$4|netice|$4 neticey cı}} debyayo de",
        "mergehistory-empty": "Revizyonî yew nibenê.",
        "mergehistory-done": "$1 ra $3 {{PLURAL:$3|revizyon|revizyoni}} [[:$2]] de {{PLURAL:$3|biyo|biyê}} têmiyan.",
        "mergehistory-fail": "Tarixê pele yew nibeno, ma rica kenê ke pel u wext control bike.",
+       "mergehistory-fail-bad-timestamp": "Mora zemani ravêrdi niya",
+       "mergehistory-fail-invalid-source": "Çime per ravêrdi niya",
+       "mergehistory-fail-invalid-dest": "Hedef per ravêrdi niya",
+       "mergehistory-fail-permission": "Verori yewkerdışi rê mısade çıni yo.",
+       "mergehistory-fail-self-merge": "Çıne u hedef pera zey pê yê",
        "mergehistory-no-source": "Pela çımeyê $1 çıniya.",
        "mergehistory-no-destination": "Pela destinasyoni $1 çini yo.",
        "mergehistory-invalid-source": "Pela çime gani yew seroğê raşt biy.",
        "grant-oversight": "Karberan u ploğyayê revizyona bınımn",
        "grant-patrol": "Perer de vurnayışa çımra ravyarn",
        "grant-protect": "Şeveknayış u wedarıtışê şeveknayışê pelan",
+       "grant-sendemail": "Karberanê binan rê e-posta bırışê",
+       "grant-uploadeditmovefile": "Dosyaya bar ke, bıvurnê  yana berê",
        "grant-uploadfile": "Dosyaya newi bar ke",
        "grant-basic": "Heqê basiti",
        "grant-viewdeleted": "Besteryaya peran u dosyaya bıasne",
        "action-createpage": "Ena perer bıvıraze",
        "action-createtalk": "pelanê werênayışi bıvıraze",
        "action-createaccount": "hesabê nê karberi bıvıraze",
+       "action-autocreateaccount": "nê hesabê karberiyê teberi otomatik vıraze",
+       "action-history": "tarixê na pele bıvêne",
        "action-minoredit": "nê vurnayışi be qıckek işaret ke",
        "action-move": "ena pele bere",
        "action-move-subpages": "ena pele, u pelanê daê bınênan bere",
        "action-move-rootuserpages": "pelanê karberiyê bıngeyan bere",
+       "action-move-categorypages": "Pera kategoriyer ber",
        "action-movefile": "ena dosya bere",
        "action-upload": "ena dosya bar ke",
        "action-reupload": "dosyayê ke database de esto ser ey binuse",
        "action-viewmywatchlist": "Listeyseyran de xo bıvin",
        "action-viewmyprivateinfo": "Xısusi tercihane xo bıvin",
        "action-editmyprivateinfo": "Xısusi malumate xo bıvurne",
+       "action-editcontentmodel": "Zerrekê modela yu perer timar ke",
+       "action-managechangetags": "Vıraz u etiketa aktiv (me) ke",
+       "action-applychangetags": "Vurnayışana piya etiket kerdışi zi dezge fi",
+       "action-purge": "Ane perer newe ke",
        "nchanges": "$1 {{PLURAL:$1|fın vurna|fıni vurna}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ra yok wazino}}",
        "enhancedrc-history": "tarix",
        "checkbox-select": "Weçinaye: $1",
        "checkbox-all": "Pêro",
        "checkbox-none": "Temam",
-       "checkbox-invert": "Doç kerdış",
+       "checkbox-invert": "Rageyre",
        "allpages": "Peli pêro",
        "nextpage": "Pela badê cû ($1)",
        "prevpage": "Pela verêne ($1)",
        "allpagesfrom": "Pera liste kerdışi bıasne:",
        "allpagesto": "Pelanê ke be ena herfe qediyenê bımocne:",
-       "allarticles": "Wesiqey pêro",
+       "allarticles": "Peli pêro",
        "allinnamespace": "Peli pênro ( $1 cayênameyî)",
        "allpagessubmit": "Şo",
        "allpagesprefix": "herfê ke şıma tiya de nuşti, pê ney herfan pelê ke destpêkenê liste ker:",
        "whatlinkshere-hidetrans": "Açarnayışê $1",
        "whatlinkshere-hidelinks": "Gıreyê $1",
        "whatlinkshere-hideimages": "Gıreyê dosya $1",
-       "whatlinkshere-filters": "Avrêci",
+       "whatlinkshere-filters": "Parzûn",
        "whatlinkshere-submit": "Şo",
        "autoblockid": "Otomatik vındarnayış #$1",
        "block": "Karberi vındarne",
        "svg-long-desc-animated": "SVG dosya, nominalin $1 × $2 piksela, ebatê dosya: $3",
        "svg-long-error": "Nêmeqbul dosyaya SVG'i: $1",
        "show-big-image": "Dosyaya oricinale",
-       "show-big-image-preview": "Verqayd dergiya: $1'i.",
+       "show-big-image-preview": "Verqaytê dergiya: $1.",
        "show-big-image-other": "Zewmi{{PLURAL:$2|Vılêşnayış|Vılêşnayışê}}: $1.",
        "show-big-image-size": "$1 × $2 piksel",
        "file-info-gif-looped": "viyariye biyo",
        "exif-planarconfiguration": "Rezeyê datayi",
        "exif-ycbcrsubsampling": "Subsampleyi ebatê Y heta C",
        "exif-ycbcrpositioning": "pozisyonê Y u C",
-       "exif-xresolution": "Rezulasyanê veriniye",
+       "exif-xresolution": "Qerarê verıniye",
        "exif-yresolution": "Rezulasyanê derganiye",
        "exif-stripoffsets": "Cayê melumatê resımi",
        "exif-rowsperstrip": "Yew reze de teneyê dizeyi",
        "exif-referenceblackwhite": "Çiftyê siya u sipe değerê referansi",
        "exif-datetime": "Zeman u tarixê vurnayişê dosyayi",
        "exif-imagedescription": "Serê resimi",
-       "exif-make": "Viraştoğê kamera",
-       "exif-model": "Modelê kamerayi",
+       "exif-make": "Vıraştoğê kamera",
+       "exif-model": "Modelê kamera",
        "exif-software": "Software ke hebitiyeno",
        "exif-artist": "Nuştoğ",
        "exif-copyright": "Wahirê copyrighti",
        "autosumm-replace": "Maqale pê '$1' vuriya",
        "autoredircomment": "heteneya [[$1]]",
        "autosumm-new": "Pela vıraziyê, '$1' bıvinê",
+       "autosumm-newblank": "Pera veng vıraziyê",
        "size-bytes": "$1 {{PLURAL:$1|bayt|bayti}}",
        "size-kilobytes": "$1 KB",
        "size-megabytes": "$1 MB",
        "watchlistedit-raw-done": "Listeyê tuyê seyrkerdişi rocaniye biyo",
        "watchlistedit-raw-added": "{{PLURAL:$1|1 sername kerd|$1 sernamey kerdi}} cı:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|1 sername dard|$1 sernamey dardi}} we:",
+       "watchlistedit-clear-title": "Lista serykerdışê pak kerê",
+       "watchlistedit-clear-legend": "Lista serykerdışê pak kerê",
+       "watchlistedit-clear-explain": "Listeya serykerdış da şıma dı sernamey pêro besteryay",
        "watchlistedit-clear-titles": "Sernamey:",
        "watchlisttools-view": "Vurnayışanê elaqedaran bıvêne",
        "watchlisttools-edit": "Lista seyrkerdışi bıvêne û bıvurne",
index 30421d7..6ebcc19 100644 (file)
        "prefs-reset-intro": "तम ये पृष्ठलाई आफनो अभिरुचीहरू साइट पूर्वावस्थामी फर्काउनत फर्काउन प्रयोग गद्दु सकन्छौ । तै पाछा ये लाई रद्द गद्दु सकन्छौ ।",
        "prefs-emailconfirm-label": "इ-मेल एकिन प्रक्रिया:",
        "youremail": "ईमेल",
-       "username": "{{लिंग:$1|प्रयोगकर्ता नाम}}:",
-       "prefs-memberingroups": "निम्न {{बहुबचन:$1|समूह | समूहहरू}}को {{लिंग:$2|सदस्य}} :",
+       "username": "{{GENDER:$1|प्रयोगकर्ता नाम}}:",
+       "prefs-memberingroups": "निम्न {{PLURAL:$1|समूह|समूहहरू}}को {{GENDER:$2|सदस्य}} :",
        "prefs-registration": "दर्ता समय:",
        "yourrealname": "वास्तविक नाम:",
        "yourlanguage": "भाषा",
        "userrights": "प्रयोगकर्ता अधिकार व्यवस्थापन",
        "userrights-lookup-user": "प्रयोगकर्ता समूह व्यवस्थापन गर",
        "userrights-user-editname": "प्रयोगकर्ता नाम दिय:",
-       "editusergroup": "सम्पादन{{लिंग:$1}}समूहहरु",
+       "editusergroup": "{{GENDER:$1|प्रयोगकर्ता}}समूहहरू सम्पादन",
        "userrights-editusergroup": "प्रयोगकर्ता समूह सम्पादन गर",
-       "saveusergroups": "सुरक्षित{{लिंग:$1}}समूहहरु",
+       "saveusergroups": "सुरक्षित {{GENDER:$1|प्रयोगकर्ता}} समूहहरू",
        "userrights-groupsmember": "को सदस्य:",
        "userrights-groupsmember-auto": "अंतर्निहित सदस्य:",
        "userrights-reason": "कारण:",
        "group-bureaucrat": "प्रशासकहरू",
        "group-suppress": "लुकौन्या वाला",
        "group-all": "(सबै)",
-       "group-user-member": "{{लिङग:$1|प्रयोगकर्ता}}",
-       "group-autoconfirmed-member": "{{लिङग:$1|स्वनिर्धारित प्रयोगकर्ता}}",
-       "group-bot-member": "{{लिङग:$1|बोट}}",
-       "group-sysop-member": "{{लिङग:$1|प्रबन्धक}}",
-       "group-bureaucrat-member": "{{लिङग:$1|प्रशासक}}",
-       "group-suppress-member": "{{लिङग:$1|दबाउन्या}}",
+       "group-user-member": "{{GENDER:$1|प्रयोगकर्ता}}",
+       "group-autoconfirmed-member": "{{GENDER:$1|स्वनिर्धारित प्रयोगकर्ता}}",
+       "group-bot-member": "{{GENDER:$1|बोट}}",
+       "group-sysop-member": "{{GENDER:$1|प्रबन्धक}}",
+       "group-bureaucrat-member": "{{GENDER:$1|प्रशासक}}",
+       "group-suppress-member": "{{GENDER:$1|दबाउन्या}}",
        "grouppage-user": "{{एनयस:आयोजना}}:प्रयोगकर्ताहरू",
        "grouppage-autoconfirmed": "{{एनयस:आयोजना}}:स्वनिर्धारित प्रयोगकर्ताहरू",
        "grouppage-bot": "{{एनयस:आयोजना}}:बोटहरु",
        "tooltip-t-whatlinkshere": "यो सित जोडियाका सब्बै विकि पानानको सूची",
        "tooltip-t-recentchangeslinked": "यै पानामी जोडियाका पानामी अहिलको परिवर्तन",
        "tooltip-feed-atom": "यै पानाकी लेखा एक एटम फिड",
-       "tooltip-t-contributions": "यिन प्रयोगकर्ताका योगदानहरूको सूची हेरपुई",
+       "tooltip-t-contributions": "{{GENDER:$1|यिन प्रयोगकर्ता}}का योगदानहरूको सूची हेरपुई",
        "tooltip-t-upload": "चित्र अप्लोड अर",
        "tooltip-t-specialpages": "सब्बै खास खास पानानको शुचि ।",
        "tooltip-t-print": "यो पानाको छापिन्या संस्करण",
index bc7d78d..839e081 100644 (file)
        "passwordreset-emailelement": "Username:\n$1\n\nTemporary password:\n$2",
        "passwordreset-emailsentemail": "If this email address is associated with your account, then a password reset email will be sent.",
        "passwordreset-emailsentusername": "If there is an email address associated with this username, then a password reset email will be sent.",
-       "passwordreset-emailsent-capture": "A password reset email has been sent, which is shown below.",
-       "passwordreset-emailerror-capture": "A password reset email was generated, which is shown below, but sending it to the {{GENDER:$2|user}} failed: $1",
        "passwordreset-emailsent-capture2": "The password reset {{PLURAL:$1|email has|emails have}} been sent. The {{PLURAL:$1|username and password|list of usernames and passwords}} is shown below.",
        "passwordreset-emailerror-capture2": "Emailing the {{GENDER:$2|user}} failed: $1 The {{PLURAL:$3|username and password|list of usernames and passwords}} is shown below.",
        "passwordreset-nocaller": "A caller must be provided",
        "changeemail": "Change or remove email address",
        "changeemail-summary": "",
        "changeemail-header": "Complete this form to change your email address. If you would like to remove the association of any email address from your account, leave the new email address blank when submitting the form.",
-       "changeemail-passwordrequired": "You will need to enter your password to confirm this change.",
        "changeemail-no-info": "You must be logged in to access this page directly.",
        "changeemail-oldemail": "Current email address:",
        "changeemail-newemail": "New email address:",
        "undo-nochange": "The edit appears to have already been undone.",
        "undo-summary": "Undo revision $1 by [[Special:Contributions/$2|$2]] ([[User talk:$2|talk]])",
        "undo-summary-username-hidden": "Undo revision $1 by a hidden user",
-       "cantcreateaccounttitle": "Cannot create account",
        "cantcreateaccount-text": "Account creation from this IP address (<strong>$1</strong>) has been blocked by [[User:$3|$3]].\n\nThe reason given by $3 is <em>$2</em>",
        "cantcreateaccount-range-text": "Account creation from IP addresses in the range <strong>$1</strong>, which includes your IP address (<strong>$4</strong>), has been blocked by [[User:$3|$3]].\n\nThe reason given by $3 is <em>$2</em>",
        "createaccount-hook-aborted": "$1",
        "watchnologin": "Not logged in",
        "addwatch": "Add to watchlist",
        "addedwatchtext": "\"[[:$1]]\" and its discussion page have been added to your [[Special:Watchlist|watchlist]].",
+       "addedwatchtext-talk": "\"[[:$1]]\" and its associated page have been added to your [[Special:Watchlist|watchlist]].",
        "addedwatchtext-short": "The page \"$1\" has been added to your watchlist.",
        "removewatch": "Remove from watchlist",
        "removedwatchtext": "\"[[:$1]]\" and its discussion page have been removed from your [[Special:Watchlist|watchlist]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" and its associated page have been removed from your [[Special:Watchlist|watchlist]].",
        "removedwatchtext-short": "The page \"$1\" has been removed from your watchlist.",
        "watch": "Watch",
        "watchthispage": "Watch this page",
index 4975329..e6a2368 100644 (file)
        "badfilename": "Dosiernomo estis ŝanĝita al \"$1\".",
        "filetype-mime-mismatch": "Dosiera sufikso \".$1\" ne kongruas la MIME-tipon de la dosiero ($2).",
        "filetype-badmime": "Dosieroj de la MIME-tipo \"$1\" ne estas permesitaj por alŝutado.",
-       "filetype-bad-ie-mime": "Ne povas alŝuti ĉi tiun dosieron, ĉar Interreta Esplorilo detektus ĝin kiel \"$1\", kiu estas malpermesita kaj eble danĝera dosiertipo.",
+       "filetype-bad-ie-mime": "Ne povas alŝuti ĉi tiun dosieron, ĉar Internet Explorer detektus ĝin kiel dosieron “$1”, kiu estas malpermesita kaj eble danĝera dosiertipo.",
        "filetype-unwanted-type": "'''\".$1\"''' estas nevolata dosiero-tipo. {{PLURAL:$3|Preferata dosiero-tipo|Prefereataj dosiero-tipoj}} estas $2.",
        "filetype-banned-type": "'''\".$1\"''' ne estas {{PLURAL:$4|permesita dosiero-tipo|permesitaj dosiero-tipoj}}. {{PLURAL:$3|Permesita dosiero-tipo|Permesitaj dosiero-tipoj}} estas $2.",
        "filetype-missing": "Ĉi tiu dosiero ne inkluzivas finaĵon de dosiernomo (kiel \".jpg\").",
        "authmanager-provider-password-domain": "Aŭtentikigo per pasvorto kaj domajno",
        "authmanager-provider-temporarypassword": "Provizora pasvorto:",
        "authprovider-confirmlink-message": "Laŭ viaj lastatempaj provoj de ensalutado, la sekvantaj kontoj povas esti ligita al via vikia konto. Ligi ilin ebligas ensalutadon per tiuj kontoj. Bonvolu elekti tiun, kiun ligendus.",
-       "authprovider-confirmlink-request-label": "Kontoj kiuj devus esti ligita",
+       "authprovider-confirmlink-request-label": "Kontoj, kiuj devas esti ligita",
        "authprovider-confirmlink-success-line": "$1: Ligita sukcese.",
        "authprovider-confirmlink-failed": "Ligado de konto ne plene sukcesis: $1",
        "authprovider-confirmlink-ok-help": "Kontinui post montrado de mesaĝoj pri malsukceso de ligado.",
index bf01b1f..a9facb7 100644 (file)
        "tagline": "De {{SITENAME}}",
        "help": "Ayuda",
        "search": "Buscar",
-       "search-ignored-headings": " #<!-- deje esta línea tal y como está --> <pre>\n# Títulos que serán ignorados por la búsqueda.\n# Los cambios estarán en vigor tan pronto como la página con el título esté indexada.\n# Puede forzar la página a ser reindexada haciendo una edición nula.\n# La sintaxis es la siguiente: .N!\n#   * Todo, desde un carácter \"#\" al final de la línea es un comentario\n#   * Todas las líneas en blanco es un título exacto para ignorar, caso y cualquier \nReferencia\nEnlaces externos\nVéase también\n #</pre> <!-- deje esta línea tal y como está -->",
+       "search-ignored-headings": " #<!-- dejar esta línea exactamente como está --> <pre>\n# Títulos que serán ignorados por la búsqueda.\n# Los cambios estarán en vigor tan pronto como la página con el título esté indexada.\n# Puedes forzar la reindexación de una página haciendo una edición nula.\n# La sintaxis es la siguiente:\n#   * Todo lo que sigue a un carácter \"#\" hasta el final de la línea, es un comentario.\n#   * Todas las líneas que no están en blanco son los títulos exactos que se ignorarán (diferenciando mayúsculas de minúsculas).\nReferencias\nEnlaces externos\nVéase también\n #</pre> <!-- dejar esta línea exactamente como está -->",
        "searchbutton": "Buscar",
        "go": "Ir",
        "searcharticle": "Ir",
        "action-applychangetags": "aplicar etiquetas junto con los cambios",
        "action-changetags": "agregar y quitar etiquetas arbitrarias a revisiones individuales y entradas del registro",
        "action-deletechangetags": "eliminar etiquetas de la base de datos",
+       "action-purge": "purgar esta página",
        "nchanges": "$1 {{PLURAL:$1|cambio|cambios}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde la última visita}}",
        "enhancedrc-history": "historial",
index b21245b..13085dd 100644 (file)
        "mergehistory-go": "Aldaketa bateragarriak erakutsi",
        "mergehistory-submit": "Berrikuspenak bateratu",
        "mergehistory-empty": "Ezin da berrikuspenik bateratu",
-       "mergehistory-done": "$1(e)ko {{PLURAL:$3|berrikuspen|berrikuspen}} bateratu egin {{PLURAL:$3|da|dira}} [[:$2]](e)n.",
+       "mergehistory-done": "$1(e)ko {{PLURAL:$3|berrikuspen}} bateratu egin {{PLURAL:$3|da|dira}} [[:$2]](e)n.",
        "mergehistory-fail": "Ezin izan da historia bateratu; egiaztatu orrialde eta denbora parametroak.",
        "mergehistory-no-source": "Ez da $1 jatorrizko orrialdea existitzen.",
        "mergehistory-no-destination": "Ez da $1 helburu orrialdea existitzen.",
        "emailccsubject": "Zure mezuaren kopia $1(r)i: $2",
        "emailsent": "Mezua bidali egin da",
        "emailsenttext": "Zure e-posta mezua bidali egin da.",
-       "emailuserfooter": "E-posta hau $1(e)k bidali dio $2(r)i {{SITENAME}}ko \"{{int:emailuser}}\" funtzioa erabiliz.",
+       "emailuserfooter": "E-posta hau $1(e)k {{GENDER:$1|bidali}} dio {{GENDER:$2|$2}}(r)i {{SITENAME}}ko \"{{int:emailuser}}\" funtzioa erabiliz.",
        "usermessage-summary": "Sistema mezua uzten.",
        "usermessage-editor": "Sistemako mezularia",
        "watchlist": "Jarraipen zerrenda",
        "logentry-move-move_redir": "$1 {{GENDER:$2|wikilariak}} «$3» orria «$4» izenera aldatu du, birzuzenketaren gainetik",
        "logentry-move-move_redir-noredirect": "$1 {{GENDER:wikilariak}} «$3» orria «$4» izenera aldatu du, birbideratze bat gainidatzita, birbideratzerik utzi gabe",
        "logentry-patrol-patrol": "$1(e)k $3 orrialdearen $4 berrikuspena patruilatutzat {{GENDER:$2|markatu}} du",
-       "logentry-newusers-newusers": "$1 erabiltzaile kontua sortu da",
+       "logentry-newusers-newusers": "$1 erabiltzaile kontua {{GENDER:$2|sortu da}}",
        "logentry-newusers-create": "$1 erabiltzaile kontua {{GENDER:$2|sortu da}}",
        "logentry-newusers-create2": "$1 wikilariak $3 erabiltzaile kontua sortu du",
+       "logentry-newusers-byemail": "$1(e)k $3 erabiltzaile kontua {{GENDER:$2|sortu du}} eta pasahitza emailez bidali da",
        "logentry-upload-upload": "$1(e)k $3 {{GENDER:$2|igo du}}",
        "log-name-tag": "Etiketen erregistroa",
        "rightsnone": "(bat ere ez)",
        "log-action-filter-block-block": "Blokeatu",
        "log-action-filter-block-reblock": "Blokeoa aldatu",
        "log-action-filter-block-unblock": "blokeoa kendu",
+       "authmanager-userdoesnotexist": "\"$1\" erabiltzaile kontua ez dago erregistratua.",
        "authmanager-email-label": "Emaila",
        "authmanager-email-help": "Helbide elektronikoa",
        "authmanager-realname-label": "Benetako izena",
index d789cf3..28e2dd8 100644 (file)
        "watchthis": "پی‌گیری این صفحه",
        "savearticle": "صفحه ذخیره شود",
        "savechanges": "ذخیرهٔ تغییرات",
-       "publishpage": "اÙ\86تشار صفحه",
-       "publishchanges": "اÙ\86تشار تغییرات",
+       "publishpage": "ذخÛ\8cرÙ\87 صفحه",
+       "publishchanges": "ذخÛ\8cرÙ\87 تغییرات",
        "preview": "پیش‌نمایش",
        "showpreview": "پیش‌نمایش",
        "showdiff": "نمایش تغییرات",
        "notvisiblerev": "آخرین نسخه توسط کاربری دیگر حذف شده‌است",
        "watchlist-details": "بدون احتساب صفحه‌های جداگانهٔ بحث، {{PLURAL:$1|$1 صفحه|$1 صفحه}} در فهرست پی‌گیری‌های شما قرار {{PLURAL:$1|دارد|دارند}}.",
        "wlheader-enotif": "ایمیل‌های اعلان فعال است.",
-       "wlheader-showupdated": "صفحه‌هایی که پس از آخرین بازدید شما تغییر کرده‌اند '''پررنگ''' نمایش داده شده‌اند.",
+       "wlheader-showupdated": "صفحه‌هایی که پس از آخرین بازدید شما تغییر کرده‌اند <strong>پررنگ</strong> نمایش داده شده‌اند.",
        "wlnote": "در زیر {{PLURAL:$1|تغییری|<strong>$1</strong> تغییری}} که در {{PLURAL:$2|ساعت|<strong>$2</strong> ساعت}} گذشته انجام شده موجود است، تاریخ آخرین بازیابی: $3، $4",
        "wlshowlast": "نمایش آخرین $1 ساعت $2 روز",
        "watchlist-hide": "نهفتن",
        "protect-default": "همهٔ کاربرها",
        "protect-fallback": "فقط به کاربرهایی که دسترسی «$1» دارند، اجازه داده می‌شود",
        "protect-level-autoconfirmed": "تنها کاربران تأییدشده",
-       "protect-level-sysop": "فقط مدیران",
+       "protect-level-sysop": "تنها مدیران",
        "protect-summary-cascade": "آبشاری",
        "protect-expiring": "زمان سرآمدن $1 (UTC)",
        "protect-expiring-local": "منقضی $1",
index 58f56e8..116ae3a 100644 (file)
        "tagline": "De {{SITENAME}}",
        "help": "Aide",
        "search": "Rechercher",
-       "search-ignored-headings": " #<!-- laisser cette ligne comme telle --> <pre>\n# Titres de sections qui seront ignorés par la recherche\n# Les changements effectués ici prennent effet dès lors que la page avec le titre est indexée.\n# Vous pouvez forcer la réindexation de la page en effectuant une modification vide\n# La syntaxe est la suivante :\n#   * Toute ligne précédée d’un « # » est un commentaire\n#   * Toute ligne non-vide est le titre exact à ignorer, casse comprise\nRéférences\nLiens externes\nVoir aussi\n #</pre> <!-- laisser cette ligne comme telle -->",
+       "search-ignored-headings": " #<!-- laisser cette ligne comme telle --> <pre>\n# Titres des sections qui seront ignorés par la recherche\n# Les changements effectués ici prennent effet dès lors que la page avec le titre est indexée.\n# Vous pouvez forcer la réindexation de la page en effectuant une modification vide\n# La syntaxe est la suivante :\n#   * Toute ligne précédée d’un « # » est un commentaire\n#   * Toute ligne non-vide est le titre exact à ignorer, casse comprise\nRéférences\nLiens externes\nVoir aussi\n #</pre> <!-- laisser cette ligne comme telle -->",
        "searchbutton": "Rechercher",
        "go": "Consulter",
        "searcharticle": "Lire",
        "missing-article": "La base de données n’a pas trouvé le texte d’une page qu’elle aurait dû trouver, intitulée « $1 » $2.\n\nGénéralement, cela survient en suivant un lien vers un diff périmé ou vers l’historique d’une page supprimée.\n\nSi ce n’est pas le cas, il peut s’agir d’une anomalie dans le programme.\nVeuillez la signaler à un [[Special:ListUsers/sysop|administrateur]] sans oublier de lui indiquer l’URL de la page.",
        "missingarticle-rev": "(numéro de version : $1)",
        "missingarticle-diff": "(diff : $1, $2)",
-       "readonly_lag": "La base de données a été automatiquement verrouillée pendant que les serveurs secondaires rattrapent leur retard sur le serveur principal.",
-       "nonwrite-api-promise-error": "L’entête HTTP « <code>Promise-Non-Write-API-Action:<code> » a été envoyé mais la requête a été faite à un module d’écriture de l’API.",
+       "readonly_lag": "La base de données a été automatiquement verrouillée pendant que les serveurs secondaires se réalignent sur le serveur principal.",
+       "nonwrite-api-promise-error": "L’entête HTTP « <code>Promise-Non-Write-API-Action:</code> » a été envoyé mais la requête a été faite à un module d’écriture de l’API.",
        "internalerror": "Erreur interne",
        "internalerror_info": "Erreur interne : $1",
        "internalerror-fatal-exception": "Erreur fatale de type « $1 »",
        "filecopyerror": "Impossible de copier le fichier « $1 » vers « $2 ».",
        "filerenameerror": "Impossible de renommer le fichier « $1 » en « $2 ».",
        "filedeleteerror": "Impossible de supprimer le fichier « $1 ».",
-       "directorycreateerror": "Impossible de créer le dossier « $1 ».",
+       "directorycreateerror": "Impossible de créer le répertoire « $1 ».",
        "directoryreadonlyerror": "Le répertoire « $1 » est en lecture seule.",
        "directorynotreadableerror": "Le répertoire « $1 » n’est pas lisible.",
        "filenotfound": "Impossible de trouver le fichier « $1 ».",
        "passwordreset-nosuchcaller": "L’appelant n’existe pas : $1",
        "passwordreset-ignored": "La réinitialisation du mot de passe n’a pas été gérée. Peut-être qu’aucun fournisseur n’a été configuré ?",
        "passwordreset-invalideamil": "Adresse de messagerie non valide",
-       "passwordreset-nodata": "Ni un nom d’utilisateur ni une adresse de messagerie n’a  été fourni",
+       "passwordreset-nodata": "Aucun nom d’utilisateur ou adresse de messagerie n’a été fourni",
        "changeemail": "Changer ou supprimer l’adresse de courriel",
        "changeemail-header": "Complétez ce formulaire pour modifier votre adresse de courriel. Si vous voulez supprimer l’association d’une adresse de courriel avec votre compte, laissez la nouvelle adresse de courriel vide lors de la soumission du formulaire.",
        "changeemail-passwordrequired": "Vous devrez saisir votre mot de passe pour confirmer cette modification.",
        "undo-summary": "Annulation des modifications $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|discussion]])",
        "undo-summary-username-hidden": "Annuler la révision $1 par un utilisateur masqué",
        "cantcreateaccounttitle": "Vous ne pouvez pas créer de compte.",
-       "cantcreateaccount-text": "La création de compte depuis cette adresse IP (<strong>$1</strong>) a été bloquée par [[User:$3|$3]]. La raison donnée était : <em>$2</em>",
+       "cantcreateaccount-text": "La création de compte depuis cette adresse IP (<strong>$1</strong>) a été bloquée par [[User:$3|$3]]. \n\nLa raison donnée par $3 était : <em>$2</em>",
        "cantcreateaccount-range-text": "La création de compte depuis les adresses IP de la plage <strong>$1</strong>, où se trouve votre adresse IP (<strong>$4</strong>), a été bloquée par [[User:$3|$3]].\n\nLe motif fourni par $3 est <em>$2</em>",
        "viewpagelogs": "Voir les opérations sur cette page",
        "nohistory": "Il n’existe pas d’historique des modifications pour cette page.",
        "mergehistory-from": "Page d'origine :",
        "mergehistory-into": "Page de destination :",
        "mergehistory-list": "Historique fusionnable des modifications",
-       "mergehistory-merge": "Les versions suivantes de [[:$1]] peuvent être fusionnées avec [[:$2]]. Utilisez la colonne de boutons radio pour fusionner uniquement les versions créées du début jusqu'à la date indiquée. Notez bien que l'utilisation des liens de navigation réinitialisera cette colonne.",
+       "mergehistory-merge": "Les versions suivantes de [[:$1]] peuvent être fusionnées avec [[:$2]]. \nUtilisez la colonne de boutons radio pour fusionner uniquement les versions créées du début jusqu'à la date indiquée. \nNotez bien que l'utilisation des liens de navigation réinitialisera cette colonne.",
        "mergehistory-go": "Voir les modifications qui peuvent être fusionnées",
        "mergehistory-submit": "Fusionner les versions",
        "mergehistory-empty": "Aucune version ne peut être fusionnée.",
        "userrights-groupsmember-auto": "Membre implicite de :",
        "userrights-groups-help": "Vous pouvez modifier les groupes auxquels appartient {{GENDER:$1|cet utilisateur|cette utilisatrice}} :\n* Une case cochée signifie que l’utilisat{{GENDER:$1|eur|rice}} se trouve dans ce groupe.\n* Une case non cochée signifie qu’{{GENDER:$1|il|elle}} ne s’y trouve pas.\n* Un astérisque (*) indique que vous ne pouvez pas retirer ce groupe une fois que vous l’avez ajouté, ou vice-versa.",
        "userrights-reason": "Motif :",
-       "userrights-no-interwiki": "Vous n'avez pas la permission de modifier des droits d'utilisateurs sur d'autres wikis.",
-       "userrights-nodatabase": "La base de donnée « $1 » n'existe pas ou n'est pas locale.",
-       "userrights-nologin": "Vous devez vous [[Special:UserLogin|connecter]] avec un compte d'administrateur pour modifier des droits d'utilisateur.",
-       "userrights-notallowed": "Vous n’avez pas la permission d’ajouter ou supprimer des droits d’utilisateur.",
+       "userrights-no-interwiki": "Vous n'avez pas la permission de modifier les droits utilisateur sur d'autres wikis.",
+       "userrights-nodatabase": "La base de données « $1 » n'existe pas ou n'est pas locale.",
+       "userrights-nologin": "Vous devez vous [[Special:UserLogin|connecter]] avec un compte d'administrateur pour modifier les droits utilisateur.",
+       "userrights-notallowed": "Vous n’avez pas la permission d’ajouter ou de supprimer des droits utilisateur.",
        "userrights-changeable-col": "Les groupes que vous pouvez modifier",
        "userrights-unchangeable-col": "Les groupes que vous ne pouvez pas modifier",
-       "userrights-conflict": "Conflit de modification de droits utilisateur ! Veuillez relire et confirmer vos modifications.",
+       "userrights-conflict": "Conflit de modification des droits utilisateur ! Veuillez relire et confirmer vos modifications.",
        "userrights-removed-self": "Vous avez supprimé vos propres droits. Par conséquent, vous ne pouvez plus accéder à cette page.",
        "group": "Groupe :",
        "group-user": "Utilisateurs",
        "right-createtalk": "Créer des pages de discussion",
        "right-createaccount": "Créer des comptes utilisateur",
        "right-autocreateaccount": "Connexion automatique avec un compte utilisateur externe",
-       "right-minoredit": "Marquer ses modifications comme mineures",
+       "right-minoredit": "Marquer les modifications comme mineures",
        "right-move": "Renommer des pages",
        "right-move-subpages": "Renommer des pages avec leurs sous-pages",
        "right-move-rootuserpages": "Renommer la page principale d'un utilisateur",
        "right-move-categorypages": "Renommer des pages de catégorie",
        "right-movefile": "Renommer des fichiers",
-       "right-suppressredirect": "Ne pas créer de redirection depuis le titre d'origine en renommant une page",
+       "right-suppressredirect": "Ne pas créer de redirection depuis le titre d'origine en renommant les pages",
        "right-upload": "Importer des fichiers",
        "right-reupload": "Écraser un fichier existant",
        "right-reupload-own": "Écraser un fichier que l'on a soi-même importé",
-       "right-reupload-shared": "Écraser localement un fichier présent sur un dépôt partagé",
+       "right-reupload-shared": "Écraser localement des fichiers présents sur un dépôt partagé",
        "right-upload_by_url": "Importer un fichier depuis une adresse URL",
-       "right-purge": "Purger le cache des pages sans demande de confirmation",
+       "right-purge": "Effacer une page du cache local sans demander de confirmation",
        "right-autoconfirmed": "Ne pas être affecté par les limitations de débit liées aux adresses IP",
        "right-bot": "Être traité comme un processus automatisé",
        "right-nominornewtalk": "Ne pas déclencher la notification de nouveau message lorsqu'on effectue une modification mineure sur la page de discussion d'un utilisateur",
        "right-writeapi": "Utiliser l'API de modification du wiki",
        "right-delete": "Supprimer des pages",
        "right-bigdelete": "Supprimer des pages ayant un gros historique",
-       "right-deletelogentry": "Supprimer et restaurer une entrée particulière du journal",
-       "right-deleterevision": "Supprimer ou restaurer une version particulière d'une page",
+       "right-deletelogentry": "Supprimer et restaurer des entrées particulières du journal",
+       "right-deleterevision": "Supprimer ou restaurer des versions particulières de pages",
        "right-deletedhistory": "Voir les entrées des historiques supprimées, mais sans leur texte",
        "right-deletedtext": "Voir le texte supprimé et les différences entre les versions supprimées",
        "right-browsearchive": "Rechercher des pages supprimées",
        "right-editmyuserjs": "Modifier vos propres fichiers JavaScript utilisateur",
        "right-viewmywatchlist": "Afficher votre propre liste de suivi",
        "right-editmywatchlist": "Modifier votre propre liste de suivi. Remarquez que certaines actions ajouteront encore des pages sans ce droit.",
-       "right-viewmyprivateinfo": "Voir vos données personnelles (exemple adresse, vrai nom)",
-       "right-editmyprivateinfo": "Modifier vos données personnelles (exemple adresse, vrai nom)",
+       "right-viewmyprivateinfo": "Voir vos données personnelles (par exemple votre adresse, votre vrai nom)",
+       "right-editmyprivateinfo": "Modifier vos données personnelles (par exemple votre adresse, votre vrai nom)",
        "right-editmyoptions": "Modifier vos préférences",
        "right-rollback": "Révoquer rapidement les modifications du dernier contributeur d'une page particulière",
        "right-markbotedits": "Marquer des modifications révoquées comme ayant été faites par un robot.",
        "right-noratelimit": "Ne pas être affecté par les limites de taux",
        "right-import": "Importer des pages depuis d'autres wikis",
        "right-importupload": "Importer des pages depuis un fichier",
-       "right-patrol": "Marquer des modifications des autres comme relues",
+       "right-patrol": "Marquer les modifications des autres comme étant relues",
        "right-autopatrol": "Avoir ses modifications automatiquement marquées comme relues",
        "right-patrolmarks": "Voir les marquages de relecture dans les modifications récentes",
        "right-unwatchedpages": "Voir la liste des pages non suivies",
        "right-mergehistory": "Fusionner les historiques des pages",
        "right-userrights": "Modifier tous les droits d'un utilisateur",
-       "right-userrights-interwiki": "Modifier les droits d'utilisateurs qui sont sur un autre wiki",
+       "right-userrights-interwiki": "Modifier les droits des utilisateurs qui sont sur d'autres wikis",
        "right-siteadmin": "Verrouiller ou déverrouiller la base de données",
        "right-override-export-depth": "Exporter les pages en incluant les pages liées jusqu'à une profondeur de 5 niveaux",
        "right-sendemail": "Envoyer un courriel aux autres utilisateurs",
        "grant-editprotected": "Modifier des pages protégées",
        "grant-highvolume": "Modification de gros volumes",
        "grant-oversight": "Masquer les utilisateurs et supprimer les révisions",
-       "grant-patrol": "Patrouiller les modifications aux pages",
+       "grant-patrol": "Vérifier les modifications de pages",
        "grant-protect": "Protéger et déprotéger des pages",
        "grant-rollback": "Révoquer des modifications sur des pages",
        "grant-sendemail": "Envoyer des courriels aux autres utilisateurs",
        "newsectionsummary": "/* $1 */ nouvelle section",
        "rc-enhanced-expand": "Voir les détails",
        "rc-enhanced-hide": "Masquer les détails",
-       "rc-old-title": "créé avec le titre « $1 »",
+       "rc-old-title": "créé initialement avec le titre « $1 »",
        "recentchangeslinked": "Suivi des pages liées",
        "recentchangeslinked-feed": "Suivi des pages liées",
        "recentchangeslinked-toolbox": "Suivi des pages liées",
        "recentchangeslinked-title": "Suivi des pages associées à « $1 »",
-       "recentchangeslinked-summary": "Cette page spéciale montre les modifications récentes sur les pages qui sont liées. Les pages de votre liste de suivi sont '''en gras'''.",
+       "recentchangeslinked-summary": "Voici les modifications faites récemment sur des pages liées depuis une page spécifique ou vers des membres d'une catégorie spécifique. \nLes pages de [[Special:Watchlist|votre liste de suivi]] sont <strong>en gras</strong>.",
        "recentchangeslinked-page": "Nom de la page :",
        "recentchangeslinked-to": "Afficher les modifications des pages qui comportent un lien vers la page donnée plutôt que l'inverse",
        "recentchanges-page-added-to-category": "[[:$1]] ajouté à la catégorie",
        "autochange-username": "Modification automatique de MediaWiki",
        "upload": "Importer un fichier",
        "uploadbtn": "Importer le fichier",
-       "reuploaddesc": "Annuler et retourner au formulaire d'import",
+       "reuploaddesc": "Annuler l'importation et retourner au formulaire d'import",
        "upload-tryagain": "Envoyer la description du fichier modifiée",
        "uploadnologin": "Non connecté",
        "uploadnologintext": "Vous devez vous $1 pour importer des fichiers.",
        "upload_directory_missing": "Le répertoire d’import de fichier ($1) est introuvable et n’a pas pu être créé par le serveur web.",
-       "upload_directory_read_only": "Le répertoire d’import de fichier ($1) n’est pas accessible en écriture depuis le serveur web.",
+       "upload_directory_read_only": "Le serveur web n’a pas accès en écriture au répertoire d’import de fichier ($1).",
        "uploaderror": "Erreur lors de l’import",
        "upload-recreate-warning": "'''Attention : Un fichier portant ce nom a été supprimé ou déplacé.'''\n\nLe journal des suppressions et celui des déplacements de cette page sont affichés ici pour informations :",
        "uploadtext": "Utilisez ce formulaire pour importer des fichiers sur le serveur.\nPour voir ou rechercher des images précédemment envoyées, consultez la [[Special:FileList|liste des images]]. L’import est aussi enregistré dans le [[Special:Log/upload|journal d’import des fichiers]], et les suppressions dans le [[Special:Log/delete|journal des suppressions]].\n\nPour inclure un fichier dans une page, utilisez un lien de la forme :\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:fichier.jpg]]</nowiki></code>''', pour afficher le fichier en pleine résolution (dans le cas d’une image) ;\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:fichier.png|200px|thumb|left|texte descriptif]]</nowiki></code>''' pour utiliser une miniature de 200 pixels de large dans une boîte à gauche avec « texte descriptif » comme description ;\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:fichier.ogg]]</nowiki></code>''' pour lier directement vers le fichier sans l’afficher.",
        "upload-preferred": "{{PLURAL:$2|Format|Formats}} de fichiers {{PLURAL:$2|préféré|préférés}} : $1.",
        "upload-prohibited": "‎{{PLURAL:$2|Format|Formats}} de fichiers {{PLURAL:$2|interdit|interdits}} : $1.",
        "uploadlogpage": "Journal d’import de fichiers",
-       "uploadlogpagetext": "Voici la liste des derniers fichiers importés sur le serveur.\nVoyez la [[Special:NewFiles|galerie des nouvelles images]] pour une présentation plus visuelle.",
+       "uploadlogpagetext": "Voici les derniers fichiers téléversés.\nVoyez la [[Special:NewFiles|galerie des nouveaux fichiers]] pour une représentation plus visuelle.",
        "filename": "Nom du fichier",
        "filedesc": "Description",
        "fileuploadsummary": "Description :",
        "filestatus": "Statut du droit d'auteur :",
        "filesource": "Source :",
        "ignorewarning": "Ignorer l'avertissement et sauvegarder le fichier quand même",
-       "ignorewarnings": "Ignorer les avertissements",
-       "minlength1": "Le noms de fichiers doivent comprendre au moins une lettre.",
-       "illegalfilename": "Le nom de fichier « $1 » contient des caractères interdits dans les titres de pages. Merci de le renommer et de l'importer à nouveau.",
-       "filename-toolong": "Le nom du fichier ne peut pas dépasser 240 octets.",
+       "ignorewarnings": "Ignorer tous les avertissements",
+       "minlength1": "Les noms de fichiers doivent comprendre au moins une lettre.",
+       "illegalfilename": "Le nom de fichier « $1 » contient des caractères interdits dans les titres de pages. \nMerci de le renommer et de l'importer à nouveau.",
+       "filename-toolong": "Les noms de fichier ne peuvent pas dépasser 240 octets.",
        "badfilename": "Le fichier a été renommé en « $1 ».",
        "filetype-mime-mismatch": "L'extension du fichier « .$1 » ne correspond pas au type MIME détecté du fichier ($2).",
-       "filetype-badmime": "Les fichiers du type MIME « $1 » ne peuvent pas être importés.",
+       "filetype-badmime": "Les fichiers de type MIME « $1 » ne peuvent pas être importés.",
        "filetype-bad-ie-mime": "Le fichier ne peut pas être importé parce qu'il serait détecté comme « $1 » par Internet Explorer, ce qui correspond à un type de fichier interdit car potentiellement dangereux.",
-       "filetype-unwanted-type": "'''« .$1 »''' est un format de fichier non désiré.\n{{PLURAL:$3|Le type de fichier préconisé est|Les types de fichiers préconisés sont}} $2.",
-       "filetype-banned-type": "''' « .$1 » '''{{PLURAL:$4|n'est pas un type de fichier autorisé|ne sont pas des types de fichiers autorisés}}. \n{{PLURAL:$3|le type de fichier autorisé est |les types de fichiers autorisés sont}} $2.",
+       "filetype-unwanted-type": "<strong>« .$1 »</strong> est un format de fichier non désiré.\n{{PLURAL:$3|Le type de fichier préconisé est|Les types de fichiers préconisés sont}} $2.",
+       "filetype-banned-type": "<strong>« .$1 »</strong>{{PLURAL:$4|n'est pas un type de fichier autorisé|ne sont pas des types de fichiers autorisés}}. \n{{PLURAL:$3|Le type de fichier autorisé est |Les types de fichiers autorisés sont}} $2.",
        "filetype-missing": "Le fichier n'a aucune extension (comme « .jpg » par exemple).",
        "empty-file": "Le fichier que vous avez soumis était vide.",
        "file-too-large": "Le fichier que vous avez soumis était trop grand.",
        "fileexists": "Un fichier existe déjà sous ce nom.\nMerci de vérifier <strong>[[:$1]]</strong> si vous n'êtes pas certain{{GENDER:||e|}} de vouloir le remplacer.\n[[$1|thumb]]",
        "filepageexists": "La page de description pour ce fichier a déjà été créée ici <strong>[[:$1]]</strong>, mais aucun fichier n'existe actuellement sous ce nom.\nLe résumé que vous allez spécifier n'apparaîtra pas sur la page de description.\nPour que ce soit le cas, vous devrez modifier manuellement la page. [[$1|thumb]]",
        "fileexists-extension": "Un fichier existe avec un nom proche : [[$2|thumb]]\n* Nom du fichier à importer : <strong>[[:$1]]</strong>\n* Nom du fichier existant : <strong>[[:$2]]</strong>\nPeut-être voulez-vous utiliser un nom plus explicite ?",
-       "fileexists-thumbnail-yes": "Le fichier semble être une image en taille réduite ''(vignette)''. [[$1|thumb]]\nVeuillez vérifier le fichier <strong>[[:$1]]</strong>.\nSi le fichier vérifié est la même image avec la taille initiale, il n'y a pas besoin d'importer une version réduite.",
-       "file-thumbnail-no": "Le nom du fichier commence par <strong>$1</strong>.\nIl est possible qu'il s'agisse d'une version réduite ''(vignette)''.\nSi vous disposez du fichier en haute résolution, importez-le, sinon veuillez modifier son nom.",
-       "fileexists-forbidden": "Un fichier avec ce nom existe déjà et ne peut pas être écrasé.\nSi vous voulez toujours importer votre fichier, veuillez revenir en arrière et utiliser un autre nom. [[File:$1|thumb|center|$1]]",
-       "fileexists-shared-forbidden": "Un fichier portant ce nom existe déjà dans le dépôt de fichiers partagé.\nSi vous voulez toujours importer votre fichier, veuillez revenir en arrière et utiliser un autre nom. [[File:$1|thumb|center|$1]]",
+       "fileexists-thumbnail-yes": "Le fichier semble être une image en taille réduite <em>(vignette)</em>. \n[[$1|thumb]]\nVeuillez vérifier le fichier <strong>[[:$1]]</strong>.\nSi le fichier vérifié est la même image avec la taille initiale, il n'y a pas besoin d'importer une version réduite.",
+       "file-thumbnail-no": "Le nom du fichier commence par <strong>$1</strong>.\nIl est possible qu'il s'agisse d'une version réduite <em>(vignette)</em>.\nSi vous disposez du fichier en haute résolution, importez-le, sinon veuillez modifier son nom.",
+       "fileexists-forbidden": "Un fichier avec ce nom existe déjà et ne peut pas être écrasé.\nSi vous voulez toujours importer votre fichier, veuillez revenir en arrière et utiliser un autre nom. \n[[File:$1|thumb|center|$1]]",
+       "fileexists-shared-forbidden": "Un fichier portant ce nom existe déjà dans le dépôt de fichiers partagé.\nSi vous voulez toujours importer votre fichier, veuillez revenir en arrière et utiliser un autre nom. \n[[File:$1|thumb|center|$1]]",
        "file-exists-duplicate": "Ce fichier est un doublon {{PLURAL:$1|du fichier suivant|des fichiers suivants}} :",
-       "file-deleted-duplicate": "Un fichier identique à celui-ci ([[:$1]]) a déjà été supprimé. Vous devriez vérifier le journal des suppressions de ce fichier avant de l'importer à nouveau.",
+       "file-deleted-duplicate": "Un fichier identique à celui-ci ([[:$1]]) a déjà été supprimé. \nVous devriez vérifier le journal des suppressions de ce fichier avant de l'importer à nouveau.",
        "file-deleted-duplicate-notitle": "Un fichier identique à ce fichier a déjà été supprimé ainsi que le titre. \nVous devriez demander à quelqu'un la possibilité de vérifier le journal de ce fichier supprimé afin d'examiner la situation  avant de l'importer à nouveau.",
        "uploadwarning": "Attention !",
        "uploadwarning-text": "Modifiez la description du fichier et essayez de nouveau.",
        "watchthisupload": "Suivre ce fichier",
        "filewasdeleted": "Un fichier avec ce nom a déjà été importé, puis supprimé.\nVous devriez vérifier le $1 avant de l'importer à nouveau.",
        "filename-thumb-name": "Ce titre ressemble à celui d’une vignette. Évitez d’importer des vignettes d’une image déjà présente sur le wiki. Si ce n’est pas le cas, veuillez corriger le nom de fichier afin qu’il soit plus descriptif et qu’il ne commence pas comme un titre de vignette.",
-       "filename-bad-prefix": "Le nom du fichier commence par '''« $1 »''' qui est typiquement un nom attribué automatiquement par les appareils photo numériques.\nVeuillez choisir un nom de fichier descriptif.",
+       "filename-bad-prefix": "Le nom du fichier commence par <strong>« $1 »</strong> qui est typiquement un nom non-descriptif attribué automatiquement par les appareils photo numériques.\nVeuillez choisir un nom de fichier plus descriptif.",
        "filename-prefix-blacklist": " #<!-- laisser cette ligne telle quelle --><pre>\n# La syntaxe est la suivante :\n#  * Tout ce qui figure entre un caractère \"#\" jusqu’à la fin de la ligne est un commentaire ;\n#  * Toute ligne non vide est un préfixe typique de nom de fichier assigné automatiquement par les appareils numériques :\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # certains téléphones mobiles\nIMG # générique\nJD # Jenoptik\nMGP # Pentax\nPICT # divers\n #</pre><!-- laisser cette ligne telle quelle -->",
        "upload-proto-error": "Protocole incorrect",
        "upload-proto-error-text": "L’import requiert des URL commençant par <code>http://</code> ou <code>ftp://</code>.",
        "upload-file-error": "Erreur interne",
-       "upload-file-error-text": "Une erreur interne est survenue en voulant créer un fichier temporaire sur le serveur. Veuillez contacter un [[Special:ListUsers/sysop|administrateur]].",
+       "upload-file-error-text": "Une erreur interne est survenue en voulant créer un fichier temporaire sur le serveur. \nVeuillez contacter un [[Special:ListUsers/sysop|administrateur]].",
        "upload-misc-error": "Erreur d’import inconnue",
        "upload-misc-error-text": "Une erreur inconnue est survenue pendant l’import.\nVeuillez vérifier que l’URL est valide et accessible, puis essayer à nouveau.\nSi le problème persiste, contactez un [[Special:ListUsers/sysop|administrateur]].",
        "upload-too-many-redirects": "L’URL contient trop de redirections.",
        "watchnologin": "Non connecté",
        "addwatch": "Ajouter à la liste de suivi",
        "addedwatchtext": "La page « [[:$1]] » et sa page de discussion ont été ajoutées à votre [[Special:Watchlist|liste de suivi]].",
+       "addedwatchtext-talk": "« [[:$1]] » et sa page associée ont été ajoutés à votre [[Special:Watchlist|liste de suivi]].",
        "addedwatchtext-short": "La page « $1 » a été ajoutée à votre liste de suivi.",
        "removewatch": "Supprimer de la liste de suivi",
        "removedwatchtext": "La page « [[:$1]] » et sa page de discussion ont été retirées de votre [[Special:Watchlist|liste de suivi]].",
+       "removedwatchtext-talk": "« [[:$1]] » et sa page associée ont été supprimés de votre [[Special:Watchlist|liste de suivi]].",
        "removedwatchtext-short": "La page « $1 » a été supprimée de votre liste de suivi.",
        "watch": "Suivre",
        "watchthispage": "Suivre cette page",
index 4476955..f729895 100644 (file)
        "enhancedrc-history": "historial",
        "recentchanges": "Cambios recentes",
        "recentchanges-legend": "Opcións dos cambios",
-       "recentchanges-summary": "Nesta páxina pode seguir as modificacións máis recentes feitas no wiki.",
+       "recentchanges-summary": "Nesta páxina podes seguir as modificacións máis recentes feitas no wiki.",
        "recentchanges-noresult": "Non se produciron cambios que coincidisen con eses criterios durante o período especificado.",
        "recentchanges-feed-description": "Nesta fonte de novas pode seguir as modificacións máis recentes feitas no wiki.",
        "recentchanges-label-newpage": "Esta edición creou unha nova páxina",
        "watchnologin": "Non accedeu ao sistema",
        "addwatch": "Engadir á lista vixilancia",
        "addedwatchtext": "A páxina \"[[:$1]]\" e mais a súa conversa foron engadidas á súa [[Special:Watchlist|lista de vixilancia]].",
+       "addedwatchtext-talk": "\"[[:$1]]\" xunto coa súa páxina asociada foron engadidas á túa [[Special:Watchlist|lista de vixilancia]].",
        "addedwatchtext-short": "A páxina \"$1\" foi engadida á súa lista de vixilancia.",
        "removewatch": "Eliminar da lista de vixilancia",
        "removedwatchtext": "A páxina \"[[:$1]]\" e mais a súa conversa foron eliminadas da súa [[Special:Watchlist|lista de vixilancia]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" xunto coa súa páxina asociada foron eliminadas da túa [[Special:Watchlist|lista de vixilancia]].",
        "removedwatchtext-short": "A páxina \"$1\" foi eliminada da súa lista de vixilancia.",
        "watch": "Vixiar",
        "watchthispage": "Vixiar esta páxina",
index 0aeca39..090585a 100644 (file)
@@ -12,7 +12,7 @@
                ]
        },
        "tog-previewonfirst": "𐌰𐍄𐌰𐌿𐌲𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍃𐌹𐌿𐌽 𐌰𐍄 𐍆𐍂𐌿𐌼𐌹𐍃𐍄𐌰 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽",
-       "underline-always": "Sinteino",
+       "underline-always": "𐍃𐌹𐌽𐍄𐌴𐌹𐌽𐍉",
        "underline-never": "𐌽𐌹 𐌰𐌹𐍅",
        "sunday": "𐌰𐍆𐌰𐍂𐍃𐌰𐌱𐌱𐌰𐍄𐍉",
        "monday": "𐌼𐌴𐌽𐌹𐌽𐍃 𐌳𐌰𐌲𐍃",
@@ -73,7 +73,7 @@
        "pagecategories": "{{PLURAL:$1|𐌺𐌿𐌽𐌹|𐌺𐌿𐌽𐌾𐌰}}",
        "category_header": "𐌻𐌰𐌿𐌱𐍉𐍃 𐌹𐌽 𐌺𐌿𐌽𐌾𐌰 \"$1\"",
        "subcategories": "𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽𐌰 𐌺𐌿𐌽𐌾𐌰",
-       "category-media-header": "𐌼𐌴𐌳𐌾𐌰 𐌹𐌽𐌽 𐌺𐌿𐌽𐌾𐌰 \"$1\"",
+       "category-media-header": "𐌼𐌴𐌳𐌾𐌰 𐌹𐌽 𐌺𐌿𐌽𐌾𐌰 \"$1\"",
        "hidden-categories": "{{PLURAL:$1|𐌰𐍆𐍆𐌹𐌻𐌷𐌰𐌽 𐌺𐌿𐌽𐌹|𐌰𐍆𐍆𐌹𐌻𐌷𐌰𐌽𐌰 𐌺𐌿𐌽𐌾𐌰}}",
        "hidden-category-category": "𐌰𐍆𐍆𐌹𐌻𐌷𐌰𐌽𐌰 𐌺𐌿𐌽𐌾𐌰",
        "category-subcat-count": "{{PLURAL:$2|𐌸𐌰𐍄𐌰 𐌺𐌿𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐌸 𐌸𐌰𐍄𐌴𐌹𐌽𐌴𐌹 𐌹𐍆𐍄𐌿𐌼 𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽 𐌺𐌿𐌽𐌹|𐌸𐌰𐍄𐌰 𐌺𐌿𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐌸 {{PLURAL:$1|𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽 𐌺𐌿𐌽𐌹|𐌹𐍆𐍄𐌿𐌼𐌰 $1 𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽𐌰 𐌺𐌿𐌽𐌾𐌰}}, 𐌰𐌻𐌻𐌰𐌹𐌶𐌴 $2 𐌺𐌿𐌽𐌾𐌴.}}",
        "projectpage": "𐌰𐌽𐌳𐌷𐌿𐌻𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍅𐌰𐌿𐍂𐍀𐌰𐌻𐌰𐌿𐍆",
        "viewhelppage": "𐌰𐌽𐌳𐌷𐌿𐌻𐌴𐌹 𐌷𐌹𐌻𐍀𐌰𐌻𐌰𐌿𐍆",
        "otherlanguages": "𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐍂𐌰𐌶𐌳𐍉𐌼",
-       "redirectedfrom": "(𐌹𐍃 𐍄𐌹𐌿𐌷𐌰𐌽𐍃/𐍄𐌹𐌿𐌷𐌰𐌽𐌰 𐌷𐌹𐌳𐍂𐌴 𐍆𐍂𐌰𐌼 $1)",
+       "redirectedfrom": "(𐌹𐍃 {{GENDER:𐍄𐌹𐌿𐌷𐌰𐌽𐍃|𐍄𐌹𐌿𐌷𐌰𐌽𐌰}} 𐌷𐌹𐌳𐍂𐌴 𐍆𐍂𐌰𐌼 $1)",
        "redirectpagesub": "𐌰𐌻𐌾𐌰𐍂 𐌱𐍂𐌹𐌲𐌲𐌰𐌽𐌳𐍃 𐌻𐌰𐌿𐍆𐍃",
        "lastmodifiedat": "𐍃𐌰 𐌻𐌰𐌿𐍆𐍃 𐌸𐌰𐍄𐌰 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄 𐌹𐌽𐌼𐌰𐌹𐌳𐌹𐌸𐍃 𐍅𐌰𐍃 ($1) ($2).",
        "protectedpage": "𐍆𐍂𐌹𐌸𐍉𐌽𐍃 𐌻𐌰𐌿𐍆𐍃",
        "pool-errorunknown": "𐌽𐌰𐍃𐌴𐌹 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆",
        "aboutsite": "𐌱𐌹 {{SITENAME}}",
        "aboutpage": "Project:𐌱𐌹",
-       "copyrightpage": "{{ns:project}}:ð\90\8c¼ð\90\8c°ð\90\8c½ð\90\8c»ð\90\8c´ð\90\8c¹ð\90\8cºð\90\8c°ð\90\8d\85ð\90\8c¹ð\90\8d\84ð\90\8d\89ð\90\8c¸ð\90\8c°",
-       "currentevents": "ð\90\8c½ð\90\8c¹ð\90\8c¿ð\90\8c¾ð\90\8c° 𐍅𐌰𐌹𐌷𐍄𐍃",
-       "currentevents-url": "Project:ð\90\8c½ð\90\8c¹ð\90\8c¿ð\90\8c¾ð\90\8c° 𐍅𐌰𐌹𐌷𐍄𐍃",
+       "copyrightpage": "{{ns:project}}:ð\90\8c±ð\90\8d\82ð\90\8c¿ð\90\8cºð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c¹ð\90\8d\82ð\90\8c°ð\90\8c¹ð\90\8c·ð\90\8d\84ð\90\8c´ð\90\8c¹ð\90\8d\83",
+       "currentevents": "ð\90\8c°ð\90\8c½ð\90\8c³ð\90\8d\85ð\90\8c°ð\90\8c¹ð\90\8d\82ð\90\8c¸ð\90\8d\89ð\90\8d\83 ð\90\8d\85ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c¸ð\90\8c°ð\90\8c½ð\90\8d\89ð\90\8d\83 𐍅𐌰𐌹𐌷𐍄𐍃",
+       "currentevents-url": "Project:ð\90\8c°ð\90\8c½ð\90\8c³ð\90\8d\85ð\90\8c°ð\90\8c¹ð\90\8d\82ð\90\8c¸ð\90\8d\89ð\90\8d\83 ð\90\8d\85ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c¸ð\90\8c°ð\90\8c½ð\90\8d\89ð\90\8d\83 𐍅𐌰𐌹𐌷𐍄𐍃",
        "disclaimers": "𐌲𐌰𐍂𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐍂𐌰𐌹𐌷𐍄𐌰𐌹𐍃",
        "disclaimerpage": "Project:𐌲𐌰𐌼𐌰𐌹𐌽𐌰 𐌲𐌰𐍂𐌰𐌹𐌳𐌴𐌹𐌽𐍃 𐍂𐌰𐌹𐌷𐍄𐌰𐌹𐍃",
-       "edithelp": "𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌷𐌹𐌻𐍀𐌰",
+       "edithelp": "ð\90\8c¹ð\90\8c½ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c¹ð\90\8c·ð\90\8c¹ð\90\8c»ð\90\8d\80ð\90\8c°",
        "mainpage": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃",
        "mainpage-description": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃",
        "portal": "𐌱𐌰𐌿𐍂𐌲𐍃 𐌲𐌰𐍅𐌹",
        "hidetoc": "𐌰𐍆𐍆𐌹𐌻𐌷",
        "confirmable-yes": "𐌾𐌰",
        "confirmable-no": "𐌽𐌴",
-       "site-rss-feed": "$1 RSS Miþnatifodjan",
-       "site-atom-feed": "$1 ð\90\8c°ð\90\8d\84ð\90\8d\89ð\90\8c¼ ð\90\8d\86ð\90\8d\89ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8d\83",
+       "site-rss-feed": "$1 RSS 𐍂𐌹𐌽𐌽𐍉",
+       "site-atom-feed": "$1 ð\90\8c°ð\90\8d\84ð\90\8d\89ð\90\8c¼ ð\90\8d\82ð\90\8c¹ð\90\8c½ð\90\8c½ð\90\8d\89",
        "page-atom-feed": "\"$1\" 𐌰𐍄𐍉𐌼 𐍂𐌹𐌽𐌽𐍉",
        "red-link-title": "$1 (𐌻𐌰𐌿𐍆𐍃 𐌽𐌹𐍃𐍄)",
        "nstab-main": "𐌻𐌰𐌿𐍆𐍃",
        "nstab-special": "𐌿𐍃𐍃𐌹𐌽𐌳𐍃 𐌻𐌰𐌿𐍆𐍃",
        "nstab-project": "𐍆𐌰𐌿𐍂𐌰𐍅𐌰𐌿𐍂𐍀𐌰𐌻𐌰𐌿𐍆𐍃",
        "nstab-image": "𐍆𐌴𐌹𐌻𐌰",
-       "nstab-template": "ð\90\8d\86ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c°ð\90\8c¼ð\90\8c´ð\90\8c»ð\90\8c´ð\90\8c¹ð\90\8c½𐍃",
+       "nstab-template": "ð\90\8d\83ð\90\8cºð\90\8c´ð\90\8c¹ð\90\8d\82ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c¹ð\90\8d\86ð\90\8d\82ð\90\8c¹ð\90\8d\83ð\90\8c°ð\90\8c·ð\90\8d\84𐍃",
        "nstab-help": "𐌷𐌹𐌻𐍀𐌰𐌻𐌰𐌿𐍆𐍃",
        "nstab-category": "𐌺𐌿𐌽𐌹",
        "mainpage-nstab": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃",
        "createacct-yourpassword-ph": "𐌼𐌴𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳",
        "createacct-yourpasswordagain": "𐌲𐌰𐍃𐌹𐌲𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳",
        "createacct-yourpasswordagain-ph": "𐌼𐌴𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳 𐌰𐍆𐍄𐍂𐌰",
-       "userlogin-remembermypassword": "𐌲𐌰𐍆𐌰𐍃𐍄 𐌼𐌹𐌺 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌽𐌰/𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰",
+       "userlogin-remembermypassword": "𐌲𐌰𐍆𐌰𐍃𐍄 𐌼𐌹𐌺 {{GENDER:𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌽𐌰|𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰}}",
        "login": "𐌰𐍄𐌲𐌰𐌲𐌲",
-       "nav-login-createaccount": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽 / 𐌲𐌰𐌻𐌰𐌽𐌲𐌾𐌰𐌽 𐌽𐌹𐌿𐍄𐌰𐌽𐌳𐌹𐍃",
-       "userlogin": "Atgaggan / gaskapjan niutandis",
+       "nav-login-createaccount": "𐌰𐍄𐌲𐌰𐌲𐌲 / 𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
+       "userlogin": "𐌰𐍄𐌲𐌰𐌲𐌲 / 𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
        "userloginnocreate": "𐌰𐍄𐌲𐌰𐌲𐌲",
        "logout": "𐌰𐍆𐌻𐌴𐌹𐌸",
        "userlogout": "𐌰𐍆𐌻𐌴𐌹𐌸",
        "userlogin-noaccount": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽?",
-       "userlogin-joinproject": "ð\90\8c²ð\90\8c°ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c½𐌴𐌹 {{SITENAME}}",
+       "userlogin-joinproject": "ð\90\8c²ð\90\8c°ð\90\8c³ð\90\8c°ð\90\8c¹ð\90\8c»𐌴𐌹 {{SITENAME}}",
        "nologinlink": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
        "createaccount": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
        "gotaccount": "𐌾𐌿 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽 𐌷𐌰𐌱𐌰𐌹𐍃? $1.",
        "extlink_tip": "𐌿𐍄𐌰𐌲𐌰𐍅𐌹𐍃𐍃 (𐌲𐌰𐌼𐌹𐌽𐌸𐌴𐌹 http:// 𐍆𐌰𐌿𐍂𐌰𐌻𐌰𐌲𐌴𐌹𐌽𐍃)",
        "headline_sample": "𐌿𐍆𐌰𐍂𐍃𐍄𐍂𐌹𐌺𐌰𐌱𐍉𐌺𐍉𐍃",
        "headline_tip": "𐌷𐌰𐌿𐌷𐌹𐌸𐌰 •𐌱• 𐌿𐍆𐌰𐍂𐍃𐍄𐍂𐌹𐌺𐍃",
-       "nowiki_sample": "ð\90\8d\83ð\90\8c°ð\90\8d\84ð\90\8c¾ð\90\8c´ð\90\8c¹ ð\90\8c¿ð\90\8c½ð\90\8d\83ð\90\8c½ð\90\8c´ð\90\8c¹ð\90\8c¸ð\90\8c¾ð\90\8c°ð\90\8c½ð\90\8c³ð\90\8d\83 ð\90\8d\84ð\90\8c´ð\90\8cºð\90\8d\83ð\90\8d\84 ð\90\8c±ð\90\8d\89ð\90\8cºð\90\8c°ð\90\8d\85ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c³ð\90\8c°ð\90\8c¼ ð\90\8c·ð\90\8c¹ð\90\8d\84",
+       "nowiki_sample": "ð\90\8d\83ð\90\8c°ð\90\8d\84ð\90\8c´ð\90\8c¹ ð\90\8c±ð\90\8d\89ð\90\8cºð\90\8d\89ð\90\8d\83 ð\90\8c¹ð\90\8c½ð\90\8c¿ð\90\8c· ð\90\8c²ð\90\8c°ð\90\8d\82ð\90\8d\85ð\90\8c¹ ð\90\8c·ð\90\8c´ð\90\8d\82",
        "nowiki_tip": "𐌿𐌽𐍅𐌹𐍄𐌾𐌹𐍃 𐍅𐌹𐌺𐌹𐍃𐌽𐌴𐌹𐌸𐌾𐌰𐌽𐌳𐍃",
        "image_tip": "𐌹𐌽𐌽𐌱𐍉𐌳𐌰𐌽𐍃 𐍆𐌴𐌹𐌻𐌰",
        "media_tip": "𐍄𐌰𐌹𐌺𐌾𐌰𐌱𐌰𐌽𐌳𐌾𐌹𐍃 𐍆𐌴𐌹𐌻𐌰𐌽𐌹𐍃",
        "sig_tip": "𐌸𐌴𐌹𐌽𐌰 𐌿𐍆𐌼𐌴𐌻𐌴𐌹𐌽𐍃 𐌼𐌹𐌸 𐌲𐌻𐌰𐌲𐌲𐍅𐌰𐌼𐌼𐌰 𐌼𐌴𐌻𐌰",
-       "hr_tip": "𐍂𐌰𐌹𐌷𐍄𐍃𐌱𐌰𐌿𐍂𐌳 (𐌱𐍂𐌿𐌺𐌾𐌰𐌽 𐌼𐌹𐌸 𐌽𐌹𐌿𐍆𐌰𐍂𐌿𐍃𐍃𐌿𐍃)",
+       "hr_tip": "𐍂𐌰𐌹𐌷𐍄𐍃 𐍃𐍄𐍂𐌹𐌺𐍃 (𐌽𐌹 𐌱𐍂𐌿𐌺𐌴𐌹 𐌿𐍆𐌰𐍂𐍆𐌹𐌻𐌿)",
        "summary": "𐌼𐌰𐌿𐍂𐌲𐌿𐍃 𐍃𐌺𐌴𐌹𐍂𐌴𐌹𐌽𐍃:",
        "subject": "𐌿𐍆𐍅𐌰𐌿𐍂𐍀𐌰:",
        "minoredit": "𐌸𐌰𐍄𐌰 𐌹𐍃𐍄 𐌼𐌹𐌽𐌽𐌹𐌶𐌴𐌹 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍃",
        "updated": "(𐌰𐌽𐌰𐌽𐌹𐍅𐌹𐌸)",
        "previewnote": "<strong>𐌲𐌰𐌼𐌹𐌽𐌸𐌴𐌹 𐌸𐌰𐍄𐌴𐌹 𐌸𐌰𐍄𐌰 𐌹𐍃𐍄 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍃𐌹𐌿𐌽𐍃.</strong>\n𐌸𐌴𐌹𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌽𐌰𐌿𐌷 𐌽𐌹 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌽𐍉𐍃 𐍃𐌹𐌽𐌳!",
        "editing": "{{GENDER:𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹}} $1",
-       "creating": "𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐍃/𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐌴𐌹 $1",
+       "creating": "{{GENDER:𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐍃|𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐌴𐌹}} $1",
        "editingsection": "{{GENDER:𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹}} $1 (𐌳𐌰𐌹𐌻)",
-       "editingcomment": "𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃/𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹 $1 (𐌽𐌹𐌿𐌾𐌰 𐌳𐌰𐌹𐌻)",
-       "yourdiff": "ð\90\8c¼ð\90\8c¹ð\90\8d\83ð\90\8d\83ð\90\8c°ð\90\8c»ð\90\8c´ð\90\8c¹ð\90\8cº𐍉𐍃",
+       "editingcomment": "{{GENDER:𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹}} $1 (𐌽𐌹𐌿𐌾𐌰 𐌳𐌰𐌹𐌻)",
+       "yourdiff": "ð\90\8c²ð\90\8c°ð\90\8d\83ð\90\8cºð\90\8c°ð\90\8c¹ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8c½𐍉𐍃",
        "template-protected": "(𐌷𐌰𐌱𐌰𐌹𐌸 𐌼𐌿𐌽𐌳)",
-       "template-semiprotected": "(halb-gabaírgjan)",
+       "template-semiprotected": "(𐌷𐌰𐌱𐌰𐌹𐌸 𐌷𐌰𐌻𐌱𐌰𐌼𐌿𐌽𐌸)",
        "hiddencategories": "𐍃𐌰 𐌻𐌰𐌿𐍆𐍃 𐌹𐍃𐍄 𐌲𐌰𐌳𐌰𐌹𐌻𐌰 {{PLURAL:$1|1 𐌰𐌽𐌰𐌻𐌰𐌿𐌲𐌽𐌹𐍃 𐌺𐌿𐌽𐌾𐌹𐍃|$1 𐌰𐌽𐌰𐌻𐌰𐌿𐌲𐌽𐌰𐌹𐌶𐌴 𐌺𐌿𐌽𐌾𐌴}}:‎",
        "permissionserrorstext-withaction": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐌳𐌿 $2, 𐌹𐌽 {{PLURAL:$1|𐌹𐍆𐍄𐌿𐌼𐌰𐌹𐌶𐍉𐍃 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃|𐌹𐍆𐍄𐌿𐌼𐌰𐌹𐌶𐍉 𐍅𐌰𐌹𐌷𐍄𐌴}}:",
        "moveddeleted-notice": "𐍃𐌰 𐌻𐌰𐌿𐍆𐍃 𐌿𐍃𐌽𐌿𐌼𐌰𐌽𐍃 𐌹𐍃𐍄. 𐌿𐍃𐌽𐌿𐌼𐍄𐍃 𐌾𐌰𐌷 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹𐌽𐍃 𐌼𐌹𐌸𐍃𐌰𐍄𐌴𐌹𐌽𐌰𐌹𐍃 𐌿𐍆 𐍃𐌹𐌽𐌳 𐌿𐍃𐍄𐌰𐌹𐌺𐌽𐌴𐌹𐌽𐌰𐌹.",
        "searchall": "𐌰𐌻𐌻𐍃",
        "search-showingresults": "{{ZPLURAL:$4|𐍄𐌰𐌿𐌹 <strong>$1 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃 <strong>$3|𐍄𐍉𐌾𐌰 <strong>$1 - $2 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃 <strong>$3}}",
        "search-nonefound": "𐌽𐌹 𐍄𐌰𐌿𐌹 𐍅𐌰𐍃 𐍃𐌰𐌼𐌰𐌽𐌰 𐍃𐍅𐌰 𐍃𐍉𐌺𐌴𐌹𐌽.",
-       "powersearch-legend": "𐍃𐍉𐌺𐌴𐌹𐌸",
+       "powersearch-legend": "𐍃𐍉𐌺𐌴𐌹",
        "preferences": "𐌼𐌴𐌹𐌽𐍉𐍃 𐌱𐍂𐌿𐌺𐌾𐌰𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌴𐌹𐍃",
        "mypreferences": "𐌲𐌰𐌻𐌴𐌹𐌺𐌰𐌽𐌳𐌴𐌹𐌽𐍃 𐍅𐌰𐌹𐌷𐍄𐍃",
-       "prefs-skin": "Seidofill",
+       "prefs-skin": "𐍆𐌹𐌻𐌻",
        "skin-preview": "Faúrsaiƕa",
-       "saveprefs": "Melja",
-       "searchresultshead": "Sokeiþ",
+       "saveprefs": "𐌲𐌰𐍆𐌰𐍃𐍄",
+       "searchresultshead": "𐍃𐍉𐌺𐌴𐌹",
        "grouppage-sysop": "{{ns:project}}:𐍃𐌴𐌹𐌳𐍉𐍆𐌰𐌸𐍃",
        "right-writeapi": "𐌱𐍂𐌿𐌺𐌴𐌹𐌽𐍃 API 𐌼𐌴𐌻𐌴𐌹𐌽𐌰𐌹𐍃",
        "rightslog": "Niutandis stutjanlog",
        "diff": "𐌼𐌹𐍃𐍃",
        "hist": "𐍃𐍀𐌹𐌻𐌻",
        "hide": "𐍆𐌹𐌻𐌷𐌰𐌽",
-       "show": "ð\90\8c·ð\90\8c¿ð\90\8c»ð\90\8c¾ð\90\8c°ð\90\8c½",
+       "show": "ð\90\8c°ð\90\8d\84ð\90\8c°ð\90\8c¿ð\90\8c²ð\90\8c´ð\90\8c¹",
        "minoreditletter": "l",
        "newpageletter": "N",
        "boteditletter": "b",
        "imagelinks": "𐌱𐍂𐌿𐌺𐌴𐌹𐌽𐍃 𐍆𐌰𐌴𐌹𐌻𐌴",
        "linkstoimage": "𐌰𐍆𐍄𐌿𐌼𐌰 {{PLURAL:$1|𐍃𐍉 𐍃𐌴𐌹𐌳𐍉 𐌻𐌴𐌹𐌽𐌺𐍉𐌸|𐌸𐍉𐍃 𐍃𐌴𐌹𐌳𐍉𐌽𐍃 𐌻𐌴𐌹𐌽𐌺𐍉𐌽𐌳}} 𐌸𐌹𐌶𐍉𐌶𐌿𐌷 𐍆𐌴𐌹𐌻𐍉𐍃",
        "sharedupload-desc-here": "𐍃𐍉 𐌳𐌰𐍄𐌰 𐌹𐍃𐍄 𐍆𐍂𐌰𐌼 $1 𐌾𐌰𐌷 𐌼𐌰𐌲 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰 𐍆𐍂𐌰𐌼 𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐍆𐌰𐌿𐍂𐌰𐍅𐌰𐌿𐍂𐍀𐍉𐌼.\n𐌲𐌰𐍃𐌺𐌴𐌹𐍂𐌴𐌹𐌽𐍃 𐌰𐌽𐌰 𐍃𐌴𐌹𐌽𐌰𐌼𐌼𐌰 [$2 𐌳𐌰𐍄𐌰 𐍃𐌺𐌴𐌹𐍂𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐌱𐌰] 𐌾𐌰𐌹𐌽𐌰𐍂 𐌰𐍄𐌰𐌿𐌲𐌹𐌸𐍃 𐌹𐍃𐍄 𐌿𐍆.",
-       "filedelete-submit": "Taíran",
-       "mimesearch": "MIME sokeiþ",
+       "filedelete-submit": "𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌴𐌹",
+       "mimesearch": "MIME 𐍃𐍉𐌺𐌴𐌹",
        "listredirects": "𐍄𐌰𐌻𐌰 𐌰𐍆 𐍄𐌰𐌹𐌺𐌾𐌰𐌽𐍃𐌴𐌹𐌳𐍉𐍃",
        "randompage": "𐌸𐌿𐍃 𐌿𐌽𐌺𐌿𐌽𐌸𐍃 𐌻𐌰𐌿𐍆𐍃",
-       "statistics": "ð\90\8d\83ð\90\8c´ð\90\8c¹ð\90\8c³ð\90\8d\89ð\90\8d\83ð\90\8d\84ð\90\8c°ð\90\8d\84ð\90\8c¹ð\90\8d\83ð\90\8d\84ð\90\8c¹ð\90\8cº",
+       "statistics": "ð\90\8d\82ð\90\8c°ð\90\8c¸ð\90\8c¾ð\90\8d\89ð\90\8c½ð\90\8d\83",
        "brokenredirects-edit": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹",
        "brokenredirects-delete": "(𐍄𐌰𐌹𐍂𐌰𐌽)",
        "nbytes": "$1 {{PLURAL:$1|𐌱𐌹𐍄|𐌱𐌰𐍄𐌰}}",
        "ncategories": "$1 {{PLURAL:$1|𐌺𐌿𐌽𐌾𐌰|𐌺𐌿𐌽𐌾𐍉𐍃}}",
-       "nlinks": "$1 {{PLURAL:$1|táikjanbandi|táikjanbandja}}",
+       "nlinks": "$1 {{PLURAL:$1|𐌲𐌰𐍅𐌹𐍃𐍃|𐌲𐌰𐍅𐌹𐍃𐍃𐌴𐌹𐍃}}",
        "nmembers": "$1 {{PLURAL:$1|niutand|niutanda}}",
        "wantedpages": "𐌲𐌰𐌹𐍂𐌽𐌹𐌳𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃",
-       "shortpages": "ð\90\8c»ð\90\8c´ð\90\8c¹ð\90\8d\84ð\90\8c¹ð\90\8c»ð\90\8c° ð\90\8d\83ð\90\8c´ð\90\8c¹ð\90\8c³𐍉𐍃",
+       "shortpages": "ð\90\8c¼ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c²ð\90\8c°ð\90\8c¹ ð\90\8c»ð\90\8c°ð\90\8c¿ð\90\8c±𐍉𐍃",
        "longpages": "𐌻𐌰𐌲𐌲𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃",
        "listusers": "𐍂𐌴𐌲𐌹𐍃𐍄𐍂𐌴𐍂𐌰𐌳𐌴 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐍃",
        "newpages": "𐌽𐌹𐌿𐌾𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃",
        "allpagessubmit": "𐌲𐌰𐌲𐌲",
        "categories": "𐌺𐌿𐌽𐌾𐌰",
        "linksearch-ns": "𐍃𐌴𐌹𐌳𐍉𐍆𐌴𐍂𐌰:",
-       "emailuser": "𐍃𐌰𐌽𐌳𐌾𐌰𐌽 𐌸𐍉 𐌽𐌹𐌿𐍄𐌰𐌽𐌳 𐌱𐍉𐌺𐍉𐌼",
+       "emailuser": "{{GENDER: 𐍃𐌰𐌽𐌳𐌴𐌹 𐌴-𐌱𐍉𐌺𐍉𐍃 𐌳𐌿 𐌸𐌰𐌼𐌼𐌰 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳|𐍃𐌰𐌽𐌳𐌴𐌹 𐌴-𐌱𐍉𐌺𐍉𐍃 𐌳𐌿 𐌸𐌹𐌶𐌰𐌹 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌾𐌰𐌹}}",
        "watchlist": "𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉",
        "mywatchlist": "𐌻𐌰𐌹𐍃𐍄𐌰𐌻𐌴𐌹𐍃𐍄𐌰",
        "watch": "𐍅𐌰𐍂𐌰𐌽",
        "rollbacklink": "𐌰𐍆𐍅𐌰𐌻𐍅𐌴𐌹",
        "rollbacklinkcount": "𐌰𐍆𐍅𐌰𐌻𐍅𐌴𐌹 $1 {{PLURAL:$1|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌽𐍃}}",
        "protectlogpage": "Log af Baírgjan",
-       "prot_1movedto2": "[[$1]] skiubiþ du [[$2]]",
+       "prot_1movedto2": "[[$1]] 𐌼𐌹𐌸𐍃𐌰𐍄𐌹𐌸 𐌳𐌿 [[$2]]",
        "protect-level-sysop": "𐌰𐌽𐌳𐌻𐌴𐍄𐌹𐌸 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐍂𐌴𐌹𐌺𐍃",
        "protect-expiring": "𐌿𐍃𐍄𐌹𐌿𐌷𐌹𐌸 $1 (UTC)",
        "restriction-type": "Freihals:",
        "undeletebtn": "𐌰𐍆𐍄𐍂𐌰 𐌲𐌰𐌱𐍉𐍄𐌾𐌰𐌽",
        "undeletelink": "𐍃𐌰𐌹𐍈𐌰𐌽/𐌰𐍆𐍄𐍂𐌰𐌲𐌰𐍃𐌰𐍄𐌾𐌰𐌽",
        "undeleteviewlink": "𐍃𐌰𐌹𐍈𐌹𐍃",
-       "undelete-search-submit": "Sokeiþ",
+       "undelete-search-submit": "𐍃𐍉𐌺𐌴𐌹",
        "namespace": "𐌽𐌰𐌼𐌰𐍂𐌿𐌼:",
-       "invert": "Afwandjan kustus",
+       "invert": "𐌲𐌰𐍅𐌰𐌽𐌳𐌴𐌹 𐌸𐌰𐍄𐌰 𐌲𐌰𐍅𐌰𐌻𐌹𐌳𐍉",
        "blanknamespace": "(𐍆𐍂𐌿𐌼𐌹𐍃𐍄𐍃)",
        "contributions": "𐌱𐌹𐌰𐌿𐌺𐌰𐌹𐌽𐌴𐌹𐍃 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌹𐍃 {{{{GENDER:$1|User}}",
        "mycontris": "𐌱𐌹𐌰𐌿𐌺𐌰𐌹𐌽𐌴𐌹𐍃",
        "istemplate": "ináukan",
        "whatlinkshere-prev": "{{PLURAL:$1|aftuma|aftumans $1}}",
        "whatlinkshere-next": "{{PLURAL:$1|iftuma|iftumans $1}}",
-       "whatlinkshere-links": "← táikajanbandja",
+       "whatlinkshere-links": "← 𐌲𐌰𐍅𐌹𐍃𐍃𐌴𐌹𐍃",
        "whatlinkshere-hidelinks": "$1 𐌲𐌰𐍅𐌹𐍃𐍃𐌴𐌹𐍃",
        "blockip": "𐍆𐌰𐌿𐍂𐌳𐌰𐌼𐌼𐌴𐌹 {{GENDER:$1|user}}",
        "ipbreason": "𐍆𐌰𐌹𐍂𐌹𐌽𐌰:",
        "ipboptions": "𐌱 𐌰𐍅𐍂𐌰:2 hours, 𐌰 𐌳𐌰𐌲𐍃:1 day, 𐌲 𐌳𐌰𐌲𐍉𐍃:3 days, 𐌰 𐍅𐌹𐌺𐍉:1 week, 𐌱 𐍅𐌹𐌺𐍉𐌽𐍃:2 weeks, 𐌰 𐌼𐌴𐌽𐍉𐌸𐍃:1 month, 𐌲 𐌼𐌴𐌽𐍉𐌸𐍉𐍃:3 months, 𐌵 𐌼𐌴𐌽𐍉𐌸𐍉𐍃:6 months, 𐌰 𐌾𐌴𐍂:1 year, 𐌹𐌽𐌿𐍄𐍂𐌹𐌲𐌲𐌴𐌽𐌳𐌴𐌹𐍃:infinite",
-       "ipblocklist-submit": "Sokeiþ",
-       "infiniteblock": "ajukduþs",
+       "ipblocklist-submit": "𐍃𐍉𐌺𐌴𐌹",
+       "infiniteblock": "𐌰𐌽𐌳𐌰𐌻𐌰𐌿𐍃",
        "blocklink": "𐍆𐌰𐌿𐍂𐌳𐌰𐌼𐌼𐌴𐌹",
        "unblocklink": "𐍅𐌰𐌽𐌳𐌾𐌰𐌽",
        "change-blocklink": "𐌲𐌰𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐍅𐌰𐌿𐍂𐌾𐌰𐍅𐌰𐌳𐌳𐌾𐌿𐍃",
        "newtitle": "𐌽𐌹𐌿𐌾𐌹 𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹:",
        "move-watch": "𐌰𐍄𐍅𐌹𐍄 𐌱𐍂𐌿𐌽𐌽𐌰𐌻𐌰𐌿𐌱𐌰 𐌾𐌰𐌷 𐌼𐌿𐌽𐌳𐍂𐌴𐌹𐌻𐌰𐌿𐌱𐌰",
        "movepagebtn": "𐍃𐌺𐌹𐌿𐌱𐌰 𐍃𐌴𐌹𐌳𐍉",
-       "movelogpage": "Log af skiubans",
+       "movelogpage": "𐌼𐌹𐌸𐍃𐌰𐍄𐌴𐌹 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹𐌽",
        "movereason": "𐍆𐌰𐌹𐍂𐌹𐌽𐌰:",
        "revertmove": "𐍂𐌰𐌹𐌳𐌾𐌰𐌽",
        "export": "𐌿𐍄𐌱𐌰𐌹𐍂 𐌻𐌰𐌿𐌱𐌰𐌽𐍃",
        "thumbnail-more": "\n𐌼𐌹𐌺𐌹𐌻𐌴𐌹",
        "tooltip-pt-userpage": "{{GENDER:|Your user}} 𐌻𐌰𐌿𐍆𐍃",
-       "tooltip-pt-mytalk": "{{GENDER:|Your}} 𐌻𐌰𐌿𐍆𐍃 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌹𐍃",
+       "tooltip-pt-mytalk": "{{GENDER:|𐌸𐌴𐌹𐌽𐍃}} 𐌻𐌰𐌿𐍆𐍃 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌹𐍃",
        "tooltip-pt-preferences": "{{GENDER:|Your}} 𐌲𐌰𐌻𐌴𐌹𐌺𐌰𐌽𐌳𐌴𐌹𐌽𐍃 𐍅𐌰𐌹𐌷𐍄𐍃",
        "tooltip-pt-watchlist": "𐍅𐌹𐌺𐍉 𐌻𐌰𐌿𐌱𐌴 𐌸𐌹𐌶𐌴𐌴𐌹 𐌰𐍄𐍅𐌰𐌹𐍃𐍄 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌼",
        "tooltip-pt-mycontris": "A list of {{GENDER:|your}} 𐌱𐌹𐌰𐌿𐌺𐌰𐌹𐌽𐌴𐌹𐍃 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌹𐍃",
        "tooltip-ca-delete": "𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌴𐌹 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰",
        "tooltip-ca-move": "𐌼𐌹𐌸𐍃𐌰𐍄𐌴𐌹 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆",
        "tooltip-ca-watch": "𐌱𐌹𐌰𐌹𐌰𐌿𐌺 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆 𐌳𐌿 𐌸𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽",
-       "tooltip-search": "ð\90\8d\83ð\90\8d\89ð\90\8cºð\90\8c¾ð\90\8c°ð\90\8c½ {{SITENAME}}",
+       "tooltip-search": "ð\90\8d\83ð\90\8d\89ð\90\8cºð\90\8c´ð\90\8c¹ {{SITENAME}}",
        "tooltip-search-go": "𐌾𐌰𐌱𐌰𐌹 𐌹𐍃𐍄, 𐌲𐌰𐌲𐌲 𐌳𐌿 𐌻𐌰𐌿𐌱𐌰 𐌼𐌹𐌸 𐍃𐌰𐌼𐌹𐌽 𐌽𐌰𐌼𐌹𐌽.",
        "tooltip-search-fulltext": "𐍃𐍉𐌺𐌴𐌹 𐌻𐌰𐌿𐌱𐌰𐌽𐍃 𐌸𐌰𐌹𐌼 𐌱𐍉𐌺𐍉𐌼",
        "tooltip-p-logo": "𐌲𐌰𐍅𐌴𐌹𐍃 𐌷𐌰𐌿𐌱𐌹𐌳𐌰𐌻𐌰𐌿𐌱𐌹𐍃",
        "tooltip-ca-nstab-special": "𐍃𐌰 𐌹𐍃𐍄 𐌿𐍃𐍃𐌹𐌽𐌳𐍃 𐌻𐌰𐌿𐍆𐍃 𐌾𐌰𐌷 𐌽𐌹 𐌼𐌰𐌲 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌳𐌰.",
        "tooltip-ca-nstab-project": "𐌰𐍄𐌰𐌿𐌲𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍅𐌰𐌿𐍂𐍀𐌰𐌻𐌰𐌿𐍆",
        "tooltip-ca-nstab-image": "𐍃𐌰𐌹𐍈 𐍆𐌰𐌴𐌹𐌻𐌰𐌻𐌰𐌿𐍆",
-       "tooltip-ca-nstab-template": "𐍃𐌰𐌹𐍈𐌹𐍃 𐍆𐌰𐌿𐍂𐌰𐌼𐌴𐌻𐌴𐌹𐌽",
+       "tooltip-ca-nstab-template": "𐍃𐌰𐌹𐍈 𐍆𐌰𐌿𐍂𐌰𐌼𐌴𐌻𐌴𐌹𐌽",
        "tooltip-ca-nstab-category": "𐍃𐌰𐌹𐍈 𐌺𐌿𐌽𐌾𐌰𐌻𐌰𐌿𐍆",
        "tooltip-save": "𐌲𐌰𐍆𐌰𐍃𐍄 𐌸𐌴𐌹𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌽𐍃",
        "tooltip-preview": "𐍆𐌰𐌿𐍂𐌰𐍃𐌰𐌹𐍈 𐌸𐌴𐌹𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃. 𐌱𐌹𐌳𐌾𐌰𐌼 𐌸𐌿𐌺, 𐌱𐍂𐌿𐌺𐌴𐌹 𐌸𐌹𐍃 𐌸𐌰𐍄𐌰 𐍆𐍂𐌿𐌼𐌹𐍃𐍄 𐍆𐌰𐌿𐍂𐌸𐌹𐌶𐌴𐌹 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹𐍃.",
        "show-big-image": "𐍆𐍂𐌿𐌼𐌹𐍃𐍄𐌰 𐌳𐌰𐍄𐌰",
        "show-big-image-preview": "𐌼𐌹𐌺𐌹𐌻𐌴𐌹 𐌸𐌹𐌶𐍉𐍃 𐍆𐌰𐌿𐍂𐌰𐍃𐌹𐌿𐌽𐌰𐌹𐍃: $1.",
        "show-big-image-size": "$1 × $2 𐍆𐍂𐌹𐍃𐌰𐌷𐍄𐌹𐍃𐍄𐌰𐌱𐌴𐌹𐍃",
-       "ilsubmit": "Sokeiþ",
+       "ilsubmit": "𐍃𐍉𐌺𐌴𐌹",
        "metadata": "𐌿𐍆𐌰𐍂𐌳𐌰𐍄𐌰",
        "exif-colorspace": "𐍆𐌰𐍂𐍅𐌰𐍂𐌿𐌼",
        "exif-orientation-1": "𐌱𐌹 𐌱𐌹𐌿𐌷𐍄𐌾𐌰",
        "namespacesall": "𐌰𐌻𐌻",
        "monthsall": "𐌰𐌻𐌻",
-       "imgmultigo": "Afgaggan!",
+       "imgmultigo": "𐌲𐌰𐌲𐌲!",
        "table_pager_limit_submit": "Affgaggan",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌰]])",
        "version-other": "Anþar",
index 2182253..807ce58 100644 (file)
        "november-date": "નવેમ્બર $1",
        "december-date": "ડિસેમ્બર $1",
        "pagecategories": "{{PLURAL:$1|શ્રેણી|શ્રેણીઓ}}",
-       "category_header": "શ્રેણી \"$1\"માં પાના",
+       "category_header": "શ્રેણી \"$1\" ના પાનાં",
        "subcategories": "ઉપશ્રેણીઓ",
        "category-media-header": "શ્રેણી \"$1\"માં દ્રશ્ય કે શ્રાવ્ય સભ્યો",
        "category-empty": "''આ શ્રેણીમાં હાલમાં કોઇ લેખ કે અન્ય સભ્ય નથી.''",
index 87def58..b4b9c89 100644 (file)
        "prefs-help-prefershttps": "העדפה זו תיכנס לתוקף בכניסה הבאה לחשבון.",
        "prefswarning-warning": "ביצעת שינויים בהעדפות שלך, והם עדיין לא נשמרו.\nעזיבת דף זה ללא לחיצה על \"$1\" תגרום לכך שההעדפות שלך לא יעודכנו.",
        "prefs-tabs-navigation-hint": "טיפ: ניתן להשתמש במקשי החצים הימני והשמאלי כדי לנווט בין הלשוניות ברשימת הלשוניות.",
-       "userrights": "ניהול הרשאות {{GENDER:{{BASEPAGENAME}}|משתמש|משתמשת}}",
+       "userrights": "ניהול הרשאות משתמש",
        "userrights-lookup-user": "ניהול קבוצות משתמש",
        "userrights-user-editname": "שם משתמש:",
        "editusergroup": "עריכת הקבוצות של ה{{GENDER:$1|משתמש}}",
        "watchnologin": "לא נכנסת לחשבון",
        "addwatch": "הוספה לרשימת המעקב",
        "addedwatchtext": "הדף \"[[:$1]]\" ודף השיחה שלו נוספו ל[[Special:Watchlist|רשימת המעקב]] שלך.",
+       "addedwatchtext-talk": "הדף \"[[:$1]]\" ודף התוכן המשויך אליו נוספו ל[[Special:Watchlist|רשימת המעקב]] שלך.",
        "addedwatchtext-short": "הדף \"$1\" נוסף לרשימת המעקב.",
        "removewatch": "הסרה מרשימת המעקב",
        "removedwatchtext": "הדף \"[[:$1]]\" ודף השיחה שלו הוסרו מ[[Special:Watchlist|רשימת המעקב]] שלך.",
+       "removedwatchtext-talk": "הדף \"[[:$1]]\" ודף התוכן המשויך אליו הוסרו מ[[Special:Watchlist|רשימת המעקב]] שלך.",
        "removedwatchtext-short": "הדף \"$1\" הוסר מרשימת המעקב.",
        "watch": "מעקב",
        "watchthispage": "מעקב אחרי דף זה",
index ca05a97..17f116b 100644 (file)
@@ -70,7 +70,7 @@
        "tog-watchlisthidebots": "Sakrij uređivanja botova s popisa praćenja",
        "tog-watchlisthideminor": "Sakrij manje promjene s popisa praćenja",
        "tog-watchlisthideliu": "Sakrij uređivanja prijavljenih s popisa praćenja",
-       "tog-watchlistreloadautomatically": "Automatski ponovno pokreni nadzornu listu kad god dođe do promjene filtra (potreban JavaScript)",
+       "tog-watchlistreloadautomatically": "Ponovno učitaj popis praćenja kad god dođe do promjene filtra (potreban JavaScript)",
        "tog-watchlisthideanons": "Sakrij uređivanja neprijavljenih s popisa praćenja",
        "tog-watchlisthidepatrolled": "Sakrij pregledane izmjene u popisu praćenja",
        "tog-watchlisthidecategorization": "Sakrij kategorizaciju stranica",
        "botpasswords-label-create": "Stvori",
        "botpasswords-label-update": "Ažuriraj",
        "botpasswords-label-cancel": "Odustani",
-       "botpasswords-label-resetpassword": "Reset lozinke",
+       "botpasswords-label-resetpassword": "Ponovno postavljanje lozinke",
        "botpasswords-insert-failed": "Nije moguće dodavanje imena bota \"$1\". Možda je već dodano?",
        "resetpass_forbidden": "Lozinka ne može biti promijenjena",
        "resetpass-no-info": "Morate biti prijavljeni da biste izravno pristupili ovoj stranici.",
        "prefs-advancedwatchlist": "Napredne mogućnosti",
        "prefs-displayrc": "Prikaži opcije",
        "prefs-displaywatchlist": "Mogućnosti prikaza",
-       "prefs-diffs": "razl",
+       "prefs-diffs": "Razlike između inačica uređivanja",
        "prefs-help-prefershttps": "Ova mogućnost će stupiti na snagu kod sljedeće prijave.",
        "prefswarning-warning": "Napravili ste promjene u Vašim postavkama koje još nisu snimljene.\nAko napustite ovu stranicu bez pritiska na \"$1\", postavke neće biti ažurirane.",
        "prefs-tabs-navigation-hint": "Savjet: možete rabiti tipke sa strjelicama lijevo i desno za prebacivanje između kartica na popisu kartica.",
        "grant-blockusers": "Blokiraj i odblokiraj korisnike",
        "grant-createaccount": "Otvori račune",
        "grant-createeditmovepage": "Stvori, uredi i premjesti stranice",
-       "grant-editmyoptions": "Izmjeni korisničke postavke",
+       "grant-editmyoptions": "Uredi korisničke postavke",
        "grant-highvolume": "Uređivanja velikog opsega",
        "grant-basic": "Osnovna prava",
        "grant-viewdeleted": "Prikaz izbrisanih datoteka i stranica",
        "recentchangeslinked-summary": "Ova posebna stranica pokazuje nedavne promjene na povezanim stranicama (ili stranicama određene kategorije). Stranice koje su na [[Special:Watchlist|Vašem popisu praćenja]] su '''podebljane'''.",
        "recentchangeslinked-page": "Naslov stranice:",
        "recentchangeslinked-to": "Pokaži promjene na stranicama s poveznicom na ovu stranicu",
-       "recentchanges-page-added-to-category": "[[:$1]] dodana u kategoriju",
+       "recentchanges-page-added-to-category": "[[:$1]] dodano u kategoriju",
        "recentchanges-page-removed-from-category": "[[:$1]] uklonjeno iz kategorije",
        "upload": "Postavi datoteku",
        "uploadbtn": "Postavi datoteku",
        "protectedpages-reason": "Razlog",
        "protectedpages-submit": "Prikaži stranice",
        "protectedpages-unknown-timestamp": "Nepoznato",
-       "protectedpages-unknown-performer": "Nepoznati korisnik",
+       "protectedpages-unknown-performer": "Nepoznati suradnik",
        "protectedtitles": "Zaštićeni naslovi",
        "protectedtitlesempty": "Nijedan naslov nije trenutačno zaštićen s tim parametrima.",
        "protectedtitles-submit": "Prikaži nazive",
        "activeusers-hidebots": "Sakrij botove",
        "activeusers-hidesysops": "Sakrij administratore",
        "activeusers-noresult": "Niti jedan suradnik nije nađen.",
-       "activeusers-submit": "Prikaz aktivnih sudionika",
+       "activeusers-submit": "Prikaz aktivnih suradnika",
        "listgrouprights": "Prava suradničkih skupina",
        "listgrouprights-summary": "Ovo je popis suradničkih skupina određenih na ovoj wiki, s njihovim pripadajućim pravima.\nDodatne informacije o pojedinim pravim se mogu pronaći [[{{MediaWiki:Listgrouprights-helppage}}|ovdje]].",
        "listgrouprights-key": "* <span class=\"listgrouprights-granted\">Dodijeljeno pravo</span>\n* <span class=\"listgrouprights-revoked\">Ukinuto pravo</span>",
        "rollback-success": "uklonjeno uređivanje {{GENDER:$1|suradnika|suradnice}} $1\nvraćeno na posljednju inačicu {{GENDER:$2|suradnika|suradnice}} $2.",
        "sessionfailure-title": "Prekid sesije",
        "sessionfailure": "Uočili smo problem s Vašom prijavom. Zadnja naredba nije izvršena kako bi se izbjegla zloupotreba. Molimo Vas da se u pregledniku vratite natrag na prethodnu stranicu, ponovno je učitate i zatim pokušate opet.",
-       "changecontentmodel-legend": "Promjeni model sadržaja",
+       "changecontentmodel-legend": "Promijeni model sadržaja",
        "changecontentmodel-title-label": "Naziv stranice",
        "changecontentmodel-model-label": "Novi model sadržaja",
        "changecontentmodel-reason-label": "Razlog:",
        "exif-gaincontrol-3": "Malo smanjenje",
        "exif-gaincontrol-4": "Veliko smanjenje",
        "exif-contrast-0": "Normalno",
-       "exif-contrast-1": "Meko",
-       "exif-contrast-2": "Tvrdo",
+       "exif-contrast-1": "Slabo",
+       "exif-contrast-2": "Jako",
        "exif-saturation-0": "Normalno",
        "exif-saturation-1": "Niska saturacija",
        "exif-saturation-2": "Visoka saturacija",
index b7e18f0..761b3cf 100644 (file)
        "action-applychangetags": "applicar etiquettas al proprie modificationes",
        "action-changetags": "adder e remover qualcunque etiquettas sur individual versiones e entratas de registro",
        "action-deletechangetags": "deler etiquettas del base de datos",
+       "action-purge": "purgar iste pagina",
        "nchanges": "$1 {{PLURAL:$1|modification|modificationes}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde le ultime visita}}",
        "enhancedrc-history": "historia",
        "watchnologin": "Tu non ha aperite un session",
        "addwatch": "Adder al observatorio",
        "addedwatchtext": "Le pagina \"[[:$1]]\", e su pagina de discussion, ha essite addite a [[Special:Watchlist|tu observatorio]].",
+       "addedwatchtext-talk": "\"[[:$1]]\" e su pagina associate ha essite addite a tu [[Special:Watchlist|observatorio]].",
        "addedwatchtext-short": "Le pagina \"$1\" ha essite addite a tu observatorio.",
        "removewatch": "Remover del observatorio",
        "removedwatchtext": "Le pagina \"[[:$1]]\", e su pagina de discussion, ha essite removite de [[Special:Watchlist|tu observatorio]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" e su pagina associate ha essite removite de tu [[Special:Watchlist|observatorio]].",
        "removedwatchtext-short": "Le pagina \"$1\" ha essite removite de tu observatorio.",
        "watch": "Observar",
        "watchthispage": "Observar iste pagina",
index 0c3a581..6a184d7 100644 (file)
        "watchnologin": "ログインしていません",
        "addwatch": "ウォッチリストに追加",
        "addedwatchtext": "「[[:$1]]」および付随する議論ページを、[[Special:Watchlist|ウォッチリスト]]に追加しました。",
+       "addedwatchtext-talk": "「[[:$1]]」および付随するページを[[Special:Watchlist|ウォッチリスト]]に追加しました。",
        "addedwatchtext-short": "ページ「$1」をウォッチリストに追加しました。",
        "removewatch": "ウォッチリストから除去",
        "removedwatchtext": "「[[:$1]]」および付随する議論ページを[[Special:Watchlist|ウォッチリスト]]から除去しました。",
+       "removedwatchtext-talk": "「[[:$1]]」および付随するページを[[Special:Watchlist|ウォッチリスト]]から除去しました。",
        "removedwatchtext-short": "ページ「$1」をウォッチリストから除去しました。",
        "watch": "ウォッチ",
        "watchthispage": "このページをウォッチする",
        "tooltip-ca-nstab-category": "カテゴリページを閲覧",
        "tooltip-minoredit": "この編集に細部の変更の印を付ける",
        "tooltip-save": "変更を保存する",
+       "tooltip-publish": "あなたによる変更を公開",
        "tooltip-preview": "変更内容をプレビューで確認できます。保存前に使用してください。",
        "tooltip-diff": "文章への変更箇所を表示する",
        "tooltip-compareselectedversions": "選択した2つの版の差分を表示する",
index b594b92..7480241 100644 (file)
                        "Ananth subray",
                        "MarcoAurelio",
                        "Macofe",
-                       "రహ్మానుద్దీన్"
+                       "రహ్మానుద్దీన్",
+                       "ಶಿವಕುಮಾರ್ ನಾಯಕ್",
+                       "Yogesh"
                ]
        },
        "tog-underline": "ಕೊಂಡಿಗಳ ಕೆಳಗೆ ಗೆರೆ ತೋರಿಸಿ",
        "tog-hideminor": "ಇತ್ತೀಚಿನ ಬದಲಾವಣೆಗಳಲ್ಲಿ ಚಿಕ್ಕಪುಟ್ಟ ಸಂಪಾದನೆಗಳನ್ನು ಅಡಗಿಸಿ",
        "tog-hidepatrolled": "ಪಹರೆಯಲ್ಲಿ ಆದ ಸಂಪಾದನೆಗಳನ್ನು ಇತ್ತೀಚೆಗಿನ ಬದಲಾವಣೆಗಳಲ್ಲಿ ಅಡಗಿಸು",
        "tog-newpageshidepatrolled": "ಪಹರೆಯಲ್ಲಿ ಆದ ಪುಟಗಳನ್ನು ಹೊಸ ಪುಟಗಳ ಪಟ್ಟಿಯಲ್ಲಿ ಅಡಗಿಸು",
-       "tog-extendwatchlist": "à²\95à³\87ವಲ à²\87ತà³\8dತà³\80à²\9aà³\86à²\97ಿನ à²¬à²¦à²²à²¾à²µà²£à³\86à²\97ಳಲà³\8dಲದà³\86, à²¸à²\82ಬà²\82ಧಿತ à²\8eಲà³\8dಲಾ à²¬à²¦à²²à²¾à²µà²£à³\86à²\97ಳನà³\8dನà³\81 à²¤à³\8bರà³\81ವà²\82ತà³\86 à²ªà²\9fà³\8dà²\9fಿಯನà³\8dನà³\81 à²µà²¿à²¸à³\8dತರಿಸಿ",
+       "tog-extendwatchlist": "ಕೇವಲ ಇತ್ತೀಚೆಗಿನ ಬದಲಾವಣೆಗಳಲ್ಲದೆ, ಎಲ್ಲಾ ಬದಲಾವಣೆಗಳನ್ನು ತೋರುವಂತೆ ಪಟ್ಟಿಯನ್ನು ವಿಸ್ತರಿಸಿ",
        "tog-usenewrc": "ಹೆಚ್ಚು ವರ್ಧಿಸಲಾದ ಇತ್ತೀಚಿನ ಬದಲಾವಣೆಗಳು ಪುಟ ಬಳಸು",
        "tog-numberheadings": "ತಲೆಬರಹಗಳಿಗೆ ಅಂಕಿಗಳನ್ನು ತೋರಿಸು",
        "tog-showtoolbar": "ಸಂಪಾದನೆಯ ಉಪಕರಣಗಳ ಪಟ್ಟಿಯನ್ನು ತೋರು",
        "faqpage": "Project:ಸಾಮಾನ್ಯವಾಗಿ ಕೇಳಲಾಗುವ ಪ್ರಶ್ನೆಗಳು",
        "actions": "ಕ್ರಿಯೆಗಳು",
        "namespaces": "ನಾಮವರ್ಗಗಳು",
-       "variants": "ಹಲವà³\81",
-       "navigation-heading": "ಸà²\82à²\9aರಣà³\86 à²®à³\86ನà³\81",
+       "variants": "ವà³\8dಯತà³\8dಯಾಸ à²¹à³\8aà²\82ದಿರà³\81ವ",
+       "navigation-heading": "ಸà²\82à²\9aರಣà³\86 à²ªà²\9fà³\8dà²\9fಿ",
        "errorpagetitle": "ದೋಷ",
        "returnto": "$1 ಗೆ ಹಿಂತಿರುಗಿ.",
        "tagline": "{{SITENAME}} ಇಂದ",
        "history_short": "ಇತಿಹಾಸ",
        "updatedmarker": "ನನ್ನ ಕೊನೆಯ ವೀಕ್ಷಣೆಯ ನಂತರ ಬದಲಾಗಿರುವವು",
        "printableversion": "ಪ್ರಿಂಟ್ ಆವೃತ್ತಿ",
-       "permalink": "ಸà³\8dಥಿರ à²¸à²\82ಪರà³\8dà²\95",
+       "permalink": "ಸà³\8dಥಿರ à²\95à³\8aà²\82ಡಿ",
        "print": "ಮುದ್ರಿಸು",
        "view": "ನೋಟ",
        "view-foreign": "$1 ರಲ್ಲಿ ನೋಡಿ",
        "undelete_short": "{{PLURAL:$1|ಒಂದು ಸಂಪಾದನೆಯ|$1 ಸಂಪಾದನೆಗಳ}} ಅಳಿಸುವಿಕೆಯನ್ನು ತೊಡೆದುಹಾಕು",
        "viewdeleted_short": "ನೋಟ {{PLURAL:$1|೧ ಅಳಿಸಲ್ಪಟ್ಟ ಸಂಪಾದನೆ|$1 ಅಳಿಸಲ್ಪಟ್ಟ ಸಂಪಾದನೆಗಳು}}",
        "protect": "ಸಂರಕ್ಷಿಸು",
-       "protect_change": "ಬದಲಾಯಿಸಿ",
+       "protect_change": "ಬದಲಾಯಿಸà³\81",
        "protectthispage": "ಈ ಪುಟವನ್ನು ಸಂರಕ್ಷಿಸಿ",
-       "unprotect": "ರà²\95à³\8dಷಣà³\86ಯನà³\8dನà³\81 à²¬à²¦à²²à²¾à²µà²£à³\86",
-       "unprotectthispage": "à²\88 à²ªà³\81à²\9fದ à²°à²\95à³\8dಷಣà³\86ಯನà³\8dನà³\81 à²¬à²¦à²²à²¾à²¯à²¿à²¸à²²à³\81",
+       "unprotect": "ರà²\95à³\8dಷಣà³\86ಯನà³\8dನà³\81 à²¬à²¦à²²à²¾à²¯à²¿à²¸à³\81",
+       "unprotectthispage": "ಈ ಪುಟದ ರಕ್ಷಣೆಯನ್ನು ಬದಲಾಯಿಸು",
        "newpage": "ಹೊಸ ಪುಟ",
-       "talkpage": "à²\88 à²ªà³\81à²\9fದ à²¬à²\97à³\8dà²\97à³\86 à²\9aರà³\8dà²\9aà³\86 à²®à²¾à²¡ಿ",
+       "talkpage": "à²\88 à²ªà³\81à²\9fವನà³\8dನà³\81 à²\9aರà³\8dà²\9aಿಸಿ",
        "talkpagelinktext": "ಚರ್ಚೆ",
        "specialpage": "ವಿಶೇಷ ಪುಟ",
        "personaltools": "ವೈಯಕ್ತಿಕ ಉಪಕರಣಗಳು",
        "talk": "ಚರ್ಚೆ",
        "views": "ನೋಟಗಳು",
        "toolbox": "ಉಪಕರಣಗಳು",
-       "userpage": "ಸದಸ್ಯರ ಪುಟ ತೋರು",
+       "userpage": "ಸದಸ್ಯರ ಪುಟವನ್ನು ವೀಕ್ಷಿಸು",
        "projectpage": "ಯೋಜನೆಯ ಪುಟವನ್ನು ನೋಡು",
        "imagepage": "ಕಡತದ ಪುಟ ವೀಕ್ಷಿಸಿ",
        "mediawikipage": "ಸಂದೇಶ ಪುಟವನ್ನು ನೋಡು",
        "templatepage": "ಟೆಂಪ್ಲೇಟು ಪುಟವನ್ನು ವೀಕ್ಷಿಸಿ",
        "viewhelppage": "ಸಹಾಯ ಪುಟ ತೋರು",
-       "categorypage": "ವರ್ಗ ಪುಟ ತೋರು",
+       "categorypage": "ವರ್ಗದ ಪುಟವನ್ನು ವೀಕ್ಷಿಸಿ",
        "viewtalkpage": "ಚರ್ಚೆಯನ್ನು ವೀಕ್ಷಿಸಿ",
        "otherlanguages": "ಇತರ ಭಾಷೆಗಳಲ್ಲಿ",
        "redirectedfrom": "($1 ಇಂದ ಪುನರ್ನಿರ್ದೇಶಿತ)",
        "copyrightpage": "{{ns:project}}:ಕೃತಿಸ್ವಾಮ್ಯತೆಗಳು",
        "currentevents": "ಪ್ರಚಲಿತ ಸಂಗತಿಗಳು",
        "currentevents-url": "Project:ಪ್ರಚಲಿತ ಸಂಗತಿಗಳು",
-       "disclaimers": "à²\85ಬಾಧà³\8dಯತೆಗಳು",
+       "disclaimers": "ಹà²\95à³\8dà²\95à³\81 à²¨à²¿à²°à²¾à²\95ರಣೆಗಳು",
        "disclaimerpage": "Project:ಸಾಮಾನ್ಯ ಅಬಾಧ್ಯತೆಗಳು",
        "edithelp": "ಸಂಪಾದನೆಗೆ ಸಹಾಯ",
        "helppage-top-gethelp": "ಸಹಾಯ",
        "policy-url": "Project:ನಿಯಮಾವಳಿಗಳು",
        "portal": "ಸಮುದಾಯ ಪುಟ",
        "portal-url": "Project:ಸಮುದಾಯ ಪುಟ",
-       "privacy": "à²\97à³\8cಪà³\8dಯತà³\86ಯ à²\95ಾರà³\8dಯನೀತಿ",
+       "privacy": "à²\97à³\8cಪà³\8dಯತಾ ನೀತಿ",
        "privacypage": "Project:ಗೌಪ್ಯತೆಯ ಕಾರ್ಯನೀತಿ",
        "badaccess": "ಅನುಮತಿ ದೋಷ",
        "badaccess-group0": "ನೀವು ಕೋರಿರುವ ಕ್ರಿಯೆಯನ್ನು ನಿರ್ವಹಿಲು ನಿಮಗೆ ಅನುಮತಿ ಇಲ್ಲ.",
        "minoredit": "ಇದು ಚುಟುಕಾದ ಬದಲಾವಣೆ",
        "watchthis": "ಈ ಪುಟವನ್ನು ವೀಕ್ಷಿಸಿ",
        "savearticle": "ಪುಟವನ್ನು ಉಳಿಸಿ",
+       "publishpage": "ಪುಟವನ್ನು ಪ್ರಕಟಿಸು",
+       "publishchanges": "ಬದಲಾವಣೆಗಳನ್ನು ಪ್ರಕಟಿಸು",
        "preview": "ಮುನ್ನೋಟ",
        "showpreview": "ಮುನ್ನೋಟ ತೋರಿಸು",
        "showdiff": "ಬದಲಾವಣೆಗಳನ್ನು ತೋರಿಸು",
        "previousrevision": "←ಹಿಂದಿನ ಪರಿಷ್ಕರಣೆ",
        "nextrevision": "ಮುಂದಿನ ಪರಿಷ್ಕರಣೆ",
        "currentrevisionlink": "ಈಗಿನ ಪರಿಷ್ಕರಣೆ",
-       "cur": "ಸಧ್ಯದ",
+       "cur": "ಸದ್ಯದ",
        "next": "ಮುಂದಿನದು",
        "last": "ಕೊನೆಯ",
        "page_first": "ಮೊದಲ",
        "recentchangeslinked-summary": "ಒಂದು ನಿರ್ದಿಷ್ಟ ಪುಟದಿಂದ (ಅಥವ ನಿರ್ದಿಷ್ಟ ವರ್ಗಕ್ಕೆ ಸೇರಿರುವ ಪುಟಗಳಿಂದ) ಸಂಪರ್ಕ ಹೊಂದಿರುವ ಪುಟಗಳಲ್ಲಿ ಇತ್ತೀಚೆಗೆ ಮಾಡಲಾಗಿರುವ ಬದಲಾವಣೆಗಳನ್ನು ಈ ಕೆಳಗೆ ಪಟ್ಟಿ ಮಾಡಲಾಗಿದೆ.\n[[Special:Watchlist|ನಿಮ್ಮ ವೀಕ್ಷಣಾಪಟ್ಟಿಯಲ್ಲಿ]] ಇರುವ ಪುಟಗಳು '''ದಪ್ಪ ಅಕ್ಷರ'''ಗಳಲ್ಲಿ ಇವೆ.",
        "recentchangeslinked-page": "ಪುಟದ ಹೆಸರು:",
        "recentchangeslinked-to": "ಇದರ ಬದಲಿಗೆ ನೇಮಿತ ಪುಟಕ್ಕೆ ಕೊಂಡಿಯನ್ನು ಹೊಂದಿರುವ ಪುಟಗಳಲ್ಲಿನ ಬದಲಾವಣೆಗಳನ್ನು ತೋರು",
-       "upload": "ಫà³\88ಲà³\8d à²\85ಪà³\8dಲà³\8bಡà³\8d",
+       "upload": "ಫà³\88ಲà³\8d à²®à³\87ಲà²\95à³\8dà²\95à³\86ರಿಸಿ",
        "uploadbtn": "ಫೈಲನ್ನು ಅಪ್ಲೋಡ್ ಮಾಡಿ",
        "reuploaddesc": "ಅಪ್ಲೋಡ್ ಅನ್ನು ನಿಲ್ಲಿಸಿ ಮತ್ತೆ ಅಪ್ಲೋಡ್ ವಕ್ಕಣೆಗೆ ಹಿಂದಿರುಗಿ",
        "uploadnologin": "ಲಾಗಿನ್ ಆಗಿಲ್ಲ",
        "unusedtemplates": "ಉಪಯೋಗದಲ್ಲಿರದ ಟೆಂಪ್ಲೇಟುಗಳು",
        "unusedtemplatestext": "ಯಾವ ಪುಟದಲ್ಲೂ ಉಪಯೋಗದಲ್ಲಿ ಇರದ ಟೆಂಪ್ಲೇಟುಗಳನ್ನು ಇಲ್ಲಿ ಪಟ್ಟಿ ಮಾಡಲಾಗಿದೆ. ಇವನ್ನು ಅಳಿಸುವ ಮುನ್ನ ಟೆಂಪ್ಲೇಟುಗಳಿಗೆ ಇತರ ಲಿಂಕುಗಳಿದೆಯೆ ಎಂದು ಪರೀಕ್ಷಿಸಲು ಮರೆಯದಿರಿ.",
        "unusedtemplateswlh": "ಇತರ ಕೊಂಡಿಗಳು",
-       "randompage": "ಯಾದà³\83à²\9aà³\8dà²\9bಿà²\95 ಪುಟ",
+       "randompage": "ಯಾವà³\81ದಾದರà³\81 à²\92à²\82ದà³\81 ಪುಟ",
        "randompage-nopages": "ಈ ಪುಟಪ್ರಬೇಧದಲ್ಲಿ ಯಾವ ಪುಟವೂ ಇಲ್ಲ.",
        "randomincategory-category": "ವರ್ಗ:",
        "randomincategory-submit": "ಹೋಗು",
        "tooltip-search": "{{SITENAME}} ಅನ್ನು ಹುಡುಕಿ",
        "tooltip-search-go": "ಇದೇ ಹೆಸರಿನ ಪುಟವಿದ್ದಲ್ಲಿ ಅಲ್ಲಿಗೆ ಹೋಗು",
        "tooltip-search-fulltext": "ಈ ಪಠ್ಯವನ್ನು ಹೊಂದಿರುವ ಪುಟಗಳನ್ನು ಹುಡುಕು",
-       "tooltip-p-logo": "ಮುಖ್ಯ ಪುಟ",
+       "tooltip-p-logo": "ಮುಖ್ಯ ಪುಟಕ್ಕೆ ಭೇಟಿ ಕೊಡಿ",
        "tooltip-n-mainpage": "ಮುಖ್ಯ ಪುಟ ನೋಡಿ",
        "tooltip-n-mainpage-description": "ಮುಖ್ಯ ಪುಟ ನೋಡಿ",
        "tooltip-n-portal": "ಯೋಜನೆಯ ಬಗ್ಗೆ, ನೀವು ಏನು ಮಾಡಬಹುದು, ಎಲ್ಲಿ ಇದರ ಬಗ್ಗೆ ತಿಳಿದುಕೊಳ್ಳಬಹುದು",
        "tooltip-n-currentevents": "ಪ್ರಸಕ್ತ ಆಗುಹೋಗುಗಳ ಬಗ್ಗೆ ಹಿನ್ನಲೆ ಮಾಹಿತಿ ಪಡೆಯಿರಿ",
        "tooltip-n-recentchanges": "ವಿಕಿಯಲ್ಲಿನ ಇತ್ತೀಚಿನ ಬದಲಾವಣೆಗಳ ಪಟ್ಟಿ.",
-       "tooltip-n-randompage": "ಯದà³\83à²\9aà³\8dà²\9bಿà²\95 ಪುಟವೊಂದನ್ನು ತೋರಿಸು",
+       "tooltip-n-randompage": "ಯಾವà³\81ದಾದರà³\81 ಪುಟವೊಂದನ್ನು ತೋರಿಸು",
        "tooltip-n-help": "ಇದರ ಬಗ್ಗೆ ತಿಳಿದುಕೊಳ್ಳಲು ಜಾಗ.",
        "tooltip-t-whatlinkshere": "ಇಲ್ಲಿಗೆ ಸಂಪರ್ಕ ಹೊಂದಿರುವ ಎಲ್ಲಾ ವಿಕಿ ಪುಟಗಳ ಪಟ್ಟಿ",
        "tooltip-t-recentchangeslinked": "ಈ ಪುಟದಿಂದ ಸಂಪರ್ಕ ಹೊಂದಿರುವ ಪುಟಗಳಲ್ಲಿನ ಇತ್ತೀಚಿನ ಬದಲಾವಣೆಗಳು",
        "tooltip-feed-atom": "ಈ ಪುಟಕ್ಕೆ Atom ಫೀಡು",
        "tooltip-t-contributions": "ಈ ಸದಸ್ಯರ ಕಾಣಿಕೆಗಳ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸು",
        "tooltip-t-emailuser": "ಈ ಸದಸ್ಯರಿಗೆ ಇ-ಅಂಚೆಯನ್ನು ಕಳುಹಿಸು",
-       "tooltip-t-upload": "ಫà³\88ಲನà³\8dನà³\81 à²\85ಪà³\8dಲà³\8bಡà³\8d à²®à²¾à²¡ಿ",
+       "tooltip-t-upload": "ಫà³\88ಲನà³\8dನà³\81 à²®à³\87ಲà²\95à³\8dà²\95à³\86ರಿಸಿ",
        "tooltip-t-specialpages": "ಎಲ್ಲಾ ವಿಶೇಷ ಪುಟಗಳ ಪಟ್ಟಿ",
        "tooltip-t-print": "ಈ ಪುಟದ ಮುದ್ರಣ ಮಾಡಬಹುದಾದಂತ ಆವೃತ್ತಿ",
        "tooltip-t-permalink": "ಪುಟದ ಈ ಆವೃತ್ತಿಗೆ ಶಾಶ್ವತ ಕೊಂಡಿ",
        "file-nohires": "ಇದಕ್ಕಿಂತ ಹೆಚ್ಚಿನ ವಿವರವಾದ ನೋಟ ಇಲ್ಲ.",
        "svg-long-desc": "SVG ಫೈಲು, ಸುಮಾರಾಗಿ $1 × $2 ಚಿತ್ರಬಿಂದುಗಳು, ಫೈಲಿನ ಗಾತ್ರ: $3",
        "show-big-image": "ಮೂಲ ಕಡತ",
+       "show-big-image-preview": "ಈ ಮುನ್ನೋಟ ಗಾತ್ರ:$1.",
+       "show-big-image-other": "ಇತರೆ{{PLURAL:$2|resolution|resolutions}}: $1.",
        "show-big-image-size": "$1 × $2 ಪಿಕ್ಸೆಲ್‌ಗಳು",
        "file-info-gif-looped": "ಲೂಪ್",
        "file-info-png-looped": "ಲೂಪ್",
        "specialpages-group-pages": "ಪುಟಗಳ ಪಟ್ಟಿ",
        "specialpages-group-redirects": "ವಿಶೇಷ ಪುಟಗಳನ್ನು ಪುನರ್ನಿರ್ದೇಶಿಸಲಾಗುತ್ತಿದೆ",
        "blankpage": "ಖಾಲಿ ಪುಟ",
-       "tag-filter": "[[ವಿಶೇಷ:ಟ್ಯಾಗ್‌ಗಳು|ಟ್ಯಾಗ್]] ಶೋಧಕ:",
+       "tag-filter": "[[Special:Tags|Tag]] ಶೋಧಕ:",
        "tag-filter-submit": "ಶೋಧಕ",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|ಟ್ಯಾಗ್|ಟ್ಯಾಗ್‌ಗಳು}}]]: $2)",
        "tags-title": "ಅಂಕಿತಗಳು",
index 6b49978..f548224 100644 (file)
        "watchnologin": "로그인하지 않음",
        "addwatch": "주시문서 목록에 추가",
        "addedwatchtext": "\"[[:$1]]\" 문서와 그 토론 문서가 [[Special:Watchlist|주시문서 목록]]에 추가되었습니다.",
+       "addedwatchtext-talk": "\"[[:$1]]\" 문서와 관련 문서가 [[Special:Watchlist|주시문서 목록]]에 추가되었습니다.",
        "addedwatchtext-short": "\"$1\" 문서를 주시문서 목록에 추가했습니다.",
        "removewatch": "주시문서 목록에서 제거",
        "removedwatchtext": "\"[[:$1]]\" 문서와 그 토론 문서가 [[Special:Watchlist|주시문서 목록]]에서 제거되었습니다.",
+       "removedwatchtext-talk": "\"[[:$1]]\" 문서와 관련 문서가 [[Special:Watchlist|주시문서 목록]]에서 제거되었습니다.",
        "removedwatchtext-short": "\"$1\" 문서를 주시문서 목록에 제거했습니다.",
        "watch": "주시",
        "watchthispage": "주시하기",
index b8ab58d..9479f3c 100644 (file)
        "minoredit": "Haec est recensio minor",
        "watchthis": "Hanc paginam observare",
        "savearticle": "Hanc redactionem servare",
+       "publishpage": "Hanc paginam edere",
+       "publishchanges": "Hanc recensionem edere",
        "preview": "Praevidere",
        "showpreview": "Prospectum ostendere",
        "showdiff": "Mutationes ostendere",
        "tooltip-ca-nstab-category": "Videre paginam categoriae",
        "tooltip-minoredit": "Indicare hanc recensionem minorem",
        "tooltip-save": "Servare mutationes tuas",
+       "tooltip-publish": "Hanc recensionem edere",
        "tooltip-preview": "Sinet prospicere, quod mutationes tuas effecerint. Utere, quaesumus, hac facultate, antequam servas!",
        "tooltip-diff": "Comparabit hanc redactionem cum superiore earumque differentias notabit",
        "tooltip-compareselectedversions": "Inspicere, quatenus contenta redactionum selectarum inter se distent",
index 8fd5a9a..bff977d 100644 (file)
@@ -53,6 +53,7 @@
        "tog-watchlisthidebots": "Ännerunge vu Botten op menger Iwwerwaachungslëscht verstoppen",
        "tog-watchlisthideminor": "Kleng Ännerungen op menger Iwwerwaachungslëscht verstoppen",
        "tog-watchlisthideliu": "Ännerunge vun ugemellte Benotzer verstoppen",
+       "tog-watchlistreloadautomatically": "D'Iwwerwaachungslëscht nei lueden esoubal wéi e Filter geännert ass (JavaScript gëtt gebraucht)",
        "tog-watchlisthideanons": "Ännerunge vun anonyme Benotzer (IP-Adressen) verstoppen",
        "tog-watchlisthidepatrolled": "Iwwerkuckten Ännerungen op der Iwwerwaachungslëscht verstoppen",
        "tog-watchlisthidecategorization": "Kategorisatioun vu Säite verstoppen",
        "mergehistory-fail-bad-timestamp": "Zäitstempel ass net valabel.",
        "mergehistory-fail-invalid-source": "Quellsäit ass net valabel.",
        "mergehistory-fail-invalid-dest": "Zilsäit ass net valabel.",
+       "mergehistory-fail-self-merge": "Quell an Zilsäit sinn déi selwecht.",
        "mergehistory-fail-toobig": "D'zesummeleeë vun der Lëscht vun de Versioune konnt net gemaach ginn well méi wéi d'Limite vun $1 {{PLURAL:$1|Versioun|Versioune}} geréckelt géife ginn",
        "mergehistory-no-source": "Originalsäit \"$1\" gëtt et net.",
        "mergehistory-no-destination": "Zilsäit \"$1\" gëtt et net.",
        "action-createpage": "dës Säit uleeën",
        "action-createtalk": "dës Diskussiounssäit uleeën",
        "action-createaccount": "dëse Benotzerkont unzeleeën",
+       "action-autocreateaccount": "automatesch dësen externe Benotzerkont opzemaachen",
        "action-history": "d'Versioune vun dëser Säit weisen",
        "action-minoredit": "dës Ännerung als kleng Ännerung ze markéieren",
        "action-move": "dës Säit ze réckelen",
index f7332f9..29737f4 100644 (file)
@@ -22,7 +22,8 @@
                        "सरोज कुमार ढकाल",
                        "Bijay chaurasia",
                        "Tulsi Bhagat",
-                       "Macofe"
+                       "Macofe",
+                       "राम प्रसाद जोशी"
                ]
        },
        "tog-underline": "लिङ्कके रेखाङ्कित करी:",
        "sqlite-has-fts": "$1 पूर्ण-पाठ खोज सहायता युक्त",
        "sqlite-no-fts": "$1 बिन पूर्ण-पाठ खोज सहायताक",
        "logentry-delete-delete": "$1 पृष्ठ $3 {{GENDER:$2|मेटौलक}}",
-       "logentry-delete-restore": "$1 {{लिंग:$2|restored}} page $3",
+       "logentry-delete-restore": "$1 {{GENDER:$2|restored}} page $3",
        "logentry-delete-event": "$1 {{लिंग:$2|changed}} एकर दृश्य{{PLURAL:$5| एकटा वृत्तलेख|$5 वृत्तलेख}}  $3: $4 केँ",
        "logentry-delete-revision": "$1 {{लिंग:$2|changed}} एकर दृश्य{{PLURAL:$5| एकटा संशोधन|$5 संशोधन}}  पन्ना $3: $4 पर",
-       "logentry-delete-event-legacy": "$1 {{लिंग:$2|changed}}  $3 पर वृत्तलेख दृश्य",
-       "logentry-delete-revision-legacy": "$1 {{लिंग:$2|changed}}  $3 पर वृत्तलेख संशोधन",
+       "logentry-delete-event-legacy": "$1 {{GENDER:$2|changed}}  $3 पर वृत्तलेख दृश्य",
+       "logentry-delete-revision-legacy": "$1 {{GENDER:$2|changed}}  $3 पर वृत्तलेख संशोधन",
        "logentry-suppress-delete": "$1 {{लिंग:$2|दबाएल}} page $3",
        "logentry-suppress-event": "$1 चोरिसँ {{लिंग:$2|changed}} एकर दृश्य{{PLURAL:$5| एकटा वृत्तलेख|$5 वृत्तलेख}}  $3: $4 पर",
        "logentry-suppress-revision": "$1 चोरिसँ {{लिंग:$2|changed}} एकर दृश्य{{PLURAL:$5| एकटा संशोधन|$5 संशोधन}}  $3: $4 पर",
-       "logentry-suppress-event-legacy": "$1 नुका कऽ {{लिंग:$2|changed}}  $3 पर वृत्तलेख दृश्य",
-       "logentry-suppress-revision-legacy": "$1 नुका कऽ {{लिंग:$2|changed}}  $3 पर संशोधन दृश्य",
+       "logentry-suppress-event-legacy": "$1 नुका क {{GENDER:$2|परिवर्तन}}  $3 पर वृत्तलेख दृश्य",
+       "logentry-suppress-revision-legacy": "$1 नुका कऽ {{GENDER:$2|changed}}  $3 पर संशोधन दृश्य",
        "revdelete-content-hid": "सामिग्री नुकाएल",
        "revdelete-summary-hid": "नुकाएल सारांश सम्पादन",
        "revdelete-uname-hid": "प्रयोक्तानाम नुकाएल",
        "logentry-import-interwiki": "$1 {{GENDER:$2|आयात केल गेल}} $3 कोनो और विकि सँ",
        "logentry-merge-merge": "$1 {{GENDER:$2|विलय केल गेल}} $3 के $4 में (संशोधन $5 धरि)",
        "logentry-move-move": "$1 हटाएल पन्ना $3 सँ $4",
-       "logentry-move-move-noredirect": "$1 {{लिंग:$2|हटाएल}} पन्ना $3 सँ $4 घुमौआकेँ बिना छोड़ने",
-       "logentry-move-move_redir": "$1 {{लिंग:$2|हटाएल}} पन्ना $3 सँ $4 घुमौआक अतिरिक्त",
+       "logentry-move-move-noredirect": "$1 {{GENDER:$2|हटाएल}} पन्ना $3 सँ $4 घुमौआकेँ बिना छोड़ने",
+       "logentry-move-move_redir": "$1 {{GENDER:$2|हटाएल}} पन्ना $3 सँ $4 घुमौआक अतिरिक्त",
        "logentry-move-move_redir-noredirect": "$1 {{लिंग:$2|हटाएल}} पन्ना $3 सँ $4 घुमौआक अतितिक्त घुमौआकेँ बिना छोड़ने",
        "logentry-patrol-patrol": "$1 {{GENDER:$2|चिन्हित}} संशोधन $4 $3 पन्नाक निरीक्षित",
        "logentry-patrol-patrol-auto": "$1 स्वतः {{GENDER:$2|चिन्हित}} संशोधन $4 $3 पन्नाक निरीक्षित",
-       "logentry-newusers-newusers": "$1 {{लिंग:$2|बनाएल}} एकटा प्रयोक्ता खाता",
+       "logentry-newusers-newusers": "$1 {{GENDER:$2|बनाएल}} एकटा प्रयोक्ता खाता",
        "logentry-newusers-create": "प्रयोगकर्ता खाता $1 {{GENDER:$2|बनाएल}} गेल",
-       "logentry-newusers-create2": "$1 {{लिंग:$2|बनाएल}} {{लिंग:$4|एकटा प्रयोक्ता खाता}} $3",
+       "logentry-newusers-create2": "$1 {{GENDER:$2|बनाएल}} {{GENDER:$4|एकटा प्रयोक्ता खाता}} $3",
        "logentry-newusers-byemail": "$1 द्वारा प्रयोक्ता खाता $3 {{GENDER:$2|बनाओल}} गेल आ कूटशब्द ई-पत्र द्वारा भेजल गेल",
-       "logentry-newusers-autocreate": "खाता $1 छल {{लिंग:$2|बनाएल}} स्वतः",
+       "logentry-newusers-autocreate": "खाता $1 छल {{GENDER:$2|बनाएल}} स्वतः",
        "logentry-upload-upload": "$1 {{GENDER:$2|ए}} $3 अपलोड केलक",
        "log-name-tag": "ट्याग लग",
        "rightsnone": "(कोनो नै)",
index b54740c..087ea59 100644 (file)
        "watchnologin": "Не сте најавени",
        "addwatch": "Додај во набљудувани",
        "addedwatchtext": "„[[:$1]]“ и нејзината страница за разговор се додадени во вашите [[Special:Watchlist|набљудувања]].",
+       "addedwatchtext-talk": "„[[:$1]]“ и нејзината поврзана страница се додадени во вашите [[Special:Watchlist|набљудувања]].",
        "addedwatchtext-short": "Страницата „$1“ е додадена во вашите набљудувања.",
        "removewatch": "Отстрани набљудуваните",
        "removedwatchtext": "„[[:$1]]“ и нејзината страница за разговор се отстранети од вашите [[Special:Watchlist|набљудувања]].",
+       "removedwatchtext-talk": "„[[:$1]]“ и нејзината поврзана страница се отстранети од вашите [[Special:Watchlist|набљудувања]].",
        "removedwatchtext-short": "Страницата „$1“ е отстранета од вашите набљудувања.",
        "watch": "Набљудувај",
        "watchthispage": "Набљудувај ја страницава",
index cb59019..591bdec 100644 (file)
        "thursday": "Īcmācuīlilhuitl",
        "friday": "Īcchicuacemilhuitl",
        "saturday": "Īcchicōmilhuitl",
-       "sun": "ilhui",
-       "mon": "ilhui",
-       "tue": "ilhui",
-       "wed": "ilhui",
-       "thu": "ilhui",
+       "sun": "Cemilhui",
+       "mon": "Ōmilhui",
+       "tue": "Ēyilhui",
+       "wed": "Nāuhilhui",
+       "thu": "Mācuililhui",
        "fri": "6 ilhui",
        "sat": "7 ilhui",
-       "january": "Īccēmētztli",
-       "february": "Īcōmēmētztli",
-       "march": "Īcyēyimētztli",
-       "april": "Īcnāuhtetlmētztli",
-       "may_long": "Īcmācuīllimētztli",
-       "june": "Īcchicuacemmētztli",
-       "july": "Īcchicōmemētztli",
-       "august": "Īcchicuēyimētztli",
-       "september": "Īcchiucnāhuimētztli",
-       "october": "Īcmahtlāctlimētztli",
-       "november": "Īcmahtlāctlioncēmētztli",
-       "december": "Īcmahtlāctliomōmemētztli",
-       "january-gen": "Īccēmētztli",
+       "january": "Ic cē mētztli",
+       "february": "Ic ōmemētztli",
+       "march": "Ic ēyi mētztli",
+       "april": "Ic nāuhtetl mētztli",
+       "may_long": "Ic mācuīlli mētztli",
+       "june": "Ic chicuacē mētztli",
+       "july": "Ic chicōme mētztli",
+       "august": "Ic chicuēyi mētztli",
+       "september": "Ic chiucnāhui mētztli",
+       "october": "Ic mahtlāctli mētztli",
+       "november": "Ic mahtlāctli oncē mētztli",
+       "december": "Ic mahtlāctli omōme mētztli",
+       "january-gen": "Ic cē mētztli",
        "february-gen": "Īcōmemētztli",
        "march-gen": "Īcyēyimētztli",
-       "april-gen": "Īcnāuhtetlmētztli",
+       "april-gen": "Ic nāuhtetl mētztli",
        "may-gen": "Īcmācuīllimētztli",
-       "june-gen": "Īcchicuacemmētztli",
-       "july-gen": "Īcchicōmemētztli",
+       "june-gen": "Ic chicuacemmētztli",
+       "july-gen": "Ic chicōme mētztli",
        "august-gen": "Īcchicuēyimētztli",
        "september-gen": "Īcchiucnāhuimētztli",
        "october-gen": "Īcmahtlāctetlmētztli",
        "november-gen": "Īcmahtlāctetloncēmētztli",
        "december-gen": "Īcmahtlāctetlomōmemētztli",
-       "jan": "1 Mētz",
-       "feb": "2 Mētz",
-       "mar": "3 Mētz",
-       "apr": "4 Mētz",
-       "may": "5 Mētz",
-       "jun": "6 Mētz",
-       "jul": "7 Mētz",
-       "aug": "8 Mētz",
-       "sep": "9 Mētz",
-       "oct": "10 Mētz",
-       "nov": "11 Mētz",
-       "dec": "12 Mētz",
+       "jan": "Ic cē",
+       "feb": "Ic ōme",
+       "mar": "Ic ēyi",
+       "apr": "Nāhui",
+       "may": "Mācuilli",
+       "jun": "Chicuacē",
+       "jul": "Chicōme",
+       "aug": "Chicuēyi",
+       "sep": "Chiucnāhui",
+       "oct": "Mahtlāctli",
+       "nov": "Mahtlāctlioncē",
+       "dec": "Mahtlāctliomōme",
        "january-date": "Īccēmētztli $1",
        "february-date": "Īcōmemētztli $1",
        "march-date": "Īquēyimētztli $1",
        "moredotdotdot": "Huehca ōmpa...",
        "mypage": "Noāmauh",
        "mytalk": "Nozānīl",
-       "anontalk": "Inīn IP ītēixnāmiquiliz",
+       "anontalk": "Tēixnāmiquiliztli",
        "navigation": "Nēnemōhualiztli",
        "and": "&#32;īhuān",
        "qbfind": "Xicahci",
        "tagline": "Īhuīcpa {{SITENAME}}",
        "help": "Tēpalēhuiliztli",
        "search": "Mà motèmo",
-       "searchbutton": "Xictēmo",
+       "searchbutton": "Tictēmōz",
        "go": "Xiyauh",
        "searcharticle": "Xiyauh",
        "history": "Tlaīxtli ītlahtōllo",
        "viewsource": "Xiquitta mēyalli",
        "viewsource-title": "Xiquitta in $1 īmēyal",
        "actionthrottled": "Tlachīhualiztli ōmotzacuili",
-       "viewsourcetext": "Tihuelīti tiquitta auh ticcopīna inīn zāzanilli ītlahtōlcaquiliztilōni:",
+       "viewsourcetext": "Tihuelīti tiquittaz auh ticcopīnaz inīn zāzanilli īmachiyōnecaquilizmēyal.",
        "namespaceprotected": "Ahmo tiquihuelīti tiquimpatla zāzaniltin īpan '''$1'''.",
        "ns-specialprotected": "In nònkuâkìskàtlaìxtlapaltìn awel ìmpan nemàtilòs mokinyèktlàlis.",
        "titleprotected": "Inīn zāzanilli ōmoquīxti ic tlachīhualiztli ic [[User:$1|$1]].\nŌquihto: <em>$2</em>",
        "userexists": "In tlatequitiltilīltōcāitl in ōquipehpen ye ia.\nTimitztlātlauhtiah xicpehpena occē.",
        "loginerror": "Ahcuallōtl tlacalaquiliztechcopa",
        "noname": "Ahmo ōtiquihto cualli tlatequitiltilīlli tōcāitl.",
-       "loginsuccesstitle": "Cualli calaquiliztli",
+       "loginsuccesstitle": "Ōticalac",
        "loginsuccess": "'''Ōticalac {{SITENAME}} quemeh \"$1\".'''",
-       "nosuchuser": "Ayāc tlatequitiltilīlli motōcāitia \"$1\".\nIn tlatequitiltilīltōcāitl quimati in huēyimachiyōtlahtōliztli.\nXiquitta in yēquihcuilōlli, ahnozo [[Special:CreateAccount|xicchīhua yancuīc cuenta]].",
+       "nosuchuser": "Ayāc tlatequitiltilīlli motōcāitīlo «$1».\nn tlatequitiltilīltōcāitl quimati in huēyimachiyōtlahtōliztli.\nXiquitta moyēquihcuilōl, ahnozo [[Special:CreateAccount|xicchīhua yancuīc cuentah]].",
        "nosuchusershort": "Ayāc tlatequitiltilīlli motōcāitia \"$1\". Xiquitta in tlein ōtitlahcuiloh melāhuacā cah.\nXiquitta moyēquihcuilōl.",
        "nouserspecified": "Mohuīquilia tiquihtoa cualli tlatequitiltilīltōcāitl.",
        "wrongpassword": "Ahcualli motlahtōlichtacāyo.\nTimitztlātlauhtia xicchīhua occeppa.",
        "newpassword": "Yancuīc motlahtōlichtacayo:",
        "retypenew": "Occeppa xiquihcuiloa yancuīc motlahtōlichtacayo:",
        "resetpass_submit": "Xicpatlāz motlahtōlichtacāyo auh xicalaquīz",
-       "changepassword-success": "Mochtacātlahtōl cualli ōtlapatlalo.",
+       "changepassword-success": "Moichtacātlahtōl ōmopatlac.",
        "resetpass_forbidden": "Tlahtōlichtacayōtl ahmo mohuelītih mopatlah",
        "resetpass-submit-loggedin": "Ticpatlāz motlahtōlichtacāyo",
        "resetpass-submit-cancel": "Xiccāhua",
        "sig_tip": "Motōcā īca cāhuitl",
        "hr_tip": "Pāntli",
        "summary": "Mopatlaliz:",
-       "subject": "Tōcāitl/Āmoxmachiyōtl:",
+       "subject": "Ītechpa:",
        "minoredit": "Ca tepitōn inīn tlapatlaliztli",
        "watchthis": "Xicpiya inīn tlaīxtli",
        "savearticle": "Xicpiya tlaīxtli",
        "accmailtext": "Ōquiyōcox zāzochtacātlahtōlli in [[User talk:$1|$1]] auh ōmoquitītlan īhuīc $2. Tihueliti ticpatlaz īpan ''[[Special:ChangePassword|Ticpatlaz in ]]'' in ōticalaco achtopa.",
        "newarticle": "(Yancuic)",
        "newarticletext": "Ōtictocac cētiliztli cē zāzanilhuīc oc ahmo ia. Intlā quiēlēhuia quichīhua, xitlahcuiloa niman (nō xiquitta [$1 tēpalēhuiliztli zāzanilli] huehca ōmpa tlapatlaliztli). Intlā ahmo, yāuh achtopa zāzanilli.",
-       "noarticletext": "In āxcān, ahmō onca tlahcuilōlli inīn zāzanilpan.\nTihuelīti [[Special:Search/{{PAGENAME}}|tictēmoa inīn zāzaniltōcācopa]] occequīntīn zāzanilpan,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} machiyōmacalpan], ahnozo [{{fullurl:{{FULLPAGENAME}}|action=edit}} ticpatla inīn zāzanilli]</span>.",
+       "noarticletext": "In āxcān, ahmō onca tlahcuilōlli inīn zāzanilpan.\nTihuelīti [[Special:Search/{{PAGENAME}}|tictēmōz inīn zāzanilli ītōca]] occequīntīn zāzanilpan,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} xictēmoa īpan in tlapōhualāmatechpa],\nahnozo [{{fullurl:{{FULLPAGENAME}}|action=edit}} xichīhua inīn zāzanilli]</span>.",
        "userpage-userdoesnotexist": "Ahmo ia cuentah \"<nowiki>$1</nowiki>\" ītōca. Timitztlātlauhtiah xitēchquinōtza intlā ticchīhuāz intlā nozo ticpatlāz inīn zāzanilli.",
        "usercsspreview": "'''Ca inīn moachtochīhualiz ītechcopa moCSS.'''\n'''¡Ahmo ōmochīuh nozan!'''",
        "userjspreview": "'''Ca inīn moachtochīhualiz ītechcopa moJavaScript.'''\n'''¡Ahmo ōmochīuh nozan!'''",
        "currentrev": "Āxcān tlapatlaliztli",
        "currentrev-asof": "Āxcān tlachiyaliztli īpan $1",
        "revisionasof": "Tlachiyaliztli īpan $1",
-       "revision-info": "Tlachiyaliztli īpan $1; $2",
+       "revision-info": "Tlachiyaliztli īpan $1 īpal {{GENDER:$6|$2}}$7",
        "previousrevision": "← Huēhueh tlapatlaliztli",
        "nextrevision": "Yancuīc tlapatlaliztli →",
        "currentrevisionlink": "Āxcān tlapatlaliztli",
        "shown-title": "Quinēxiltīz $1 {{PLURAL:$1|mochīhualiztli}} cece āmac",
        "viewprevnext": "Xiquintta ($1 {{int:pipe-separator}} $2) ($3).",
        "searchmenu-exists": "'''Ye ia zāzanilli ītōca \"[[$1]]\" inīn huiquipan'''",
-       "searchmenu-new": "'''Tihuelīti ticchīhuāz zāzanilli ītōca \"[[:$1]]\" inīn huiquipan'''",
+       "searchmenu-new": "<strong>Ticchīhuāz in zāzanilli «[[:$1]]» inīn huiquipan.</strong> {{PLURAL:$2|0=|Nō xiquitta in tlanāmiquiliztli in mochīhualiztli.}}",
        "searchprofile-articles": "Tlapiyaliztli zāzanilli",
        "searchprofile-images": "Nepapan media",
        "searchprofile-everything": "Mochi",
        "gender-male": "Oquichtli",
        "gender-female": "Cihuātl",
        "email": "E-mail",
-       "prefs-help-realname": "Melāhuac motōca.\nIntlā ticnequi, tlācah quimatīzqueh motequi.",
+       "prefs-help-realname": "In melāhuac tōcāitl mopehpenaliztli.\nIntlā ticmaca, momitztlaīxcoyantīz in motequi.",
        "prefs-help-email-required": "Tihuīquilia quihcuiloa mo e-mailcān.",
        "prefs-signature": "Motōcā",
        "userrights-user-editname": "Xihcuiloa cē tlatequitiltilīltōcāitl:",
-       "editusergroup": "Tiquimpatlāz tlatequitiltilīlli olōlli",
+       "editusergroup": "Tiquimpatlāz {{GENDER:$1|tlatequitiltilīlli}} īolōl",
        "userrights-editusergroup": "Tiquimpatlāz tlatequitiltilīlli olōlli",
-       "saveusergroups": "Tiquimpiyāz tlatequitiltilīlli olōlli",
+       "saveusergroups": "Tiquimpiyāz {{GENDER:$1|tlatequitiltilīlli}} īolōl",
        "userrights-groupsmember": "Olōlco:",
        "userrights-reason": "Īxtlamatiliztli:",
        "userrights-no-interwiki": "Ahmo tihuelīti ticpatla tlatequitiltilīlli huelītiliztli occequīntīn huiquipan.",
        "rightslog": "Tlatequitiltilīlli huelītiliztli tlahcuilōlloh",
        "action-read": "xāmapōhua inīn tlaīxtli",
        "action-edit": "xicpatla inīn tlaīxtli",
-       "action-createpage": "xicchīhua tlaīxtli",
-       "action-createtalk": "tiquinchīhuāz tēixnāmiquiliztli zāzaniltin",
+       "action-createpage": "xicchīhua inīn āmatl",
+       "action-createtalk": "xicchīhuā inīn tēixnāmiquiliztli zāzaniltin",
        "action-createaccount": "ticchīhuaz inīn tlatequitiltilīlli īcuentah",
        "action-move": "ticpatlāz inīn zāzanilli",
        "action-move-subpages": "tiquimpatlāz inīn zāzanilli īhuān zāzaniltōn",
        "newpageletter": "Y",
        "boteditletter": "T",
        "number_of_watching_users_pageview": "[$1 tlatequitiltilīlli {{PLURAL:$1|tlachiya|tlachiyah}}]",
-       "rc_categories_any": "Zāzo",
+       "rc_categories_any": "Zāzo in tlaihittalli",
        "newsectionsummary": "Yancuīc tlahtōltzintli: /* $1 */",
        "recentchangeslinked": "Tlapatlaliztli tzonhuilizpan",
        "recentchangeslinked-feed": "Tlapatlaliztli tzonhuilizpan",
        "whatlinkshere-next": "{{PLURAL:$1|niman|$1 niman}}",
        "whatlinkshere-links": "← tzòwilistìn",
        "whatlinkshere-hideredirs": "$1 tlacuepaliztli",
-       "whatlinkshere-hidelinks": "$1 tzòwilistìn",
+       "whatlinkshere-hidelinks": "$1 tzonhuiliztli",
        "whatlinkshere-hideimages": "$1 tlahcuilōltzonhuīliztli",
        "whatlinkshere-filters": "Tlatzetzelōni",
        "blockip": "Tiquitzacuilīz tlatequitiltilīlli",
        "importbadinterwiki": "Ahcualli interhuiqui tzonhuiliztli",
        "import-upload": "Tiquinquetzāz XML tlahcuilōlli",
        "importlogpage": "Tiquincōhuāz tlahcuilōlloh",
-       "tooltip-pt-userpage": "Notlatequitiltilīlzāzanil",
-       "tooltip-pt-mytalk": "Mozānīl",
-       "tooltip-pt-preferences": "Mopanitlatlālīl",
+       "tooltip-pt-userpage": "{{GENDER:|Motlatequitiltilīlzāzanil}}",
+       "tooltip-pt-mytalk": "{{GENDER:|Motēīxnāmiquiliztli}}",
+       "tooltip-pt-preferences": "{{GENDER:|Motlaēlēhuiliz}}",
        "tooltip-pt-watchlist": "Zāzaniltin tiquintlachiya ic tlapatlaliztli",
-       "tooltip-pt-mycontris": "Notlahcuilōl",
+       "tooltip-pt-mycontris": "{{GENDER:|Motlahcuilōl}}",
        "tooltip-pt-login": "Tihuelīti timocalaqui, tēl ahmo tihuīquilia.",
        "tooltip-pt-logout": "Tiquīzāz",
        "tooltip-ca-talk": "Inīn tlahcuilōlli zānīllī ītechcopa",
        "tooltip-t-recentchangeslinked": "Yancuic tlapatlaliztli inīn zāzanilhuīcpa moquintzonhuilia",
        "tooltip-feed-rss": "RSS tlachicāhualiztli inīn zāzaniltechcopa",
        "tooltip-feed-atom": "Atom tlachicāhualiztli inīn zāzaniltechcopa",
-       "tooltip-t-contributions": "Xiquitta inīn tlatequitiltilīlli ītlahcuilōl",
+       "tooltip-t-contributions": "Tlapōhualmatl ītechpa {{GENDER:$1|inīn tlatequitiltilīlli}} ītlahcuilōl",
        "tooltip-t-emailuser": "Tiquihcuilōz inīn tlatequitiltililhuīc",
        "tooltip-t-upload": "Tiquinquetzāz tlahcuilōlli",
        "tooltip-t-specialpages": "Ìntlapòpòwaltekpànal mochtìn in nònkuâkìskàtlaìxtlapaltìn",
        "tooltip-t-print": "Tepoztlahcuilōlli",
        "tooltip-ca-nstab-main": "Xiquitta in tlamantlaīxtli",
        "tooltip-ca-nstab-user": "Xiquitta tlatequitiltilīlli īzāzanil",
-       "tooltip-ca-nstab-special": "Inìn sè nònkuâkìskàtlaìxtlapalli, yêìka awel nemàtilòs moyêyèktlàlis in tlaìxtlapalli",
+       "tooltip-ca-nstab-special": "Inīn nōncuahquīzqui āmatl, auh ahmohuelitizpatla",
        "tooltip-ca-nstab-project": "Xiquitta in tlatequipanōllaīxtli",
        "tooltip-ca-nstab-image": "Xiquittāz īxipzāzanilli",
        "tooltip-ca-nstab-mediawiki": "Xiquitta in tlahcuilōltzin",
index 057cac7..6332449 100644 (file)
        "moredotdotdot": "Mer …",
        "morenotlisted": "Denne lista er ufullstendig.",
        "mypage": "Min brukerside",
-       "mytalk": "Min diskusjonsside",
+       "mytalk": "Diskusjon",
        "anontalk": "Brukerdiskusjon",
        "navigation": "Navigasjon",
        "and": "&#32;og",
index 2e34b74..bda199e 100644 (file)
        "listgrouprights-group": "समूह",
        "listgrouprights-rights": "अधिकारहरु",
        "listgrouprights-helppage": "Help:सामूहिक अधिकारहरु",
-       "listgrouprights-members": "(सदसà¥\8dयहरà¥\81को सूची)",
+       "listgrouprights-members": "(सदसà¥\8dयहरà¥\82को सूची)",
        "listgrouprights-addgroup": "{{PLURAL:$2|समूह|समूहहरु}}: $1 थप्ने",
        "listgrouprights-removegroup": "{{PLURAL:$2|समूह|समूहहरु}}: $1 हटाउने",
        "listgrouprights-addgroup-all": "सबै समूह थप्ने",
        "contributions": "{{GENDER:$1|प्रयोगकर्ता}}का योगदानहरू",
        "contributions-title": "$1को प्रयोगकर्ता योगदानहरू",
        "mycontris": "योगदानहरू",
+       "anoncontribs": "योगदानहरू",
        "contribsub2": " {{GENDER:$3|$1}} ($2)को लागि",
        "contributions-userdoesnotexist": "प्रयोगकर्ता \"$1\" दर्ता गरिएको छैन् ।",
        "nocontribs": "यस मापदण्ड अनुसार परिवर्त पाइएन।",
        "tooltip-t-recentchangeslinked": "यस पृष्ठमा जोडिएका पृष्ठहरूमा हालैको परिवर्तन",
        "tooltip-feed-rss": "यो पृष्ठको लागि RSS फिड",
        "tooltip-feed-atom": "यो पृष्ठको लागि एटम फिड",
-       "tooltip-t-contributions": "यस प्रयोगकर्ताका योगदानहरूको सूची हेर्नुहोस्",
+       "tooltip-t-contributions": "{{GENDER:$1|यस प्रयोगकर्ता}}का योगदानहरूको सूची हेर्नुहोस्",
        "tooltip-t-emailuser": "यो प्रयोगकर्तालाई इमेल पठाउनुहोस्",
        "tooltip-t-info": "यस पृष्ठको बारेमा थप जानकारी",
        "tooltip-t-upload": "फाइल अपलोड गर्ने",
        "special-characters-title-emdash": "इएम ड्यास",
        "special-characters-title-minus": "घटाउने चिन्ह",
        "mw-widgets-titleinput-description-new-page": "हालसम्म पृष्ठ उपलब्ध छैन्",
-       "mw-widgets-titleinput-description-redirect": "$1 मा जाने",
-       "api-error-blacklisted": "एउटा फरक वर्णनात्मक शीर्षक चयन गर्नुहोस् ।"
+       "mw-widgets-titleinput-description-redirect": "$1 मा जाने"
 }
index 19041c9..3357ad2 100644 (file)
@@ -78,7 +78,8 @@
                        "Lemondoge",
                        "Dinosaur918",
                        "Jdforrester",
-                       "Jeleniccz"
+                       "Jeleniccz",
+                       "MrLeopold"
                ]
        },
        "tog-underline": "Koppelingen onderstrepen:",
        "action-managechangetags": "labels aan te maken en te verwijderen",
        "action-applychangetags": "labels aan uw bewerkingen toe te voegen",
        "action-changetags": "willekeurige labels toe te voegen aan en te verwijderen van versies en logboekregels",
+       "action-purge": "Schoon deze pagina op",
        "nchanges": "$1 {{PLURAL:$1|bewerking|bewerkingen}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sinds uw laatste bezoek}}",
        "enhancedrc-history": "geschiedenis",
index cffe63d..66bf6a4 100644 (file)
        "yourdomainname": "ਤੁਹਾਡਾ ਡੋਮੇਨ:",
        "password-change-forbidden": "ਇਸ ਵਿਕੀ ਤੇ ਤੁਸੀਂ ਪਾਸਵਰਡ ਨਹੀਂ ਬਦਲ ਸਕਦੇ।",
        "externaldberror": "ਜਾਂ ਤਾਂ ਪ੍ਰਮਾਣਕੀ ਡਾਟਾਬੇਸ ਦੋਸ਼ ਆਇਆ ਹੈ ਜਾਂ ਤੁਹਾਨੂੰ ਆਪਣੇ ਬਾਹਰੀ ਖਾਤੇ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ।",
-       "login": "ਲਾà¨\97à¨\87ਨ",
+       "login": "ਦਾà¨\96ਲ",
        "login-security": "ਆਪਣੀ ਪਛਾਣ ਦੀ ਪੜਤਾਲ ਕਰਵਾਉ",
        "nav-login-createaccount": "ਲਾਗਇਨ/ਖਾਤਾ ਬਣਾਓ",
        "userlogin": "ਲਾਗਇਨ/ਖਾਤਾ ਬਣਾਓ",
        "loginlanguagelabel": "ਭਾਸ਼ਾ: $1",
        "suspicious-userlogout": "ਤੁਹਾਡੀ ਵਿਦਾਇਗੀ ਦੀ ਬੇਨਤੀ ਨਕਾਰ ਦਿੱਤੀ ਗਈ ਕਿਉਂਕਿ ਲੱਗਦਾ ਹੈ ਕਿ ਇਹ ਕਿਸੇ ਟੁੱਟੇ ਹੋਏ ਬਰਾਊਜ਼ਰ ਜਾਂ ਕੈਸ਼ ਹੋਈ ਪ੍ਰਾਕਸੀ ਤੋਂ ਭੇਜੀ ਗਈ ਸੀ।",
        "createacct-another-realname-tip": "ਅਸਲੀ ਨਾਂ ਚੋਣਵਾਂ ਹੈ।\nਜੇਕਰ ਤੁਸੀਂ ਇਹ ਦਿੱਤਾ ਹੈ ਤਾਂ ਤੁਹਾਡੇ ਕੰਮ ਵਾਸਤੇ ਗੁਣ ਦੇ ਤੌਰ ਉੱਤੇ ਵਰਤਿਆ ਜਾਵੇਗਾ।",
-       "pt-login": "ਲਾà¨\97 à¨\87ਨ",
-       "pt-login-button": "ਲਾà¨\97 à¨\87ਨ",
+       "pt-login": "ਦਾà¨\96ਲ",
+       "pt-login-button": "ਦਾà¨\96ਲ",
        "pt-createaccount": "ਖਾਤਾ ਬਣਾਓ",
        "pt-userlogout": "ਬਾਹਰ ਆਉ",
        "php-mail-error-unknown": "PHP ਦੇ ਮੇਲ() ਕਰਜ ਵਿੱਚ ਅਣਜਾਣ ਦੋਸ਼",
        "nosuchsectiontitle": "ਭਾਗ ਲੱਭ ਨਹੀਂ ਰਿਹਾ",
        "nosuchsectiontext": "ਤੁਸੀਂ ਨਾ-ਮੌਜੂਦ ਭਾਗ ਨੂੰ ਸੋਧਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ।\nਸ਼ਾਇਦ ਤੁਹਾਡੇ ਸਫ਼ੇ ਨੂੰ ਵੇਖਣ ਦੇ ਦੌਰਾਨ ਇਹ ਮਿਟਾਇਆ ਜਾਂ ਇਸਦਾ ਸਿਰਲੇਖ ਬਦਲਿਆ ਜਾ ਚੁੱਕਾ ਹੈ।",
        "loginreqtitle": "ਲਾਗਇਨ ਚਾਹੀਦਾ ਹੈ",
-       "loginreqlink": "ਲਾà¨\97à¨\87ਨ",
+       "loginreqlink": "ਦਾà¨\96ਲ",
        "loginreqpagetext": "ਹੋਰ ਸਫ਼ੇ ਵੇਖਣ ਲਈ ਤੁਹਾਨੂੰ $1 ਕਰਨਾ ਪਵੇਗਾ।",
        "accmailtitle": "ਪਾਸਵਰਡ ਭੇਜਿਆ।",
        "accmailtext": "[[User talk:$1|$1]] ਲਈ ਰਲ਼ਵੇਂ ਤੌਰ ’ਤੇ ਬਣਿਆ ਪਾਸਵਰਡ $2 ਨੂੰ ਭੇਜਿਆ ਜਾ ਚੁੱਕਾ ਹੈ।\nਇਸ ਨਵੇਂ ਖਾਤੇ ਲਈ ਲਾਗਇਨ ਕਰਨ ਤੋਂ ਬਾਅਦ ''[[Special:ChangePassword|ਪਾਸਵਰਡ ਬਦਲੋ]]'' ’ਤੇ ਜਾ ਕੇ ਪਾਸਵਰਡ ਬਦਲਿਆ ਜਾ ਸਕਦਾ ਹੈ।",
        "tooltip-pt-mycontris": "ਤੁਹਾਡੇ ਯੋਗਦਾਨਾਂ ਦੀ ਸੂਚੀ",
        "tooltip-pt-login": "ਤੁਹਾਨੂੰ ਦਾਖ਼ਲ ਹੋਣ ਲਈ ਪ੍ਰੇਰਿਆ ਜਾਂਦਾ ਹੈ; ਪਰ ਇਹ ਕੋਈ ਲਾਜ਼ਮੀ ਨਹੀਂ",
        "tooltip-pt-logout": "ਸਾਈਟ ਤੋਂ ਬਾਹਰ ਆਉ",
-       "tooltip-pt-createaccount": "ਤà©\81ਹਾਨà©\82à©° à¨\96ਾਤਾ à¨¬à¨£à¨¾à¨\89ਣ à¨¤à©\8bà¨\82 à¨¬à¨¾à¨\85ਦ à¨²à¨¾à¨\97 à¨\87ਨ ਕਰਨ ਦੀ ਸਲਾਹ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ; ਹਾਲਾਂਕਿ ਇਹ ਲਾਜ਼ਮੀ ਨਹੀਂ",
+       "tooltip-pt-createaccount": "ਤà©\81ਹਾਨà©\82à©° à¨\96ਾਤਾ à¨¬à¨£à¨¾à¨\89ਣ à¨¤à©\8bà¨\82 à¨¬à¨¾à¨\85ਦ à¨¦à¨¾à¨\96ਲ ਕਰਨ ਦੀ ਸਲਾਹ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ; ਹਾਲਾਂਕਿ ਇਹ ਲਾਜ਼ਮੀ ਨਹੀਂ",
        "tooltip-ca-talk": "ਸਮਗੱਰੀ ਸਫ਼ੇ ਬਾਰੇ ਚਰਚਾ",
        "tooltip-ca-edit": "ਇਹ ਸਫ਼ਾ ਸੋਧੋ",
        "tooltip-ca-addsection": "ਨਵਾਂ ਭਾਗ ਸ਼ੁਰੂ ਕਰੋ",
index 5eb8b4a..2e10b6a 100644 (file)
        "watchnologin": "Nie jesteś zalogowany",
        "addwatch": "Dodaj do listy obserwowanych",
        "addedwatchtext": "Strona „[[:$1|$1]]” wraz ze swoją stroną dyskusji została dodana do Twojej [[Special:Watchlist|listy obserwowanych]].",
+       "addedwatchtext-talk": "Strona „[[:$1]]” i strony z nią związane zostały dodane do Twojej [[Special:Watchlist|listy obserwowanych]].",
        "addedwatchtext-short": "Strona „$1” została dodana do twojej listy obserwowanych.",
        "removewatch": "Usuń z listy obserwowanych",
        "removedwatchtext": "Strona „[[:$1|$1]]” wraz ze swoją stroną dyskusji została usunięta z Twojej [[Special:Watchlist|listy obserwowanych]].",
+       "removedwatchtext-talk": "Strona „[[:$1]]” i strony z nią związane zostały usunięte z Twojej [[Special:Watchlist|listy obserwowanych]].",
        "removedwatchtext-short": "Strona „$1” została usunięta z twojej listy obserwowanych.",
        "watch": "Obserwuj",
        "watchthispage": "Obserwuj",
        "confirm-unwatch-button": "OK",
        "confirm-unwatch-top": "Usunąć tę stronę z listy obserwowanych?",
        "confirm-rollback-button": "OK",
+       "confirm-rollback-top": "Wycofać edycje tej strony?",
        "percent": "$1%",
        "quotation-marks": "„$1”",
        "imgmultipageprev": "← poprzednia strona",
        "timezone-local": "Czas lokalny",
        "duplicate-defaultsort": "Uwaga: Domyślnym kluczem sortowania będzie „$2” i zastąpi on wcześniej wykorzystywany klucz „$1”.",
        "duplicate-displaytitle": "<strong>Uwaga:</strong> Wyświetlenie tytułu „$2” powoduje nadpisanie wcześniej wyświetlanego tytułu „$1”.",
+       "restricted-displaytitle": "<strong>Ostrzeżenie:</strong> Tytuł do wyświetlania \"$1\" został zignorowany, ponieważ nie jest odpowiednikiem aktualnego tytułu tej strony.",
        "invalid-indicator-name": "<strong>Błąd:</strong> Atrybut stanu strony <code>name</code> nie może być pusty.",
        "version": "Wersja oprogramowania",
        "version-extensions": "Zainstalowane rozszerzenia",
        "tags-deactivate": "dezaktywuj",
        "tags-hitcount": "$1 {{PLURAL:$1|zmiana|zmiany|zmian}}",
        "tags-manage-no-permission": "Nie masz uprawnień do zarządzania znacznikami.",
+       "tags-manage-blocked": "Nie możesz zarządzać znacznikami zmian, kiedy jesteś zablokowany.",
        "tags-create-heading": "Utwórz nowy znacznik",
        "tags-create-explanation": "Nowe znaczniki będą dostępne domyślnie dla użytkowników i botów.",
        "tags-create-tag-name": "Nazwa znacznika:",
        "tags-delete-not-found": "Znacznik „$1” nie istnieje.",
        "tags-delete-too-many-uses": "Znacznik „$1” jest stosowany w więcej niż {{PLURAL:$2|jednej wersji|$2 wersjach}}, co oznacza, że nie może być usunięty.",
        "tags-delete-warnings-after-delete": "Znacznik „$1” został usunięty, ale {{PLURAL:$2|otrzymano następujące ostrzeżenie|otrzymano następujące ostrzeżenia}}:",
+       "tags-delete-no-permission": "Nie masz uprawnień do usuwania znaczników zmian.",
        "tags-activate-title": "Aktywacja znacznika",
        "tags-activate-question": "Zamierzasz aktywować znacznik „$1”.",
        "tags-activate-reason": "Powód:",
        "tags-deactivate-not-allowed": "Nie można dezaktywować znacznika „$1”.",
        "tags-deactivate-submit": "Dezaktywuj",
        "tags-apply-no-permission": "Nie masz uprawnień do wprowadzania znaczników wraz z własnymi zmianami.",
+       "tags-apply-blocked": "Nie możesz stosować znaczników do swoich zmian, gdy jesteś zablokowany.",
        "tags-apply-not-allowed-one": "Znacznik „$1” nie może zostać wprowadzony ręcznie.",
        "tags-apply-not-allowed-multi": "{{PLURAL:$2|Następujący znacznik nie może zostać wprowadzony ręcznie|Następujące znaczniki nie mogą zostać wprowadzone ręcznie}}: $1",
        "tags-update-no-permission": "Nie masz uprawnień do dodawania lub usuwania znaczników z poszczególnych wersji lub wpisów w rejestrze.",
+       "tags-update-blocked": "Nie możesz dodawać i usuwać znaczników zmian, kiedy jesteś zablokowany.",
        "tags-update-add-not-allowed-one": "Znacznik „$1” nie może zostać dodany ręcznie.",
        "tags-update-add-not-allowed-multi": "{{PLURAL:$2|Następujący znacznik nie może zostać dodany ręcznie|Następujące znaczniki nie mogą zostać dodane ręcznie}}: $1",
        "tags-update-remove-not-allowed-one": "Znacznika „$1” nie można usunąć.",
        "api-error-nomodule": "Błąd wewnętrzny – nie określono modułu przesyłania plików.",
        "api-error-ok-but-empty": "Błąd wewnętrzny – brak odpowiedzi od serwera.",
        "api-error-overwrite": "Nadpisanie istniejącego pliku nie jest dopuszczalne.",
+       "api-error-ratelimited": "Próbujesz przesłać więcej plików w krótszym odstępie czasowym, niż ta wiki na to pozwala.\nSpróbuj jeszcze raz za kilka minut.",
        "api-error-stashfailed": "Błąd wewnętrzny – serwer nie mógł zapisać pliku tymczasowego.",
        "api-error-publishfailed": "Błąd wewnętrzny: serwer nie mógł zapisać pliku tymczasowego.",
        "api-error-stasherror": "Wystąpił błąd podczas przesyłania pliku.",
        "mw-widgets-titleinput-description-new-page": "strona jeszcze nie istnieje",
        "mw-widgets-titleinput-description-redirect": "przekierowanie do $1",
        "sessionmanager-tie": "Nie można łączyć kilku rodzajów uwierzytelniania dla zapytania: $1.",
+       "sessionprovider-generic": "sesje $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "sesje na podstawie cookie",
        "sessionprovider-nocookies": "Być może cookies są wyłączone. Upewnij się, że masz włączone cookies i zacznij od nowa.",
        "randomrootpage": "Losowa strona (bez podstron)",
index 84fbdf3..a7709b6 100644 (file)
        "feedback-thanks-title": "Obrigado!",
        "feedback-useragent": "Agente de usuário:",
        "searchsuggest-search": "Pesquisa",
-       "searchsuggest-containing": "contendo...",
+       "searchsuggest-containing": "páginas contendo…",
        "api-error-badaccess-groups": "Você não tem permissão para enviar arquivos para este wiki.",
        "api-error-badtoken": "Erro interno: token inválido.",
        "api-error-copyuploaddisabled": "O upload por URL está desativado neste servidor.",
index 9b44b28..3a0cfb0 100644 (file)
        "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.",
        "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.",
        "watch": "Vigiar",
        "watchthispage": "Vigiar esta página",
index b553756..1e8db1e 100644 (file)
                        "Guycn2",
                        "2axterix2",
                        "Ата",
-                       "Matěj Suchánek"
+                       "Matěj Suchánek",
+                       "Chaduvari"
                ]
        },
        "sidebar": "{{notranslate}}",
        "passwordreset-emailelement": "This is a body of a password reset email to allow them into the system with a new password. Parameters:\n* $1 - the user's login name. This parameter can be used for GENDER.\n* $2 - the temporary password given by the system",
        "passwordreset-emailsentemail": "Used in [[Special:PasswordReset]].\n\nSee also:\n* {{msg-mw|Passwordreset-emailsent-capture}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
        "passwordreset-emailsentusername": "Used in [[Special:PasswordReset]].\n\nSee also:\n* {{msg-mw|Passwordreset-emailsent-capture}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
-       "passwordreset-emailsent-capture": "Used in [[Special:PasswordReset]].\n\nSee also:\n* {{msg-mw|Passwordreset-emailsentemail}}\n* {{msg-mw|Passwordreset-emailsentusername}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
-       "passwordreset-emailerror-capture": "Error message displayed in [[Special:PasswordReset]] when sending an email fails. Parameters:\n* $1 - error message\n* $2 - username, used for GENDER\nSee also:\n* {{msg-mw|Passwordreset-emailsentemail}}\n* {{msg-mw|Passwordreset-emailsentusername}}\n* {{msg-mw|Passwordreset-emailsent-capture}}",
        "passwordreset-emailsent-capture2": "Used in [[Special:PasswordReset]].\n\nParameters:\n* $1 - number of accounts notified\n\nSee also:\n* {{msg-mw|Passwordreset-emailsentemail}}\n* {{msg-mw|Passwordreset-emailsentusername}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
        "passwordreset-emailerror-capture2": "Error message displayed in [[Special:PasswordReset]] when sending an email fails. Parameters:\n* $1 - error message\n* $2 - username, used for GENDER\n* $3 - number of accounts notified\n\nSee also:\n* {{msg-mw|Passwordreset-emailsentemail}}\n* {{msg-mw|Passwordreset-emailsentusername}}\n* {{msg-mw|Passwordreset-emailsent-capture}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
        "passwordreset-nocaller": "Shown when a password reset was requested but the caller was not provided. This is an internal error.",
        "changeemail": "Title of [[Special:ChangeEmail|special page]]. This page also allows removing the user's email address.",
        "changeemail-summary": "{{ignored}}",
        "changeemail-header": "Text of [[Special:ChangeEmail]].",
-       "changeemail-passwordrequired": "Shown on [[Special:ChangeEmail]] if users are required to enter their password to change their email address..",
        "changeemail-no-info": "Error message for [[Special:ChangeEmail]].\n\nParameters:\n* $1 (unused) - a link to [[Special:UserLogin]] with {{msg-mw|loginreqlink}} as link description",
        "changeemail-oldemail": "Label for e-mail address field in [[Special:ChangeEmail]].",
        "changeemail-newemail": "Label for e-mail address field in [[Special:ChangeEmail]]. See also {{msg-mw|changeemail-newemail-help}}",
        "watchthis": "Text of checkbox above {{msg-mw|Showpreview}} button in editor.\n\nSee also:\n* {{msg-mw|Watchthis}}\n* {{msg-mw|Accesskey-watch}}\n* {{msg-mw|Tooltip-watch}}\n{{Identical|Watch this page}}",
        "savearticle": "Text on the button to create a new page. It should be an action which is short and makes clear that the effect is immediate and public.\n\nSee also {{msg-mw|showpreview}} and {{msg-mw|showdiff}} for the other buttons, and {{msg-mw|savechanges}} for the label for the button when the page is being modified.\n\nSee also:\n* {{msg-mw|Accesskey-publish}}\n* {{msg-mw|Tooltip-publish}}\n{{Identical|Save page}}",
        "savechanges": "Text on the button to save the changes to an existing page. It should be an action which is short and makes clear that the effect is immediate and public.\n\nSee also {{msg-mw|showpreview}} and {{msg-mw|showdiff}} for the other buttons, and {{msg-mw|savearticle}} for the label for the button when the page is being modified.\n\nNote: This i18n is being introduced in advance of usage to provide extra time for translators.\n\nSee also:\n* {{msg-mw|Accesskey-publish}}\n* {{msg-mw|Tooltip-publish}}\n{{Identical|Save changes}}",
-       "publishpage": "Text on the button to create a new page on a public wiki. It should be an action which is short and makes clear that the effect is immediate and public.\n\nSee also {{msg-mw|showpreview}} and {{msg-mw|showdiff}} for the other buttons, and {{msg-mw|publishchanges}} for the label for the button when the page is being modified.\n\nNote: This i18n is being introduced in advance of usage to provide extra time for translators.\n\nSee also:\n* {{msg-mw|Accesskey-publish}}\n* {{msg-mw|Tooltip-publish}}\n{{Identical|Publish page}}",
-       "publishchanges": "Text on the button to save the changes to an existing page on a public wiki. It should be an action which is short and makes clear that the effect is immediate and public.\n\nSee also {{msg-mw|showpreview}} and {{msg-mw|showdiff}} for the other buttons, and {{msg-mw|publishchanges}} for the label for the button when the page is being created.\n\nNote: This i18n is being introduced in advance of usage to provide extra time for translators.\n\nSee also:\n* {{msg-mw|Accesskey-publish}}\n* {{msg-mw|Tooltip-publish}}\n{{Identical|Publish changes}}",
+       "publishpage": "పేజీని ప్రచురించు",
+       "publishchanges": "మార్పులను ప్రచురించు",
        "preview": "The title of the Preview page shown after clicking the \"Show preview\" button in the edit page. Since this is a heading, it should probably be translated as a noun and not as a verb.\n\n{{Identical|Preview}}",
        "showpreview": "The text of the button to preview the page you are editing. See also {{msg-mw|showdiff}} and {{msg-mw|savearticle}} for the other buttons.\n\nSee also:\n* {{msg-mw|Showpreview}}\n* {{msg-mw|Accesskey-preview}}\n* {{msg-mw|Tooltip-preview}}\n{{Identical|Show preview}}",
        "showdiff": "Button below the edit page. See also {{msg-mw|Showpreview}} and {{msg-mw|Savearticle}} for the other buttons.\n\nSee also:\n* {{msg-mw|Showdiff}}\n* {{msg-mw|Accesskey-diff}}\n* {{msg-mw|Tooltip-diff}}\n{{Identical|Show change}}",
        "undo-nochange": "Message appears if an attempt to revert an edit by clicking the \"undo\" link results in an edit making no change to the current version of the page.\n\nSee also:\n* {{msg-mw|Undo-failure}}\n* {{msg-mw|Undo-norev}}",
        "undo-summary": "Edit summary for an undo action. Parameters:\n* $1 - revision ID\n* $2 - username\n{{Identical|Undo}}",
        "undo-summary-username-hidden": "Edit summary for an undo action where the username of the old revision is hidden.\n\nParameters:\n* $1 - the revision ID being undone\nSee also:\n* {{msg-mw|Undo-summary}}",
-       "cantcreateaccounttitle": "Used as title of the error message {{msg-mw|Cantcreateaccount-text}}.",
-       "cantcreateaccount-text": "Used as error message, with the title {{msg-mw|Cantcreateaccounttitle}}.\n* $1 - target IP address\n* $2 - reason or {{msg-mw|Blockednoreason}}\n* $3 - username\nSee also:\n* {{msg-mw|Cantcreateaccount-range-text}}",
+       "cantcreateaccount-text": "Used as error message when account creation is prevented by an IP block.\n* $1 - target IP address\n* $2 - reason or {{msg-mw|Blockednoreason}}\n* $3 - username\nSee also:\n* {{msg-mw|Cantcreateaccount-range-text}}",
        "cantcreateaccount-range-text": "Used instead of the {{msg-mw|Cantcreateaccount-text}} when the block is a range block.\n* $1 - target IP address range\n* $2 - reason or {{msg-mw|Blockednoreason}}\n* $3 - username\n* $4 - current user's IP address",
        "createaccount-hook-aborted": "Placeholder message to return with API errors on account create; passes through the message from a hook {{notranslate}}",
        "viewpagelogs": "Link displayed in history of pages",
        "watchlistanontext": "Shown on Special:Userlogin when user tries to access their watchlist before logging in",
        "watchnologin": "Used as error page title.\n\nThe error message for this title is:\n* {{msg-mw|Watchnologintext}}\n{{Identical|Not logged in}}",
        "addwatch": "Link to a dialog box, displayed at the end of the list of categories at the foot of each page.\n\nSee also:\n* {{msg-mw|Removewatch}}",
-       "addedwatchtext": "Explanation shown when clicking on the {{msg-mw|Watch}} tab. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Addedwatch}}",
+       "addedwatchtext": "Message shown after clicking on the {{msg-mw|Watch}} tab in a content namespace page. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Removedwatchtext}}\n* {{msg-mw|Addedwatchtext-talk}}",
+       "addedwatchtext-talk": "Message shown after clicking on the {{msg-mw|Watch}} tab in a talk namespace page. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Removedwatchtext-talk}}\n* {{msg-mw|Addedwatchtext}}",
        "addedwatchtext-short": "Explanation shown when watching item from [[Special:UnwatchedPages]].\n\nSee also:\n* {{msg-mw|Removedwatchtext-short}}\n* {{msg-mw|Addedwatchtext}}",
        "removewatch": "Link to a dialog box, displayed at the end of the list of categories at the foot of each page.\n\nSee also:\n* {{msg-mw|Addwatch}}",
-       "removedwatchtext": "After a page has been removed from a user's watchlist by clicking the {{msg-mw|Unwatch}} tab at the top of an article, this message appears just below the title of the article.\n\nParameters:\n* $1 - the title of the article\nSee also:\n* {{msg-mw|Removedwatch}}\n* {{msg-mw|Addedwatchtext}}",
+       "removedwatchtext": "Message shown after clicking on the {{msg-mw|Unwatch}} tab in a content namespace page. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Addedwatchtext}}\n* {{msg-mw|Removedwatchtext-talk}}",
+       "removedwatchtext-talk": "Message shown after clicking on the {{msg-mw|Unwatch}} tab in a talk namespace page. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Addedwatchtext-talk}}\n* {{msg-mw|Removedwatchtext}}",
        "removedwatchtext-short": "Explanation shown when unwatching item from [[Special:UnwatchedPages]].\n\nSee also:\n* {{msg-mw|Addedwatchtext-short}}.\n* {{msg-mw|Removedwatchtext}}.",
        "watch": "{{doc-actionlink}}\nName of the Watch tab. Should be in the imperative mood.\n\nSee also:\n* {{msg-mw|Watch}}\n* {{msg-mw|Accesskey-ca-watch}}\n* {{msg-mw|Tooltip-ca-watch}}",
        "watchthispage": "Used as link text.\n\nSee also:\n* {{msg-mw|Unwatchthispage|link text}}\n* {{msg-mw|Notanarticle|error message}}\n{{Identical|Watch this page}}",
index 080ae69..590fc20 100644 (file)
@@ -29,7 +29,8 @@
                        "ImGelu",
                        "Wintereu",
                        "Rsocol",
-                       "Nemo bis"
+                       "Nemo bis",
+                       "Turbojet"
                ]
        },
        "tog-underline": "Sublinierea legăturilor:",
        "watchthis": "Urmărește această pagină",
        "savearticle": "Salvare pagină",
        "publishpage": "Publică pagina",
+       "publishchanges": "Publică modificările",
        "preview": "Previzualizare",
        "showpreview": "Previzualizare",
        "showdiff": "Afișare diferențe",
index da33a37..7a266a8 100644 (file)
        "site-atom-feed": "$1 — Atom-лента",
        "page-rss-feed": "«$1» — RSS-лента",
        "page-atom-feed": "«$1» — Atom-лента",
-       "feed-atom": "Атом",
+       "feed-atom": "Atom",
        "red-link-title": "$1 (страница не существует)",
        "sort-descending": "Упорядочить по убыванию",
        "sort-ascending": "Упорядочить по возрастанию",
        "watchthis": "Следить за этой страницей",
        "savearticle": "Записать страницу",
        "savechanges": "Сохранить изменения",
-       "publishpage": "издавать страницу",
-       "publishchanges": "Ð\9eпÑ\83бликоваÑ\82Ñ\8c Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ\8f",
+       "publishpage": "Создать страницу",
+       "publishchanges": "Ð\97апиÑ\81аÑ\82Ñ\8c Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83",
        "preview": "Предпросмотр",
        "showpreview": "Предварительный просмотр",
        "showdiff": "Внесённые изменения",
index 54c4e65..c146a73 100644 (file)
        "minoredit": "Ovo je manje uređenje",
        "watchthis": "Prati ovu stranicu",
        "savearticle": "Spremi stranicu",
+       "publishpage": "Objavi stranicu",
+       "publishchanges": "Objavi izmjene",
        "preview": "Pregled",
        "showpreview": "Prikaži pregled",
        "showdiff": "Prikaži izmjene",
index 81007c5..4f1d008 100644 (file)
        "tagline": "Iz {{GRAMMAR:rodilnik|{{SITENAME}}}}",
        "help": "Pomoč",
        "search": "Iskanje",
+       "search-ignored-headings": " #<!-- te vrstice ne spreminjajte --> <pre>\n# Poglavja, ki bodo prezrta pri iskanju.\n# Spremembe bodo začele veljati takoj, ko bo stran s poglavjem indeksirana.\n# Reindeksacijo strani lahko vsilite z ničelnim urejanjem.\n# Skladnja je sledeča:\n#   * Vse od znaka »#« do konca vrstice je pripomba.\n#   * Vsaka neprazna vrstica je natančen naslov, ki ga bomo prezrli, upoštevajoč velikost črk in ostalo.\nOpombe\nOpombe in sklici\nViri\nZunanje povezave\nGlej tudi\n #</pre> <!-- te vrstice ne spreminjajte -->",
        "searchbutton": "Iskanje",
        "go": "Pojdi na",
        "searcharticle": "Pojdi na",
        "watchnologin": "Niste prijavljeni",
        "addwatch": "Dodaj na spisek nadzorov",
        "addedwatchtext": "»[[:$1]]« in pripadajočo pogovorno stran smo dodali na vaš [[Special:Watchlist|spisek nadzorov]].",
+       "addedwatchtext-talk": "»[[:$1]]« in pripadajočo stran smo dodali na vaš [[Special:Watchlist|spisek nadzorov]].",
        "addedwatchtext-short": "Stran »$1« smo dodali na vaš spisek nadzorov.",
        "removewatch": "Odstrani s spiska nadzorov",
        "removedwatchtext": "»[[:$1]]« in pripadajočo pogovorno stran smo odstranili z vašega [[Special:Watchlist|spiska nadzorov]].",
+       "removedwatchtext-talk": "»[[:$1]]« in pripadajočo stran smo odstranili z vašega [[Special:Watchlist|spiska nadzorov]].",
        "removedwatchtext-short": "Stran »$1« smo odstranili z vašega spiska nadzorov.",
        "watch": "Opazuj",
        "watchthispage": "Opazuj stran",
index c595457..3f5bf22 100644 (file)
@@ -17,7 +17,8 @@
                        "Tchoř",
                        "Timpul",
                        "아라",
-                       "Macofe"
+                       "Macofe",
+                       "Uostofchuodnego"
                ]
        },
        "tog-underline": "Podsztrychńyńcy linkůw:",
        "listingcontinuesabbrev": "ć.d.",
        "index-category": "Indeksowane zajty",
        "noindex-category": "Ńyindeksowane zajty",
-       "broken-file-category": "Zajty ze linkomi lo ńyistniejących ůobrozkůw",
+       "broken-file-category": "Zajty z linkami do niyôbecnych zbiorōw",
        "about": "Uo serwiśe",
        "article": "zajta",
        "newwindow": "(uodwjyro śe we nowym uokńe)",
        "unprotectthispage": "Uodymkńij ta zajta",
        "newpage": "Nowy artikel",
        "talkpage": "Godej uo tym artiklu",
-       "talkpagelinktext": "Dyskusyjo",
+       "talkpagelinktext": "dyskusyjŏ",
        "specialpage": "Szpecyjolno zajta",
        "personaltools": "Perzōnŏlne",
        "articlepage": "Zajta artikla",
        "disclaimers": "Prawne informacyje",
        "disclaimerpage": "Project:Prawne informacyje",
        "edithelp": "Půmoc we půmjyńańy",
-       "mainpage": "Przodńo zajta",
+       "mainpage": "Przodniŏ zajta",
        "mainpage-description": "Przodńo zajta",
        "policy-url": "Project:Prawidła",
        "portal": "Portal używoczůw",
        "newmessageslinkplural": "{{PLURAL:$1|jedno nowina|999=nowiny}}",
        "newmessagesdifflinkplural": "{{PLURAL:$1|uostatńe sprowjyńe|999=uostatńe sprowjyńa}}",
        "youhavenewmessagesmulti": "Mosz nowe powjadůmjyńa: $1",
-       "editsection": "Sprowjej",
+       "editsection": "edytuj",
        "editold": "sprowjej",
        "viewsourceold": "pokoż zdrzůdło",
        "editlink": "sprowjej",
        "viewsourcelink": "zdrzůdłowy tekst",
-       "editsectionhint": "Sprowjej tajla: $1",
+       "editsectionhint": "Edytuj tajlã: $1",
        "toc": "Treść",
        "showtoc": "uobejrzij",
        "hidetoc": "schrůń",
        "nstab-template": "Muster",
        "nstab-help": "Zajta půmocy",
        "nstab-category": "Kategoryjo",
+       "mainpage-nstab": "Przodniŏ zajta",
        "nosuchaction": "Ńy mo takij uoperacyji",
        "nosuchactiontext": "Uoprogramowańy ńy rozpoznowo uoperacyji takij kej podano w URL.",
        "nosuchspecialpage": "Ńy mo takij szpecyjolnyj zajty",
        "resetpass-abort-generic": "Půmjyńańe hasła uostoła zatrzimane bez rozszyrzyńe.",
        "passwordreset": "Wyczyść hasło",
        "passwordreset-disabled": "No tyj wiki zamkńynto resytowańy hasył.",
-       "passwordreset-username": "Mjano używacza:",
+       "passwordreset-username": "Miano ôd używŏcza:",
        "passwordreset-domain": "Domyna:",
        "passwordreset-capture": "Pokozać treść e-brifa?",
        "passwordreset-capture-help": "Eli zaznaczysz to pole, uobejrzisz wjadůmość e-brifa ze hasłym.",
        "skin-preview": "podglůnd",
        "datedefault": "Důmyślny",
        "prefs-labs": "Funkcyje \"labs\"",
-       "prefs-user-pages": "Zajty używaczy",
+       "prefs-user-pages": "Zajty ôd używŏczōw",
        "prefs-personal": "Dane używocza",
        "prefs-rc": "Ńydowno pomjyńane",
        "prefs-watchlist": "Pozůrlista",
        "userrights-changeable-col": "Grupy, kere moges wybrać",
        "userrights-unchangeable-col": "Grupy, kerych ńy moges wybrać",
        "group": "Grupa:",
-       "group-user": "Używacze",
-       "group-autoconfirmed": "AutůmatyczÅ\84y zatwjerdzůne używacze",
+       "group-user": "Używŏcze",
+       "group-autoconfirmed": "AutÅ\8dmatycznie przituplowani używÅ\8fcze",
        "group-bot": "Boty",
        "group-sysop": "Admińi",
        "group-bureaucrat": "Bjurokraty",
        "group-suppress": "Rewizorze",
        "group-all": "(wszyjscy)",
-       "group-user-member": "{{GENDER:$1|używacz}}",
-       "group-autoconfirmed-member": "AutůmatyczÅ\84y zatwjerdzůny używacz",
+       "group-user-member": "{{GENDER:$1|używŏcz|używŏczka}}",
+       "group-autoconfirmed-member": "AutÅ\8dmatycznie {{GENDER:$1|przituplowany używÅ\8fcz|przituplowanÅ\8f używÅ\8fczka}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
        "group-sysop-member": "{{GENDER:$1|admin}}",
        "group-bureaucrat-member": "{{GENDER:$1|bjurokrata}}",
        "group-suppress-member": "{{GENDER:$1|rewizůr}}",
-       "grouppage-user": "{{ns:project}}:Używacze",
-       "grouppage-autoconfirmed": "{{ns:project}}:AutůmatyczÅ\84y zatwjerdzyÅ\84i używacze",
+       "grouppage-user": "{{ns:project}}:Używŏcze",
+       "grouppage-autoconfirmed": "{{ns:project}}:AutÅ\8dmatycznie przituplowani używÅ\8fcze",
        "grouppage-bot": "{{ns:project}}:Boty",
        "grouppage-sysop": "{{ns:project}}:Admińistratory",
        "grouppage-bureaucrat": "{{ns:project}}:Bjurokraty",
        "nopagetitle": "Ńy ma sam zajty docelowyj",
        "nopagetext": "Wybrano zajta docelowo ńy istńeje.",
        "pager-newer-n": "{{PLURAL:$1|1 nowšy|$1 nowše|$1 nowšych}}",
-       "pager-older-n": "{{PLURAL:$1|1 staršy|$1 starše|$1 staršych}}",
+       "pager-older-n": "{{PLURAL:$1|1 starszy|$1 starsze|$1 starszych}}",
        "suppress": "Oversight",
        "booksources": "Kśůnžki",
        "booksources-search-legend": "Sznupej za zdrzůdłůma kśůnżkowymi",
        "listusers-noresult": "Ńy znejdźůno žodnygo užytkowńika.",
        "activeusers-hidebots": "Schrůń boty",
        "activeusers-hidesysops": "Schrůń adminy",
-       "activeusers-noresult": "Ńy sům używacze.",
+       "activeusers-noresult": "Niy szło znŏjść żŏdnych używŏczōw",
        "listgrouprights": "Uprawńyńo grup użytkowńikůw",
        "listgrouprights-summary": "Půńiży znojdowo śe spis grup użytkowńikůw zdefińjowanych na tyj wiki, s wyszczygůlńyńym przidźelůnych im prow dostympu.\nSprowdź zajta [[{{MediaWiki:Listgrouprights-helppage}}|s dodatkowymi informacjami]] uo uprowńyńach użytkowńikůw.",
        "listgrouprights-key": "* <span class=\"listgrouprights-granted\">Dane uprawńyńy</span>\n* <span class=\"listgrouprights-revoked\">Uodebrane uprawńyńy</span>",
        "mailnologintext": "Muśyš śe [[Special:UserLogin|zalůgować]] i mjeć wpisany aktualny adres e-brif w swojich [[Special:Preferences|preferyncyjach]], coby můc wysuać e-brif do inkšygo užytkowńika.",
        "emailuser": "Poślij tymu używoczowi e-brif",
        "emailpagetext": "Możesz użyć půńiższygo formularza, coby wysłać wjadůmość e-brif do tygo użytkowńika.\nAdres e-brifa, kery zostoł bez Ćebje wkludzůny we [[Special:Preferences|Twojich sztalowańach]], pojawi śe we polu „Uod”, bez cůż uodbjorca bydźe můg Ći uodpedźeć.",
-       "defemailsubject": "{{SITENAME}} - e-brif uod używacza \"$1\"",
-       "usermaildisabled": "E-brif używacza ńy załůnczony",
+       "defemailsubject": "{{SITENAME}} - e-mail ôd używŏcza \"$1\"",
+       "usermaildisabled": "E-mail ôd używŏcza je zastŏwiōny",
        "noemailtitle": "Brak adresu e-brif",
-       "noemailtext": "Tyn używacz ńy podoł dobrygo e-brifa, abo zadecydowoł, co ńy chce uotrzimywać wjadůmośći e-brif uod inkszych używaczy.",
-       "nowikiemailtext": "Tyn sprowjorz ńy chcy e-brifůw uod inkszych używaczy.",
+       "noemailtext": "Tyn używŏcz niy podoł nŏleżnyj adresy email.",
+       "nowikiemailtext": "Tyn używŏcz niy chce dostŏwać emaili ôd inkszych.",
        "emailtarget": "Podej adresata",
-       "emailusername": "Mjano używacza:",
+       "emailusername": "Miano ôd używŏcza:",
        "emailusernamesubmit": "Poślij",
        "email-legend": "Wyślij e-brif ku inkszymu użytkowńikowi {{GRAMMAR:MS.lp|{{SITENAME}}}}",
        "emailfrom": "Uod:",
        "delete-confirm": "Wyćep „$1”",
        "delete-legend": "Wyćep",
        "historywarning": "Pozor! Ta zajta kerům chceš wyćepnůńć mo historjo:",
-       "confirmdeletetext": "Chceš wyćepnůńć trwale artikel abo plik s bazy danych s historią. Pokož, aže wjyš co robdza, i to aže to je tak jak godojům [[{{MediaWiki:Policy-url}}|zasady]].",
+       "confirmdeletetext": "Zarŏz wyciepniesz artikel i cołkõ ôd niygo historyjõ. Przitupluj, iże na isto chcesz to zrobić, miarkujesz kōnsekwyncyje, i co robisz to podle [[{{MediaWiki:Policy-url}}|prawideł]].",
        "actioncomplete": "Fertig",
        "actionfailed": "Ńy udało sie.",
        "deletedtext": "Wyćepano \"$1\". Rejer uostatnio zrobiůnych wyćepań možeš uobejžyć tukej: $2.",
        "contribsub2": "Lo {{GENDER:$3|używocza|używoczki}} $1 ($2)",
        "nocontribs": "Brak pomjyńań uodpowjadajůncych tym kryterjům.",
        "uctop": "(teroźńo)",
-       "month": "Uod mjeśůnca (i downiyjše):",
-       "year": "Uod roku (i dowńijše):",
+       "month": "Do miesiōnca:",
+       "year": "Do roku:",
        "sp-contributions-newbies": "Pokoż ajnzac ino uod nowych użytkowńikůw",
        "sp-contributions-newbies-sub": "Dlo nowych užytkowńikůw",
        "sp-contributions-newbies-title": "Wkłod nowych użytkowńików",
        "tooltip-pt-logout": "Uodloguj śe ze wiki",
        "tooltip-pt-createaccount": "Namawjůmy do stworzyńo kůnta a zalogůwańo śa, atoli niy je to uobowjůnzkowe",
        "tooltip-ca-talk": "Dyskusyjo uo tym artiklu",
-       "tooltip-ca-edit": "Mogesz sprowjać ta zajta. Podwjela spamjyntosz půmjyńańo, klikńij we knefel \"Uobźyrej\".",
+       "tooltip-ca-edit": "Edytuj tã zajtã",
        "tooltip-ca-addsection": "Przidej nowy temat",
        "tooltip-ca-viewsource": "Ta zajta je zawrzito. Mogesz uobźyrać zdrzůdłowy tekst.",
        "tooltip-ca-history": "Storsze wersyje tyj zajty",
        "tooltip-ca-nstab-main": "Uobźyrej zajta artikla",
        "tooltip-ca-nstab-user": "Ukoż perzůnalno zajta używocza",
        "tooltip-ca-nstab-media": "Uobejřij zajta artikla",
-       "tooltip-ca-nstab-special": "To je ekstra zajta. Ńy moges jej sprowjać.",
+       "tooltip-ca-nstab-special": "To je ekstra zajta i niy idzie jij edytować",
        "tooltip-ca-nstab-project": "Uobejřij zajta projektu",
        "tooltip-ca-nstab-image": "Ukoż zajta grafiki",
        "tooltip-ca-nstab-mediawiki": "Zoboč komunikat systymowy",
        "tooltip-ca-nstab-template": "Uobźyrej muster",
-       "tooltip-ca-nstab-help": "Pokož zajte s půmocą",
+       "tooltip-ca-nstab-help": "Pokŏż zajtã pōmocy",
        "tooltip-ca-nstab-category": "Ukoż zajta kategoryje",
        "tooltip-minoredit": "Uoznacz ta zmjana za drobno",
        "tooltip-save": "Naszkryflej půmjyńańa",
        "exif-exposureprogram-5": "kreatywny (duža guymbja uostrośći)",
        "exif-exposureprogram-6": "aktywny (dužo gibkość migawki)",
        "exif-exposureprogram-7": "tryb portretowy (do zdjyńć s bliska, s ńyuostrym tuym)",
-       "exif-exposureprogram-8": "tryb krajobrazowy (dla zdjęć wykůnywanych s dužej uodlyguośći s uostrośćům ustavjůnům na tuo)",
+       "exif-exposureprogram-8": "tryb landszaftu (dlŏ bildōw ze ôstrościōm nasztalowanōm na zadek)",
        "exif-subjectdistance-value": "$1 metrůw",
        "exif-meteringmode-0": "ńyuokryślůny",
        "exif-meteringmode-1": "średńo",
        "exif-gpsdirection-t": "kerůnek geůgrafičny",
        "exif-gpsdirection-m": "kerůnek magnetyčny",
        "namespacesall": "wszyjske",
-       "monthsall": "wšyskie",
+       "monthsall": "wszyjske",
        "confirmemail": "Potwjerdź adres e-brif",
        "confirmemail_noemail": "Ńy podoužeś prawiduowygo adresa e-brifa we [[Special:Preferences|preferencyjach]].",
        "confirmemail_text": "Projekt {{SITENAME}} wymago weryfikacyji adresa e-brif před užyćym fůnkcyji kořistajůncych s počty.\nWćiś knefel půńižy coby wysúać na swůj adres list s linkym do zajty WWW.\nList bydźe zawjeroú link do zajty, w kerym zakodowany bydźe idyntyfikator.\nUodymkńij tyn link we přyglůndarce, čym potwjerdźiš, co ježeś užytkowńikym tygo adresa e-brif.",
index 23c10a3..70141c2 100644 (file)
@@ -24,7 +24,8 @@
                        "Pphongpan355",
                        "Macofe",
                        "Pilarbini",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "B20180"
                ]
        },
        "tog-underline": "การขีดเส้นใต้ลิงก์:",
        "laggedslavemode": "<strong>คำเตือน:</strong> หน้านี้อาจไม่มีการปรับล่าสุด",
        "readonly": "ฐานข้อมูลถูกล็อก",
        "enterlockreason": "ใส่เหตุแห่งการล็อก ทั้งเวลาที่คาดว่าจะปลดล็อก",
-       "readonlytext": "à¸\82à¸\93ะà¸\99ีà¹\89à¸\90าà¸\99à¸\82à¹\89อมูลà¸\96ูà¸\81ลà¹\87อà¸\81มิà¹\83หà¹\89รัà¸\9aà¸\82à¹\89อมูลใหม่และการแก้ไขเพิ่มเติมอื่น อาจเป็นเพราะการบำรุงรักษาฐานข้อมูลรูทีน หลังแล้วเสร็จจะกลับมาใช้งานได้ตามปกติ\n\nผู้ดูแลระบบที่ล็อกได้ให้คำอธิบายดังนี้: $1",
+       "readonlytext": "à¸\82à¸\93ะà¸\99ีà¹\89à¸\90าà¸\99à¸\82à¹\89อมูลà¸\96ูà¸\81ลà¹\87อà¸\81รายà¸\81ารใหม่และการแก้ไขเพิ่มเติมอื่น อาจเป็นเพราะการบำรุงรักษาฐานข้อมูลรูทีน หลังแล้วเสร็จจะกลับมาใช้งานได้ตามปกติ\n\nผู้ดูแลระบบที่ล็อกได้ให้คำอธิบายดังนี้: $1",
        "missing-article": "ฐานข้อมูลไม่พบข้อความของหน้าที่ควรมี ชื่อ \"$1\" $2\n\nสาเหตุมักเกิดจากผลต่างที่ล้าสมัย หรือการเชื่อมโยงประวัติไปยังหน้านั้นถูกลบแล้ว\n\nหากไม่ใช่กรณีดังกล่าว คุณอาจพบจุดบกพร่องในซอฟต์แวร์ กรุณารายงานต่อ[[Special:ListUsers/sysop|ผู้ดูแลระบบ]] พร้อมระบุยูอาร์แอล",
        "missingarticle-rev": "(รุ่นปรับปรุง#: $1)",
        "missingarticle-diff": "(ต่าง: $1, $2)",
        "protectedinterface": "หน้านี้เป็นข้อความส่วนต่อประสานสำหรับซอฟต์แวร์บนวิกินี้ และถูกล็อกเพื่อป้องกันการกระทำผิด\nในการเพิ่มหรือเปลี่ยนแปลงการแปลสำหรับทุกวิกิ โปรดใช้ [https://translatewiki.net/ translatewiki.net] โครงการแปลมีเดียวิกิเป็นภาษาถิ่น",
        "editinginterface": "<strong>คำเตือน:</strong> คุณกำลังแก้ไขหน้าที่ใช้จัดหาข้อความอินเตอร์เฟซให้ซอฟต์แวร์\nการเปลี่ยนแปลงหน้านี้จะมีผลต่อสภาพปรากฏของส่วนต่อประสานผู้ใช้แก่ผู้ใช้อื่นบนวิกินี้",
        "translateinterface": "ในการเพิ่มหรือเปลี่ยนแปลงคำแปลสำหรับทุกวิกิ โปรดใช้ [https://translatewiki.net/ translatewiki.net] โครงการแปลเป็นภาษาถิ่นของมีเดียวิกิ",
-       "cascadeprotected": "หน้านี้ถูกป้องกันมิให้แก้ไข เพราะถูกรวมอยู่ในหน้าต่อไปนี้ซึ่งถูกล็อกโดยเปิดตัวเลือก \"ต่อเรียง\":\n$2",
+       "cascadeprotected": "หน้านี้ถูกป้องกันมิให้แก้ไข เพราะถูกรวมอยู่ใน{{PLURAL:$1|page, which is|หน้าต่อไปนี้}} ซึ่งถูกล็อกโดยเปิดตัวเลือก \"ต่อเรียง\":\n$2",
        "namespaceprotected": "คุณไม่มีสิทธิแก้ไขหน้าในเนมสเปซ <strong>$1</strong>",
        "customcssprotected": "คุณไม่มีสิทธิแก้ไขหน้า CSS นี้ เพราะมีการตั้งค่าส่วนบุคคลของผู้ใช้อื่น",
        "customjsprotected": "คุณไม่มีสิทธิแก้ไขหน้าจาวาสคริปต์นี้ เพราะหน้านี้มีการตั้งค่าส่วนบุคคลของผู้ใช้อื่น",
        "special-characters-group-bangla": "บังคลา",
        "special-characters-group-telugu": "เตลูกู",
        "special-characters-group-sinhala": "สิงหล",
-       "special-characters-group-gujarati": "คุชราต",
-       "api-error-blacklisted": "โปรดใช้ชื่ออื่นที่สื่อความหมาย"
+       "special-characters-group-gujarati": "คุชราต"
 }
index f0128f9..128db0e 100644 (file)
        "prefs-namespaces": "Исемнәр мәйданы",
        "default": "килешү буенча",
        "prefs-files": "Файллар",
-       "prefs-custom-css": "Үземнең CSS",
-       "prefs-custom-js": "Үземнең JS",
+       "prefs-custom-css": "Шәхси CSS",
+       "prefs-custom-js": "Шәхси JS",
        "prefs-common-css-js": "Барлык бизәлешләр өчен гомуми CSS/JS:",
        "prefs-reset-intro": "Бу бит сезнең көйләнмәләрегезне бетерү өчен кулланыла. Бу эшне башкару нәтиҗәсендә сез яңадан үз көйләнмәләрне яңадан кайтара алмыйсыз.",
        "prefs-emailconfirm-label": "E-mail раслау",
index 0b6fc8a..45a58d2 100644 (file)
        "action-applychangetags": "додавання міток разом зі змінами",
        "action-changetags": "додавання або вилучення будь-яких міток для певних версій сторінок або записів журналів",
        "action-deletechangetags": "вилучення міток з бази даних",
+       "action-purge": "очищення кешу цієї сторінки",
        "nchanges": "$1 {{PLURAL:$1|зміна|зміни|змін}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|зміна з останнього візиту|зміни з останнього візиту|змін з останнього візиту}}",
        "enhancedrc-history": "історія",
        "watchnologin": "Ви не увійшли до системи",
        "addwatch": "Додати до списку спостереження",
        "addedwatchtext": "«[[:$1]]» та її сторінка обговорення додані до вашого [[Special:Watchlist|списку спостереження]].",
+       "addedwatchtext-talk": "«[[:$1]]» та пов'язану з нею сторінку додано до Вашого [[Special:Watchlist|списку спостереження]].",
        "addedwatchtext-short": "Сторінка \" $1 \" була додана до вашого списку спостереження.",
        "removewatch": "Видалити зі списку спостереження",
        "removedwatchtext": "«[[:$1]]» та її сторінка обговорення вилучені з Вашого [[Special:Watchlist|списку спостереження]].",
+       "removedwatchtext-talk": "«[[:$1]]» та пов'язану з нею сторінку вилучено з Вашого [[Special:Watchlist|списку спостереження]].",
        "removedwatchtext-short": "Сторінка \"$1\" була видалена із вашого списку спостереження.",
        "watch": "Спостерігати",
        "watchthispage": "Спостерігати за цією сторінкою",
        "unblockip": "Розблокувати IP-адресу",
        "unblockiptext": "Використовуйте подану нижче форму, щоб відновити можливість збереження з раніше заблокованої IP-адреси.",
        "ipusubmit": "Зняти це блокування",
-       "unblocked": "[[User:$1|$1]] {{GENDER:$1|розблокований|розблокована}}",
-       "unblocked-range": "$1 розблоковано",
-       "unblocked-id": "Блокування $1 було зняте",
-       "unblocked-ip": "[[Special:Contributions/$1|$1]] вже розлоковано.",
+       "unblocked": "[[User:$1|$1]] {{GENDER:$1|розблокований|розблокована}}.",
+       "unblocked-range": "$1 розблоковано.",
+       "unblocked-id": "Блокування $1 було зняте.",
+       "unblocked-ip": "[[Special:Contributions/$1|$1]] розблоковано.",
        "blocklist": "Заблоковані користувачі",
        "ipblocklist": "Список заблокованих адрес та користувачів",
        "ipblocklist-legend": "Пошук заблокованого користувача",
index 1897e60..b00ef27 100644 (file)
        "specialpages": "خصوصی صفحات",
        "specialpages-group-pages": "فہارست صفحات",
        "tag-filter": "[[Special:Tags|لوحہ]] فلٹر:",
-       "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|ٹیگ|ٹیگز}}]]: $2)",
+       "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|ٹیگ|ٹیگ}}]]: $2)",
        "tags-source-header": "ماخذ",
        "tags-active-header": "فعال؟",
        "tags-active-yes": "ہاں",
index d807319..036c3e3 100644 (file)
        "log-action-filter-upload": "טיפ ארויפֿלאד:",
        "log-action-filter-all": "אַלע",
        "log-action-filter-delete-delete": "אויסמעקן בלאט",
+       "log-action-filter-import-interwiki": "אריבערוויקי אימפארט",
        "log-action-filter-protect-unprotect": "אראפנעמען שיץ"
 }
index edd63ec..0beedc7 100644 (file)
        "tagline": "来自{{SITENAME}}",
        "help": "帮助",
        "search": "搜索",
-       "search-ignored-headings": " #<!-- è¯·å°\86æ\9c¬è¡\8cä¿\9dæ\8c\81å\8e\9fæ · --> <pre>\n# ä¼\9a被æ\90\9c索忽ç\95¥ç\9a\84æ \87é¢\98ã\80\82\n# å¯¹è¯¥è¡¨ç\9a\84æ\9b´æ\94¹ä¼\9aå\9c¨è¡¨ä¸­æ \87é¢\98ç\9a\84页é\9d¢è¢«ç´¢å¼\95æ\97¶ç\94\9fæ\95\88ã\80\82\n# ä½ å\8f¯ä»¥é\80\9aè¿\87空ç¼\96è¾\91强å\88¶ä½¿é¡µé\9d¢è¢«é\87\8dæ\96°ç´¢å¼\95ã\80\82\n# è¯­æ³\95å¦\82ä¸\8bï¼\9a\n#   * æ\89\80æ\9c\89以â\80\9c\80\9då¼\80头ç\9a\84è¡\8cé\83½æ\98¯æ³¨é\87\8aã\80\82\n#   * æ\89\80æ\9c\89é\9d\9e空ç\99½è¡\8cå°±æ\98¯è¦\81忽ç\95¥ç\9a\84æ \87é¢\98ã\80\82\nå\8f\82è\80\83èµ\84æ\96\99\nå¤\96é\83¨é\93¾æ\8e¥\nå\8f¦è¯·å\8f\82é\98\85\n #</pre> <!-- è¯·å°\86æ\9c¬行保持原样 -->",
+       "search-ignored-headings": " #<!-- è¯·å°\86æ­¤è¡\8cä¿\9dæ\8c\81å\8e\9fæ · --> <pre>\n# å°\86被æ\90\9c索忽ç\95¥ç\9a\84æ \87é¢\98ã\80\82\n# å¯¹æ­¤é¡µé\9d¢ç\9a\84æ\9b´æ\94¹ä¼\9aå\9c¨å¸¦æ \87é¢\98ç\9a\84页é\9d¢è¢«ç´¢å¼\95æ\97¶äº§ç\94\9få½±å\93\8dã\80\82\n# æ\82¨å\8f¯ä»¥é\80\9aè¿\87è¿\9bè¡\8c空ç¼\96è¾\91æ\9d¥å¼ºå\88¶é¡µé\9d¢é\87\8dæ\96°ç´¢å¼\95ã\80\82\n# è¯­æ³\95å¦\82ä¸\8bï¼\9a\n#  * æ\89\80æ\9c\89以â\80\9c\80\9då¼\80头ç\9a\84è¡\8cé\83½æ\98¯æ³¨é\87\8aã\80\82\n#  * æ\89\80æ\9c\89é\9d\9e空ç\99½è¡\8cé\83½æ\98¯è¦\81忽ç\95¥ç\9a\84æ \87é¢\98ã\80\82\nå\8f\82è\80\83æ\96\87ç\8c®\nå¤\96é\83¨é\93¾æ\8e¥\nå\8f\82è§\81\n #</pre> <!-- è¯·å°\86æ­¤行保持原样 -->",
        "searchbutton": "搜索",
        "go": "前往",
        "searcharticle": "前往",
        "watchnologin": "未登录",
        "addwatch": "添加至监视列表",
        "addedwatchtext": "“[[:$1]]”及其讨论页已加入至您的[[Special:Watchlist|监视列表]]中。",
+       "addedwatchtext-talk": "“[[:$1]]”及其相关联页面已加入至您的[[Special:Watchlist|监视列表]]中。",
        "addedwatchtext-short": "页面“$1”已加入您的监视列表。",
        "removewatch": "从监视列表中删除",
        "removedwatchtext": "“[[:$1]]”及其讨论页已从您的[[Special:Watchlist|监视列表]]中移除。",
+       "removedwatchtext-talk": "“[[:$1]]”及其相关联页面已从您的[[Special:Watchlist|监视列表]]中移除。",
        "removedwatchtext-short": "页面“$1”已从您的监视列表移除。",
        "watch": "监视",
        "watchthispage": "监视本页",
index a550d12..9fa6632 100644 (file)
@@ -41,8 +41,6 @@ class ChangePassword extends Maintenance {
        }
 
        public function execute() {
-               global $wgDisableAuthManager;
-
                if ( $this->hasOption( "user" ) ) {
                        $user = User::newFromName( $this->getOption( 'user' ) );
                } elseif ( $this->hasOption( "userid" ) ) {
@@ -55,17 +53,13 @@ class ChangePassword extends Maintenance {
                }
                $password = $this->getOption( 'password' );
                try {
-                       if ( $wgDisableAuthManager ) {
-                               $user->setPassword( $password );
-                       } else {
-                               $status = $user->changeAuthenticationData( [
-                                       'username' => $user->getName(),
-                                       'password' => $password,
-                                       'retype' => $password,
-                               ] );
-                               if ( !$status->isGood() ) {
-                                       throw new PasswordError( $status->getWikiText( null, null, 'en' ) );
-                               }
+                       $status = $user->changeAuthenticationData( [
+                               'username' => $user->getName(),
+                               'password' => $password,
+                               'retype' => $password,
+                       ] );
+                       if ( !$status->isGood() ) {
+                               throw new PasswordError( $status->getWikiText( null, null, 'en' ) );
                        }
                        $user->saveSettings();
                        $this->output( "Password set for " . $user->getName() . "\n" );
index 6d2a0e9..e83d7c6 100644 (file)
@@ -230,6 +230,13 @@ class ConvertExtensionToRegistration extends Maintenance {
 
        public function handleHooks( $realName, $value ) {
                foreach ( $value as $hookName => &$handlers ) {
+                       if ( $hookName === 'UnitTestsList' ) {
+                               $this->output( "Note: the UnitTestsList hook is no longer necessary as " .
+                                       "long as your tests are located in the \"tests/phpunit/\" directory. " .
+                                       "Please see <https://www.mediawiki.org/wiki/Manual:PHP_unit_testing/" .
+                                       "Writing_unit_tests_for_extensions#Register_your_tests> for more details.\n"
+                               );
+                       }
                        foreach ( $handlers as $func ) {
                                if ( $func instanceof Closure ) {
                                        $this->error( "Error: Closures cannot be converted to JSON. " .
index 3591b9c..1872716 100644 (file)
@@ -56,8 +56,6 @@ class CreateAndPromote extends Maintenance {
        }
 
        public function execute() {
-               global $wgDisableAuthManager;
-
                $username = $this->getArg( 0 );
                $password = $this->getArg( 1 );
                $force = $this->hasOption( 'force' );
@@ -122,17 +120,13 @@ class CreateAndPromote extends Maintenance {
                if ( $password ) {
                        # Try to set the password
                        try {
-                               if ( $wgDisableAuthManager ) {
-                                       $user->setPassword( $password );
-                               } else {
-                                       $status = $user->changeAuthenticationData( [
-                                               'username' => $user->getName(),
-                                               'password' => $password,
-                                               'retype' => $password,
-                                       ] );
-                                       if ( !$status->isGood() ) {
-                                               throw new PasswordError( $status->getWikiText( null, null, 'en' ) );
-                                       }
+                               $status = $user->changeAuthenticationData( [
+                                       'username' => $user->getName(),
+                                       'password' => $password,
+                                       'retype' => $password,
+                               ] );
+                               if ( !$status->isGood() ) {
+                                       throw new PasswordError( $status->getWikiText( null, null, 'en' ) );
                                }
                                if ( $exists ) {
                                        $this->output( "Password set.\n" );
index 780e049..3b75c3a 100644 (file)
     "grunt-jscs": "2.8.0",
     "grunt-jsonlint": "1.0.7",
     "grunt-karma": "2.0.0",
-    "grunt-stylelint": "0.4.0",
+    "grunt-stylelint": "0.6.0",
     "karma": "1.1.0",
     "karma-chrome-launcher": "1.0.1",
     "karma-firefox-launcher": "1.0.0",
     "karma-qunit": "1.0.0",
     "qunitjs": "1.22.0",
-    "stylelint-config-wikimedia": "0.2.2"
+    "stylelint-config-wikimedia": "0.3.0"
   }
 }
index 1558ee6..053c3f3 100644 (file)
@@ -923,6 +923,7 @@ return [
                        'mediawiki.api.edit',
                        'json',
                ],
+               'targets' => [ 'desktop', 'mobile' ],
        ],
        'mediawiki.api.user' => [
                'scripts' => 'resources/src/mediawiki/api/user.js',
@@ -1412,6 +1413,7 @@ return [
                'class' => 'ResourceLoaderEditToolbarModule',
                'scripts' => 'resources/src/mediawiki.toolbar/toolbar.js',
                'styles' => 'resources/src/mediawiki.toolbar/toolbar.less',
+               'dependencies' => 'jquery.textSelection',
                'position' => 'top',
        ],
        'mediawiki.experiments' => [
@@ -1705,6 +1707,14 @@ return [
                'position' => 'top',
                'targets' => [ 'desktop', 'mobile' ],
        ],
+       'mediawiki.page.patrol' => [
+               'position' => 'top',
+               'styles' => [
+                       'resources/src/mediawiki/page/mediawiki.page.patrol.css',
+                       'resources/src/mediawiki/page/mediawiki.page.patrol.print.css'
+                               => [ 'media' => 'print' ],
+               ]
+       ],
        'mediawiki.page.patrol.ajax' => [
                'scripts' => 'resources/src/mediawiki/page/patrol.ajax.js',
                'dependencies' => [
index 50bfa87..62be0d8 100644 (file)
                        for ( key in ts.collationTable ) {
                                // Check hasOwn to be safe
                                if ( ts.collationTable.hasOwnProperty( key ) ) {
-                                       keys.push( key );
+                                       keys.push( mw.RegExp.escape( key ) );
                                }
                        }
                        if ( keys.length ) {
-                               ts.collationRegex = new RegExp( '[' + keys.join( '' ) + ']', 'ig' );
+                               ts.collationRegex = new RegExp( keys.join( '|' ), 'ig' );
                        }
                }
        }
index 4209aa1..0ee4058 100644 (file)
 .editButtons input:first-child {
        margin-left: .1em;
 }
+
+/*
+ * Add a bit of margin space between the preview and the toolbar.
+ * This replaces the ugly <p><br /></p> we used to insert into the page source
+ */
+#wikiPreview.ontop {
+       margin-bottom: 1em;
+}
index d387a2d..6a7c76a 100644 (file)
@@ -19,7 +19,6 @@ div#column-one,
 #footer-places,
 .mw-hidden-catlinks,
 .usermessage,
-.patrollink,
 .ns-0 .mw-redirectedfrom,
 div.magnify,
 #mw-navigation,
index 7ccf59e..786f53d 100644 (file)
@@ -289,11 +289,6 @@ table.small {
        font-style: italic;
 }
 
-span.unpatrolled {
-       font-weight: bold;
-       color: #f00;
-}
-
 div.gallerybox {
        width: 150px;
 }
index 8fcc667..38d2a27 100644 (file)
@@ -98,14 +98,6 @@ span.comment {
        unicode-bidi: isolate;
 }
 
-/**
- * Add a bit of margin space between the preview and the toolbar.
- * This replaces the ugly <p><br /></p> we used to insert into the page source
- */
-#wikiPreview.ontop {
-       margin-bottom: 1em;
-}
-
 /* Stop floats from intruding into edit area in previews */
 #editform,
 #toolbar,
@@ -123,23 +115,6 @@ span.history-deleted {
        font-style: italic;
 }
 
-/**
- * Patrol stuff
- */
-.not-patrolled {
-       background-color: #ffa;
-}
-
-.unpatrolled {
-       font-weight: bold;
-       color: #f00;
-}
-
-div.patrollink {
-       font-size: 75%;
-       text-align: right;
-}
-
 /**
  * Forms
  */
index f2019e7..4b8eced 100644 (file)
@@ -115,9 +115,3 @@ table.mw-userrights-groups * td,
 table.mw-userrights-groups * th {
        padding-right: 1.5em;
 }
-
-/* Special:Upload */
-p.mw-upload-editlicenses {
-       font-size: 90%;
-       text-align: right;
-}
index b916248..283df85 100644 (file)
@@ -8,3 +8,8 @@
        color: #705000;
        background-color: #fdf1d1;
 }
+
+p.mw-upload-editlicenses {
+       font-size: 90%;
+       text-align: right;
+}
diff --git a/resources/src/mediawiki/page/mediawiki.page.patrol.css b/resources/src/mediawiki/page/mediawiki.page.patrol.css
new file mode 100644 (file)
index 0000000..f237dbd
--- /dev/null
@@ -0,0 +1,13 @@
+.not-patrolled {
+       background-color: #ffa;
+}
+
+.unpatrolled {
+       font-weight: bold;
+       color: #f00;
+}
+
+.patrollink {
+       font-size: 75%;
+       text-align: right;
+}
diff --git a/resources/src/mediawiki/page/mediawiki.page.patrol.print.css b/resources/src/mediawiki/page/mediawiki.page.patrol.print.css
new file mode 100644 (file)
index 0000000..497bceb
--- /dev/null
@@ -0,0 +1,3 @@
+.patrollink {
+       display: none;
+}
index 917a6ad..487ab84 100644 (file)
@@ -13,8 +13,6 @@ class ApiLoginTest extends ApiTestCase {
         * Test result of attempted login with an empty username
         */
        public function testApiLoginNoName() {
-               global $wgDisableAuthManager;
-
                $session = [
                        'wsTokenSecrets' => [ 'login' => 'foobar' ],
                ];
@@ -22,11 +20,11 @@ class ApiLoginTest extends ApiTestCase {
                        'lgname' => '', 'lgpassword' => self::$users['sysop']->getPassword(),
                        'lgtoken' => (string)( new MediaWiki\Session\Token( 'foobar', '' ) )
                ], $session );
-               $this->assertEquals( $wgDisableAuthManager ? 'NoName' : 'Failed', $data[0]['login']['result'] );
+               $this->assertEquals( 'Failed', $data[0]['login']['result'] );
        }
 
        public function testApiLoginBadPass() {
-               global $wgServer, $wgDisableAuthManager;
+               global $wgServer;
 
                $user = self::$users['sysop'];
                $userName = $user->getUser()->getName();
@@ -64,7 +62,7 @@ class ApiLoginTest extends ApiTestCase {
                $this->assertNotInternalType( "bool", $result );
                $a = $result["login"]["result"];
 
-               $this->assertEquals( $wgDisableAuthManager ? 'WrongPass' : 'Failed', $a );
+               $this->assertEquals( 'Failed', $a );
        }
 
        public function testApiLoginGoodPass() {
@@ -190,6 +188,7 @@ class ApiLoginTest extends ApiTestCase {
                $this->assertArrayHasKey( "login", $data[0] );
                $this->assertArrayHasKey( "result", $data[0]['login'] );
                $this->assertEquals( "Success", $data[0]['login']['result'] );
+               $this->assertArrayHasKey( 'lgtoken', $data[0]['login'] );
        }
 
        public function testBotPassword() {
index ac4d2c9..7e1f9d8 100644 (file)
@@ -9,7 +9,7 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
        protected $apiContext;
 
        protected function setUp() {
-               global $wgServer, $wgDisableAuthManager;
+               global $wgServer;
 
                parent::setUp();
                self::$apiUrl = $wgServer . wfScript( 'api' );
@@ -22,7 +22,7 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
                ];
 
                $this->setMwGlobals( [
-                       'wgAuth' => $wgDisableAuthManager ? new AuthPlugin : new MediaWiki\Auth\AuthManagerAuthPlugin,
+                       'wgAuth' => new MediaWiki\Auth\AuthManagerAuthPlugin,
                        'wgRequest' => new FauxRequest( [] ),
                        'wgUser' => self::$users['sysop']->getUser(),
                ] );
index 1ded0df..89e48f7 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AbstractAuthenticationProvider
  */
 class AbstractAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testAbstractAuthenticationProvider() {
                $provider = $this->getMockForAbstractClass( AbstractAuthenticationProvider::class );
                $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
index ecce932..a1cdf7e 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AbstractPasswordPrimaryAuthenticationProvider
  */
 class AbstractPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testConstructor() {
                $provider = $this->getMockForAbstractClass(
                        AbstractPasswordPrimaryAuthenticationProvider::class
index c35430e..9638451 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AbstractPreAuthenticationProvider
  */
 class AbstractPreAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testAbstractPreAuthenticationProvider() {
                $user = \User::newFromName( 'UTSysop' );
 
index 420a330..d8588d5 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AbstractPrimaryAuthenticationProvider
  */
 class AbstractPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testAbstractPrimaryAuthenticationProvider() {
                $user = \User::newFromName( 'UTSysop' );
 
index 9cdc051..bb90dd9 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AbstractSecondaryAuthenticationProvider
  */
 class AbstractSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testAbstractSecondaryAuthenticationProvider() {
                $user = \User::newFromName( 'UTSysop' );
 
index 82608b0..99b9029 100644 (file)
@@ -30,12 +30,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
        protected $managerPriv;
 
        protected function setUp() {
-               global $wgDisableAuthManager;
-
                parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
 
                $this->setMwGlobals( [ 'wgAuth' => null ] );
                $this->stashMwGlobals( [ 'wgHooks' ] );
@@ -200,14 +195,6 @@ class AuthManagerTest extends \MediaWikiTestCase {
                        \RequestContext::getMain()->getConfig(),
                        \TestingAccessWrapper::newFromObject( $singleton )->config
                );
-
-               $this->setMwGlobals( [ 'wgDisableAuthManager' => true ] );
-               try {
-                       AuthManager::singleton();
-                       $this->fail( 'Expected exception not thrown' );
-               } catch ( \BadMethodCallException $ex ) {
-                       $this->assertSame( '$wgDisableAuthManager is set', $ex->getMessage() );
-               }
        }
 
        public function testCanAuthenticateNow() {
index 44f2743..96e50e0 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AuthPluginPrimaryAuthenticationProvider
  */
 class AuthPluginPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testConstruction() {
                $plugin = new AuthManagerAuthPlugin();
                try {
index cac031c..a7df221 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AuthenticationRequest
  */
 class AuthenticationRequestTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testBasics() {
                $mock = $this->getMockForAbstractClass( AuthenticationRequest::class );
 
index aafcd09..aa0e3c7 100644 (file)
@@ -6,15 +6,6 @@ namespace MediaWiki\Auth;
  * @group AuthManager
  */
 abstract class AuthenticationRequestTestCase extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        abstract protected function getInstance( array $args = [] );
 
        /**
index 58ff8b6..477b161 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\AuthenticationResponse
  */
 class AuthenticationResponseTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        /**
         * @dataProvider provideConstructors
         * @param string $constructor
index f2341bc..e6d3ecf 100644 (file)
@@ -8,15 +8,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\CheckBlocksSecondaryAuthenticationProvider
  */
 class CheckBlocksSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testConstructor() {
                $provider = new CheckBlocksSecondaryAuthenticationProvider();
                $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
index 580ef6c..3fc45a4 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\ConfirmLinkSecondaryAuthenticationProvider
  */
 class ConfirmLinkSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        /**
         * @dataProvider provideGetAuthenticationRequests
         * @param string $action
index 3548002..d482453 100644 (file)
@@ -8,15 +8,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\LegacyHookPreAuthenticationProvider
  */
 class LegacyHookPreAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        /**
         * Get an instance of the provider
         * @return LegacyHookPreAuthenticationProvider
index 713c27e..088dd00 100644 (file)
@@ -13,15 +13,6 @@ class LocalPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestCase
        private $config = null;
        private $validity = null;
 
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        /**
         * Get an instance of the provider
         *
index 79c138b..90ed542 100644 (file)
@@ -7,15 +7,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider
  */
 class ResetPasswordSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        /**
         * @dataProvider provideGetAuthenticationRequests
         * @param string $action
index 8d0bf96..515a5b3 100644 (file)
@@ -13,15 +13,6 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestC
        private $config = null;
        private $validity = null;
 
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        /**
         * Get an instance of the provider
         *
index 8b273b5..aa6f0e8 100644 (file)
@@ -8,15 +8,6 @@ namespace MediaWiki\Auth;
  * @covers MediaWiki\Auth\ThrottlePreAuthenticationProvider
  */
 class ThrottlePreAuthenticationProviderTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testConstructor() {
                $provider = new ThrottlePreAuthenticationProvider();
                $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
index dba748b..5806003 100644 (file)
@@ -14,15 +14,6 @@ use Psr\Log\NullLogger;
  * @covers MediaWiki\Auth\Throttler
  */
 class ThrottlerTest extends \MediaWikiTestCase {
-       protected function setUp() {
-               global $wgDisableAuthManager;
-
-               parent::setUp();
-               if ( $wgDisableAuthManager ) {
-                       $this->markTestSkipped( '$wgDisableAuthManager is set' );
-               }
-       }
-
        public function testConstructor() {
                $cache = new \HashBagOStuff();
                $logger = $this->getMockBuilder( AbstractLogger::class )
index e216ced..2114e0a 100644 (file)
@@ -123,7 +123,7 @@ class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
 
        /**
         * @dataProvider providerDeprecatedModules
-        * @covers ResourceLoaderFileModule::getScripts
+        * @covers ResourceLoaderFileModule::getScript
         */
        public function testDeprecatedModules( $name, $expected ) {
                $modules = self::getModules();
index e725fee..1ebb07c 100644 (file)
@@ -867,303 +867,6 @@ class SessionManagerTest extends MediaWikiTestCase {
                $this->assertTrue( SessionManager::validateSessionId( $id ), "Generated ID: $id" );
        }
 
-       public function testAutoCreateUser() {
-               global $wgGroupPermissions, $wgDisableAuthManager;
-
-               if ( !$wgDisableAuthManager ) {
-                       $this->markTestSkipped( 'AuthManager is not disabled' );
-               }
-
-               \ObjectCache::$instances[__METHOD__] = new TestBagOStuff();
-               $this->setMwGlobals( [ 'wgMainCacheType' => __METHOD__ ] );
-               $this->setMwGlobals( [
-                       'wgAuth' => new AuthPlugin,
-               ] );
-
-               $this->stashMwGlobals( [ 'wgGroupPermissions' ] );
-               $wgGroupPermissions['*']['createaccount'] = true;
-               $wgGroupPermissions['*']['autocreateaccount'] = false;
-
-               // Replace the global singleton with one configured for testing
-               $manager = $this->getManager();
-               $reset = TestUtils::setSessionManagerSingleton( $manager );
-
-               $logger = new \TestLogger( true, function ( $m ) {
-                       if ( substr( $m, 0, 15 ) === 'SessionBackend ' ) {
-                               // Don't care.
-                               return null;
-                       }
-                       $m = str_replace( 'MediaWiki\Session\SessionManager::autoCreateUser: ', '', $m );
-                       return $m;
-               } );
-               $manager->setLogger( $logger );
-
-               $session = SessionManager::getGlobalSession();
-
-               // Can't create an already-existing user
-               $user = User::newFromName( 'UTSysop' );
-               $id = $user->getId();
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( $id, $user->getId() );
-               $this->assertSame( 'UTSysop', $user->getName() );
-               $this->assertSame( [], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Sanity check that creation works at all
-               $user = User::newFromName( 'UTSessionAutoCreate1' );
-               $this->assertSame( 0, $user->getId(), 'sanity check' );
-               $this->assertTrue( $manager->autoCreateUser( $user ) );
-               $this->assertNotEquals( 0, $user->getId() );
-               $this->assertSame( 'UTSessionAutoCreate1', $user->getName() );
-               $this->assertEquals(
-                       $user->getId(), User::idFromName( 'UTSessionAutoCreate1', User::READ_LATEST )
-               );
-               $this->assertSame( [
-                       [ LogLevel::INFO, 'creating new user ({username}) - from: {url}' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Check lack of permissions
-               $wgGroupPermissions['*']['createaccount'] = false;
-               $wgGroupPermissions['*']['autocreateaccount'] = false;
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $session->clear();
-               $this->assertSame( [
-                       [
-                               LogLevel::DEBUG,
-                               'user is blocked from this wiki, blacklisting',
-                       ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Check other permission
-               $wgGroupPermissions['*']['createaccount'] = false;
-               $wgGroupPermissions['*']['autocreateaccount'] = true;
-               $user = User::newFromName( 'UTSessionAutoCreate2' );
-               $this->assertSame( 0, $user->getId(), 'sanity check' );
-               $this->assertTrue( $manager->autoCreateUser( $user ) );
-               $this->assertNotEquals( 0, $user->getId() );
-               $this->assertSame( 'UTSessionAutoCreate2', $user->getName() );
-               $this->assertEquals(
-                       $user->getId(), User::idFromName( 'UTSessionAutoCreate2', User::READ_LATEST )
-               );
-               $this->assertSame( [
-                       [ LogLevel::INFO, 'creating new user ({username}) - from: {url}' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test account-creation block
-               $anon = new User;
-               $block = new \Block( [
-                       'address' => $anon->getName(),
-                       'user' => $id,
-                       'reason' => __METHOD__,
-                       'expiry' => time() + 100500,
-                       'createAccount' => true,
-               ] );
-               $block->insert();
-               $this->assertInstanceOf( 'Block', $anon->isBlockedFromCreateAccount(), 'sanity check' );
-               $reset2 = new \ScopedCallback( [ $block, 'delete' ] );
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               \ScopedCallback::consume( $reset2 );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'user is blocked from this wiki, blacklisting' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Sanity check that creation still works
-               $user = User::newFromName( 'UTSessionAutoCreate3' );
-               $this->assertSame( 0, $user->getId(), 'sanity check' );
-               $this->assertTrue( $manager->autoCreateUser( $user ) );
-               $this->assertNotEquals( 0, $user->getId() );
-               $this->assertSame( 'UTSessionAutoCreate3', $user->getName() );
-               $this->assertEquals(
-                       $user->getId(), User::idFromName( 'UTSessionAutoCreate3', User::READ_LATEST )
-               );
-               $this->assertSame( [
-                       [ LogLevel::INFO, 'creating new user ({username}) - from: {url}' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test prevention by AuthPlugin
-               global $wgAuth;
-               $oldWgAuth = $wgAuth;
-               $mockWgAuth = $this->getMock( 'AuthPlugin', [ 'autoCreate' ] );
-               $mockWgAuth->expects( $this->once() )->method( 'autoCreate' )
-                       ->will( $this->returnValue( false ) );
-               $this->setMwGlobals( [
-                       'wgAuth' => $mockWgAuth,
-               ] );
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $this->setMwGlobals( [
-                       'wgAuth' => $oldWgAuth,
-               ] );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'denied by AuthPlugin' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test prevention by wfReadOnly()
-               $this->setMwGlobals( [
-                       'wgReadOnly' => 'Because',
-               ] );
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $this->setMwGlobals( [
-                       'wgReadOnly' => false,
-               ] );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'denied by wfReadOnly()' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test prevention by a previous session
-               $session->set( 'MWSession::AutoCreateBlacklist', 'test' );
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'blacklisted in session (test)' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test uncreatable name
-               $user = User::newFromName( 'UTDoesNotExist@' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist@', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'Invalid username, blacklisting' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test AbortAutoAccount hook
-               $mock = $this->getMock( __CLASS__, [ 'onAbortAutoAccount' ] );
-               $mock->expects( $this->once() )->method( 'onAbortAutoAccount' )
-                       ->will( $this->returnCallback( function ( User $user, &$msg ) {
-                               $msg = 'No way!';
-                               return false;
-                       } ) );
-               $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'AbortAutoAccount' => [ $mock ] ] );
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'AbortAutoAccount' => [] ] );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'denied by hook: No way!' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test AbortAutoAccount hook screwing up the name
-               $mock = $this->getMock( 'stdClass', [ 'onAbortAutoAccount' ] );
-               $mock->expects( $this->once() )->method( 'onAbortAutoAccount' )
-                       ->will( $this->returnCallback( function ( User $user ) {
-                               $user->setName( 'UTDoesNotExistEither' );
-                       } ) );
-               $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'AbortAutoAccount' => [ $mock ] ] );
-               try {
-                       $user = User::newFromName( 'UTDoesNotExist' );
-                       $manager->autoCreateUser( $user );
-                       $this->fail( 'Expected exception not thrown' );
-               } catch ( \UnexpectedValueException $ex ) {
-                       $this->assertSame(
-                               'AbortAutoAccount hook tried to change the user name',
-                               $ex->getMessage()
-                       );
-               }
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertNotSame( 'UTDoesNotExistEither', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExistEither', User::READ_LATEST ) );
-               $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'AbortAutoAccount' => [] ] );
-               $session->clear();
-               $this->assertSame( [], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Test for "exception backoff"
-               $user = User::newFromName( 'UTDoesNotExist' );
-               $cache = \ObjectCache::getLocalClusterInstance();
-               $backoffKey = wfMemcKey( 'MWSession', 'autocreate-failed', md5( $user->getName() ) );
-               $cache->set( $backoffKey, 1, 60 * 10 );
-               $this->assertFalse( $manager->autoCreateUser( $user ) );
-               $this->assertSame( 0, $user->getId() );
-               $this->assertNotSame( 'UTDoesNotExist', $user->getName() );
-               $this->assertEquals( 0, User::idFromName( 'UTDoesNotExist', User::READ_LATEST ) );
-               $cache->delete( $backoffKey );
-               $session->clear();
-               $this->assertSame( [
-                       [ LogLevel::DEBUG, 'denied by prior creation attempt failures' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-
-               // Sanity check that creation still works, and test completion hook
-               $cb = $this->callback( function ( User $user ) {
-                       $this->assertNotEquals( 0, $user->getId() );
-                       $this->assertSame( 'UTSessionAutoCreate4', $user->getName() );
-                       $this->assertEquals(
-                               $user->getId(), User::idFromName( 'UTSessionAutoCreate4', User::READ_LATEST )
-                       );
-                       return true;
-               } );
-               $mock = $this->getMock( 'stdClass',
-                       [ 'onAuthPluginAutoCreate', 'onLocalUserCreated' ] );
-               $mock->expects( $this->once() )->method( 'onAuthPluginAutoCreate' )
-                       ->with( $cb );
-               $mock->expects( $this->once() )->method( 'onLocalUserCreated' )
-                       ->with( $cb, $this->identicalTo( true ) );
-               $this->mergeMwGlobalArrayValue( 'wgHooks', [
-                       'AuthPluginAutoCreate' => [ $mock ],
-                       'LocalUserCreated' => [ $mock ],
-               ] );
-               $user = User::newFromName( 'UTSessionAutoCreate4' );
-               $this->assertSame( 0, $user->getId(), 'sanity check' );
-               $this->assertTrue( $manager->autoCreateUser( $user ) );
-               $this->assertNotEquals( 0, $user->getId() );
-               $this->assertSame( 'UTSessionAutoCreate4', $user->getName() );
-               $this->assertEquals(
-                       $user->getId(),
-                       User::idFromName( 'UTSessionAutoCreate4', User::READ_LATEST )
-               );
-               $this->mergeMwGlobalArrayValue( 'wgHooks', [
-                       'AuthPluginAutoCreate' => [],
-                       'LocalUserCreated' => [],
-               ] );
-               $this->assertSame( [
-                       [ LogLevel::INFO, 'creating new user ({username}) - from: {url}' ],
-               ], $logger->getBuffer() );
-               $logger->clearBuffer();
-       }
-
-       public function onAbortAutoAccount( User $user, &$msg ) {
-       }
-
        public function testPreventSessionsForUser() {
                $manager = $this->getManager();
 
index beb5e78..bd076ba 100644 (file)
@@ -212,7 +212,7 @@ class UserTest extends MediaWikiTestCase {
         * @group medium
         * @covers User::getEditCount
         */
-       public function testEditCount() {
+       public function testGetEditCount() {
                $user = $this->getMutableTestUser()->getUser();
 
                // let the user have a few (3) edits
@@ -221,17 +221,15 @@ class UserTest extends MediaWikiTestCase {
                        $page->doEdit( (string)$i, 'test', 0, false, $user );
                }
 
-               $user->clearInstanceCache();
                $this->assertEquals(
                        3,
                        $user->getEditCount(),
                        'After three edits, the user edit count should be 3'
                );
 
-               // increase the edit count and clear the cache
+               // increase the edit count
                $user->incEditCount();
 
-               $user->clearInstanceCache();
                $this->assertEquals(
                        4,
                        $user->getEditCount(),
@@ -239,6 +237,46 @@ class UserTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * Test User::editCount
+        * @group medium
+        * @covers User::getEditCount
+        */
+       public function testGetEditCountForAnons() {
+               $user = User::newFromName( 'Anonymous' );
+
+               $this->assertNull(
+                       $user->getEditCount(),
+                       'Edit count starts null for anonymous users.'
+               );
+
+               $user->incEditCount();
+
+               $this->assertNull(
+                       $user->getEditCount(),
+                       'Edit count remains null for anonymous users despite calls to increase it.'
+               );
+       }
+
+       /**
+        * Test User::editCount
+        * @group medium
+        * @covers User::incEditCount
+        */
+       public function testIncEditCount() {
+               $user = $this->getMutableTestUser()->getUser();
+               $user->incEditCount();
+
+               $reloadedUser = User::newFromId( $user->getId() );
+               $reloadedUser->incEditCount();
+
+               $this->assertEquals(
+                       2,
+                       $reloadedUser->getEditCount(),
+                       'Increasing the edit count after a fresh load leaves the object up to date.'
+               );
+       }
+
        /**
         * Test changing user options.
         * @covers User::setOption
index baaa66b..a70946a 100755 (executable)
@@ -77,7 +77,7 @@ class PHPUnitMaintClass extends Maintenance {
                global $wgDevelopmentWarnings;
                global $wgSessionProviders, $wgSessionPbkdf2Iterations;
                global $wgJobTypeConf;
-               global $wgAuthManagerConfig, $wgAuth, $wgDisableAuthManager;
+               global $wgAuthManagerConfig, $wgAuth;
 
                // Inject test autoloader
                require_once __DIR__ . '/../TestsAutoLoader.php';
@@ -147,7 +147,7 @@ class PHPUnitMaintClass extends Maintenance {
                        ],
                        'secondaryauth' => [],
                ];
-               $wgAuth = $wgDisableAuthManager ? new AuthPlugin : new MediaWiki\Auth\AuthManagerAuthPlugin();
+               $wgAuth = new MediaWiki\Auth\AuthManagerAuthPlugin();
 
                // Bug 44192 Do not attempt to send a real e-mail
                Hooks::clear( 'AlternateUserMailer' );
index b09bb28..ca26aaf 100644 (file)
                        [ 'Strasse' ]
                ],
 
+               // Data set "digraph"
+               digraphWords = [
+                       [ 'London' ],
+                       [ 'Ljubljana' ],
+                       [ 'Luxembourg' ],
+                       [ 'Njivice' ],
+                       [ 'Norwich' ],
+                       [ 'New York' ]
+               ],
+               digraphWordsSorted = [
+                       [ 'London' ],
+                       [ 'Luxembourg' ],
+                       [ 'Ljubljana' ],
+                       [ 'New York' ],
+                       [ 'Norwich' ],
+                       [ 'Njivice' ]
+               ],
+
                complexMDYDates = [
                        [ 'January, 19 2010' ],
                        [ 'April 21 1991' ],
                }
        );
 
+       tableTest(
+               'Digraphs with custom collation',
+               [ 'City' ],
+               digraphWords,
+               digraphWordsSorted,
+               function ( $table ) {
+                       mw.config.set( 'tableSorterCollation', {
+                               lj: 'lzzzz',
+                               nj: 'nzzzz'
+                       } );
+
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
+       );
+
        QUnit.test( 'Rowspan not exploded on init', 1, function ( assert ) {
                var $table = tableCreate( header, planets );