Merge "Add LBFactory::beginMasterChanges() for doing DBO_TRX rounds"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 24 Aug 2016 20:21:14 +0000 (20:21 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 24 Aug 2016 20:21:14 +0000 (20:21 +0000)
87 files changed:
RELEASE-NOTES-1.28
autoload.php
composer.json
docs/hooks.txt
includes/DefaultSettings.php
includes/EditPage.php
includes/MediaWiki.php
includes/MediaWikiServices.php
includes/OutputPage.php
includes/Pingback.php
includes/ServiceWiring.php
includes/api/i18n/es.json
includes/api/i18n/lt.json
includes/collation/Collation.php
includes/collation/NumericUppercaseCollation.php [new file with mode: 0644]
includes/content/JsonContent.php
includes/content/TextContent.php
includes/content/WikitextContent.php
includes/db/CloneDatabase.php
includes/db/DatabaseMysqlBase.php
includes/db/DatabaseMysqli.php
includes/filebackend/lockmanager/DBLockManager.php
includes/filebackend/lockmanager/MySqlLockManager.php
includes/filebackend/lockmanager/RedisLockManager.php
includes/filerepo/file/LocalFile.php
includes/htmlform/HTMLForm.php
includes/htmlform/HTMLFormField.php
includes/htmlform/fields/HTMLMultiSelectField.php
includes/htmlform/fields/HTMLRadioField.php
includes/installer/i18n/es.json
includes/installer/i18n/hu.json
includes/installer/i18n/lt.json
includes/installer/i18n/vi.json
includes/jobqueue/JobQueueDB.php
includes/jobqueue/JobRunner.php
includes/libs/virtualrest/VirtualRESTServiceClient.php
includes/objectcache/SqlBagOStuff.php
includes/page/Article.php
includes/page/WikiPage.php
includes/parser/Parser.php
includes/specialpage/LoginSignupSpecialPage.php
includes/specials/SpecialCreateAccount.php
includes/specials/SpecialMyLanguage.php
includes/specials/SpecialRunJobs.php
languages/Language.php
languages/i18n/af.json
languages/i18n/ar.json
languages/i18n/be-tarask.json
languages/i18n/be.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/fa.json
languages/i18n/fr.json
languages/i18n/jv.json
languages/i18n/km.json
languages/i18n/ko.json
languages/i18n/lb.json
languages/i18n/lt.json
languages/i18n/lv.json
languages/i18n/mk.json
languages/i18n/my.json
languages/i18n/nds.json
languages/i18n/nn.json
languages/i18n/oc.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/sl.json
languages/i18n/sv.json
languages/i18n/tcy.json
languages/i18n/te.json
languages/i18n/uk.json
languages/i18n/vi.json
languages/messages/MessagesSk.php
maintenance/validateRegistrationFile.php
resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js
resources/src/mediawiki/htmlform/multiselect.js
tests/parser/parserTests.txt
tests/phpunit/includes/MediaWikiServicesTest.php
tests/phpunit/includes/content/TextContentTest.php
tests/phpunit/includes/libs/objectcache/CachedBagOStuffTest.php
tests/phpunit/includes/libs/objectcache/HashBagOStuffTest.php
tests/phpunit/includes/libs/objectcache/MultiWriteBagOStuffTest.php
tests/phpunit/structure/ExtensionJsonValidationTest.php

index 865e300..92ac869 100644 (file)
@@ -39,7 +39,8 @@ production.
 * (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
+  to 'uca-default-u-kn' or 'uca-<langcode>-u-kn'. If you can't use UCA collations,
+  a 'numeric' collation is also available. If migrating from another
   collation, you will need to run the updateCollation.php maintenance script.
 
 === External library changes in 1.28 ===
index 0d19056..39102fd 100644 (file)
@@ -975,6 +975,7 @@ $wgAutoloadLocalClasses = [
        'NullLockManager' => __DIR__ . '/includes/filebackend/lockmanager/LockManager.php',
        'NullRepo' => __DIR__ . '/includes/filerepo/NullRepo.php',
        'NullStatsdDataFactory' => __DIR__ . '/includes/libs/stats/NullStatsdDataFactory.php',
+       'NumericUppercaseCollation' => __DIR__ . '/includes/collation/NumericUppercaseCollation.php',
        'OOUIHTMLForm' => __DIR__ . '/includes/htmlform/OOUIHTMLForm.php',
        'ORAField' => __DIR__ . '/includes/db/DatabaseOracle.php',
        'ORAResult' => __DIR__ . '/includes/db/DatabaseOracle.php',
index 956739d..2243b7c 100644 (file)
@@ -45,7 +45,7 @@
        },
        "require-dev": {
                "jakub-onderka/php-parallel-lint": "0.9.2",
-               "justinrainbow/json-schema": "~1.6",
+               "justinrainbow/json-schema": "~3.0",
                "mediawiki/mediawiki-codesniffer": "0.7.2",
                "monolog/monolog": "~1.18.2",
                "nikic/php-parser": "2.1.0",
index 5cf8ffe..a0ee8bd 100644 (file)
@@ -297,16 +297,6 @@ After a user account is created.
 $user: the User object that was created. (Parameter added in 1.7)
 $byEmail: true when account was created "by email" (added in 1.12)
 
-'AddNewAccountApiForm': Allow modifying internal login form when creating an
-account via API.
-$apiModule: the ApiCreateAccount module calling
-$loginForm: the LoginForm used
-
-'AddNewAccountApiResult': Modify API output when creating a new account via API.
-$apiModule: the ApiCreateAccount module calling
-$loginForm: the LoginForm used
-&$result: associative array for API result data
-
 'AfterBuildFeedLinks': Executed in OutputPage.php after all feed links (atom, rss,...)
 are created. Can be used to omit specific feeds from being outputted. You must not use
 this hook to add feeds, use OutputPage::addFeedLink() instead.
@@ -2069,13 +2059,6 @@ $e: The exception (in case of a plain old PHP error, a wrapping ErrorException)
 $suppressed: true if the error was suppressed via
   error_reporting()/wfSuppressWarnings()
 
-'LoginAuthenticateAudit': A login attempt for a valid user account either
-succeeded or failed. No return data is accepted; this hook is for auditing only.
-$user: the User object being authenticated against
-$password: the password being submitted and found wanting
-$retval: a LoginForm class constant with authenticateUserData() return
-  value (SUCCESS, WRONG_PASS, etc.).
-
 'LoginFormValidErrorMessages': Called in LoginForm when a function gets valid
 error messages. Allows to add additional error messages (except messages already
 in LoginForm::$validErrorMessages).
index 87003f0..f1afc4c 100644 (file)
@@ -3193,6 +3193,15 @@ $wgHTMLFormAllowTableFormat = true;
  */
 $wgUseMediaWikiUIEverywhere = false;
 
+/**
+ * Whether to label the store-to-database-and-show-to-others button in the editor
+ * as "Save page"/"Save changes" if false (the default) or, if true, instead as
+ * "Publish page"/"Publish changes".
+ *
+ * @since 1.28
+ */
+$wgEditButtonPublishNotSave = false;
+
 /**
  * Permit other namespaces in addition to the w3.org default.
  *
@@ -8033,9 +8042,13 @@ $wgJobRunRate = 1;
  * When $wgJobRunRate > 0, try to run jobs asynchronously, spawning a new process
  * to handle the job execution, instead of blocking the request until the job
  * execution finishes.
+ *
  * @since 1.23
  */
-$wgRunJobsAsync = true;
+$wgRunJobsAsync = (
+       !function_exists( 'register_postsend_function' ) &&
+       !function_exists( 'fastcgi_finish_request' )
+);
 
 /**
  * Number of rows to update per job
@@ -8250,11 +8263,29 @@ $wgPageLanguageUseDB = false;
 
 /**
  * Global configuration variable for Virtual REST Services.
- * Parameters for different services are to be declared inside
- * $wgVirtualRestConfig['modules'], which is to be treated as an associative
- * array. Global parameters will be merged with service-specific ones. The
- * result will then be passed to VirtualRESTService::__construct() in the
- * module.
+ *
+ * Use the 'path' key to define automatically mounted services. The value for this
+ * key is a map of path prefixes to service configuration. The later is an array of:
+ *   - class : the fully qualified class name
+ *   - options : map of arguments to the class constructor
+ * Such services will be available to handle queries under their path from the VRS
+ * singleton, e.g. MediaWikiServices::getInstance()->getVirtualRESTServiceClient();
+ *
+ * Auto-mounting example for Parsoid:
+ *
+ * $wgVirtualRestConfig['paths']['/parsoid/'] = [
+ *     'class' => 'ParsoidVirtualRESTService',
+ *     'options' => [
+ *         'url' => 'http://localhost:8000',
+ *         'prefix' => 'enwiki',
+ *         'domain' => 'en.wikipedia.org'
+ *     ]
+ * ];
+ *
+ * Parameters for different services can also be declared inside the 'modules' value,
+ * which is to be treated as an associative array. The parameters in 'global' will be
+ * merged with service-specific ones. The result will then be passed to
+ * VirtualRESTService::__construct() in the module.
  *
  * Example config for Parsoid:
  *
@@ -8268,6 +8299,7 @@ $wgPageLanguageUseDB = false;
  * @since 1.25
  */
 $wgVirtualRestConfig = [
+       'paths' => [],
        'modules' => [],
        'global' => [
                # Timeout in seconds
@@ -8342,7 +8374,7 @@ $wgEventRelayerConfig = [
  * PHP version, and chosen database backend. The Wikimedia Foundation shares this data with
  * MediaWiki developers to help guide future development efforts.
  *
- * For details about what data is sent, see: https://www.mediawiki.org/wiki/Pingback
+ * For details about what data is sent, see: https://www.mediawiki.org/wiki/Manual:$wgPingback
  *
  * @var bool
  * @since 1.28
index 9b862b9..738eaec 100644 (file)
@@ -401,6 +401,11 @@ class EditPage {
         */
        private $enableApiEditOverride = false;
 
+       /**
+        * @var IContextSource
+        */
+       protected $context;
+
        /**
         * @param Article $article
         */
@@ -408,6 +413,7 @@ class EditPage {
                $this->mArticle = $article;
                $this->page = $article->getPage(); // model object
                $this->mTitle = $article->getTitle();
+               $this->context = $article->getContext();
 
                $this->contentModel = $this->mTitle->getContentModel();
 
@@ -422,6 +428,14 @@ class EditPage {
                return $this->mArticle;
        }
 
+       /**
+        * @since 1.28
+        * @return IContextSource
+        */
+       public function getContext() {
+               return $this->context;
+       }
+
        /**
         * @since 1.19
         * @return Title
@@ -493,7 +507,6 @@ class EditPage {
         * the newly-edited page.
         */
        function edit() {
-               global $wgOut, $wgRequest, $wgUser;
                // Allow extensions to modify/prevent this form or submission
                if ( !Hooks::run( 'AlternateEdit', [ $this ] ) ) {
                        return;
@@ -501,13 +514,15 @@ class EditPage {
 
                wfDebug( __METHOD__ . ": enter\n" );
 
+               $request = $this->context->getRequest();
+               $out = $this->context->getOutput();
                // If they used redlink=1 and the page exists, redirect to the main article
-               if ( $wgRequest->getBool( 'redlink' ) && $this->mTitle->exists() ) {
-                       $wgOut->redirect( $this->mTitle->getFullURL() );
+               if ( $request->getBool( 'redlink' ) && $this->mTitle->exists() ) {
+                       $out->redirect( $this->mTitle->getFullURL() );
                        return;
                }
 
-               $this->importFormData( $wgRequest );
+               $this->importFormData( $request );
                $this->firsttime = false;
 
                if ( wfReadOnly() && $this->save ) {
@@ -536,7 +551,7 @@ class EditPage {
                        wfDebug( __METHOD__ . ": User can't edit\n" );
                        // Auto-block user's IP if the account was "hard" blocked
                        if ( !wfReadOnly() ) {
-                               $user = $wgUser;
+                               $user = $this->context->getUser();
                                DeferredUpdates::addCallableUpdate( function () use ( $user ) {
                                        $user->spreadAnyEditBlock();
                                } );
@@ -610,15 +625,14 @@ class EditPage {
         * @return array
         */
        protected function getEditPermissionErrors( $rigor = 'secure' ) {
-               global $wgUser;
-
-               $permErrors = $this->mTitle->getUserPermissionsErrors( 'edit', $wgUser, $rigor );
+               $user = $this->context->getUser();
+               $permErrors = $this->mTitle->getUserPermissionsErrors( 'edit', $user, $rigor );
                # Can this title be created?
                if ( !$this->mTitle->exists() ) {
                        $permErrors = array_merge(
                                $permErrors,
                                wfArrayDiff2(
-                                       $this->mTitle->getUserPermissionsErrors( 'create', $wgUser, $rigor ),
+                                       $this->mTitle->getUserPermissionsErrors( 'create', $user, $rigor ),
                                        $permErrors
                                )
                        );
@@ -651,13 +665,12 @@ class EditPage {
         * @throws PermissionsError
         */
        protected function displayPermissionsError( array $permErrors ) {
-               global $wgRequest, $wgOut;
-
-               if ( $wgRequest->getBool( 'redlink' ) ) {
+               $out = $this->context->getOutput();
+               if ( $this->context->getRequest()->getBool( 'redlink' ) ) {
                        // The edit page was reached via a red link.
                        // Redirect to the article page and let them click the edit tab if
                        // they really want a permission error.
-                       $wgOut->redirect( $this->mTitle->getFullURL() );
+                       $out->redirect( $this->mTitle->getFullURL() );
                        return;
                }
 
@@ -672,7 +685,7 @@ class EditPage {
 
                $this->displayViewSourcePage(
                        $content,
-                       $wgOut->formatPermissionsErrorMessage( $permErrors, 'edit' )
+                       $out->formatPermissionsErrorMessage( $permErrors, 'edit' )
                );
        }
 
@@ -682,29 +695,28 @@ class EditPage {
         * @param string $errorMessage additional wikitext error message to display
         */
        protected function displayViewSourcePage( Content $content, $errorMessage = '' ) {
-               global $wgOut;
+               $out = $this->context->getOutput();
+               Hooks::run( 'EditPage::showReadOnlyForm:initial', [ $this, &$out ] );
 
-               Hooks::run( 'EditPage::showReadOnlyForm:initial', [ $this, &$wgOut ] );
-
-               $wgOut->setRobotPolicy( 'noindex,nofollow' );
-               $wgOut->setPageTitle( wfMessage(
+               $out->setRobotPolicy( 'noindex,nofollow' );
+               $out->setPageTitle( wfMessage(
                        'viewsource-title',
                        $this->getContextTitle()->getPrefixedText()
                ) );
-               $wgOut->addBacklinkSubtitle( $this->getContextTitle() );
-               $wgOut->addHTML( $this->editFormPageTop );
-               $wgOut->addHTML( $this->editFormTextTop );
+               $out->addBacklinkSubtitle( $this->getContextTitle() );
+               $out->addHTML( $this->editFormPageTop );
+               $out->addHTML( $this->editFormTextTop );
 
                if ( $errorMessage !== '' ) {
-                       $wgOut->addWikiText( $errorMessage );
-                       $wgOut->addHTML( "<hr />\n" );
+                       $out->addWikiText( $errorMessage );
+                       $out->addHTML( "<hr />\n" );
                }
 
                # If the user made changes, preserve them when showing the markup
                # (This happens when a user is blocked during edit, for instance)
                if ( !$this->firsttime ) {
                        $text = $this->textbox1;
-                       $wgOut->addWikiMsg( 'viewyourtext' );
+                       $out->addWikiMsg( 'viewyourtext' );
                } else {
                        try {
                                $text = $this->toEditText( $content );
@@ -713,21 +725,21 @@ class EditPage {
                                # (e.g. for an old revision with a different model)
                                $text = $content->serialize();
                        }
-                       $wgOut->addWikiMsg( 'viewsourcetext' );
+                       $out->addWikiMsg( 'viewsourcetext' );
                }
 
-               $wgOut->addHTML( $this->editFormTextBeforeContent );
+               $out->addHTML( $this->editFormTextBeforeContent );
                $this->showTextbox( $text, 'wpTextbox1', [ 'readonly' ] );
-               $wgOut->addHTML( $this->editFormTextAfterContent );
+               $out->addHTML( $this->editFormTextAfterContent );
 
-               $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'templatesUsed' ],
+               $out->addHTML( Html::rawElement( 'div', [ 'class' => 'templatesUsed' ],
                        Linker::formatTemplates( $this->getTemplates() ) ) );
 
-               $wgOut->addModules( 'mediawiki.action.edit.collapsibleFooter' );
+               $out->addModules( 'mediawiki.action.edit.collapsibleFooter' );
 
-               $wgOut->addHTML( $this->editFormTextBottom );
+               $out->addHTML( $this->editFormTextBottom );
                if ( $this->mTitle->exists() ) {
-                       $wgOut->returnToMain( null, $this->mTitle );
+                       $out->returnToMain( null, $this->mTitle );
                }
        }
 
@@ -737,18 +749,19 @@ class EditPage {
         * @return bool
         */
        protected function previewOnOpen() {
-               global $wgRequest, $wgUser, $wgPreviewOnOpenNamespaces;
-               if ( $wgRequest->getVal( 'preview' ) == 'yes' ) {
+               global $wgPreviewOnOpenNamespaces;
+               $request = $this->context->getRequest();
+               if ( $request->getVal( 'preview' ) == 'yes' ) {
                        // Explicit override from request
                        return true;
-               } elseif ( $wgRequest->getVal( 'preview' ) == 'no' ) {
+               } elseif ( $request->getVal( 'preview' ) == 'no' ) {
                        // Explicit override from request
                        return false;
                } elseif ( $this->section == 'new' ) {
                        // Nothing *to* preview for new sections
                        return false;
-               } elseif ( ( $wgRequest->getVal( 'preload' ) !== null || $this->mTitle->exists() )
-                       && $wgUser->getOption( 'previewonfirst' )
+               } elseif ( ( $request->getVal( 'preload' ) !== null || $this->mTitle->exists() )
+                       && $this->context->getUser()->getOption( 'previewonfirst' )
                ) {
                        // Standard preference behavior
                        return true;
@@ -801,7 +814,7 @@ class EditPage {
         * @throws ErrorPageError
         */
        function importFormData( &$request ) {
-               global $wgContLang, $wgUser;
+               global $wgContLang;
 
                # Section edit can come from either the form or a link
                $this->section = $request->getVal( 'wpSection', $request->getVal( 'section' ) );
@@ -913,13 +926,14 @@ class EditPage {
                        $this->watchthis = $request->getCheck( 'wpWatchthis' );
 
                        # Don't force edit summaries when a user is editing their own user or talk page
+                       $user = $this->context->getUser();
                        if ( ( $this->mTitle->mNamespace == NS_USER || $this->mTitle->mNamespace == NS_USER_TALK )
-                               && $this->mTitle->getText() == $wgUser->getName()
+                               && $this->mTitle->getText() == $user->getName()
                        ) {
                                $this->allowBlankSummary = true;
                        } else {
                                $this->allowBlankSummary = $request->getBool( 'wpIgnoreBlankSummary' )
-                                       || !$wgUser->getOption( 'forceeditsummary' );
+                                       || !$user->getOption( 'forceeditsummary' );
                        }
 
                        $this->autoSumm = $request->getText( 'wpAutoSummary' );
@@ -1025,7 +1039,6 @@ class EditPage {
         * @return bool If the requested section is valid
         */
        function initialiseForm() {
-               global $wgUser;
                $this->edittime = $this->page->getTimestamp();
                $this->editRevId = $this->page->getLatest();
 
@@ -1034,20 +1047,21 @@ class EditPage {
                        return false;
                }
                $this->textbox1 = $this->toEditText( $content );
+               $user = $this->context->getUser();
 
                // activate checkboxes if user wants them to be always active
                # Sort out the "watch" checkbox
-               if ( $wgUser->getOption( 'watchdefault' ) ) {
+               if ( $user->getOption( 'watchdefault' ) ) {
                        # Watch all edits
                        $this->watchthis = true;
-               } elseif ( $wgUser->getOption( 'watchcreations' ) && !$this->mTitle->exists() ) {
+               } elseif ( $user->getOption( 'watchcreations' ) && !$this->mTitle->exists() ) {
                        # Watch creations
                        $this->watchthis = true;
-               } elseif ( $wgUser->isWatched( $this->mTitle ) ) {
+               } elseif ( $user->isWatched( $this->mTitle ) ) {
                        # Already watched
                        $this->watchthis = true;
                }
-               if ( $wgUser->getOption( 'minordefault' ) && !$this->isNew ) {
+               if ( $user->getOption( 'minordefault' ) && !$this->isNew ) {
                        $this->minoredit = true;
                }
                if ( $this->textbox1 === false ) {
@@ -1064,9 +1078,11 @@ class EditPage {
         * @since 1.21
         */
        protected function getContentObject( $def_content = null ) {
-               global $wgOut, $wgRequest, $wgUser, $wgContLang;
+               global $wgContLang;
 
                $content = false;
+               $request = $this->context->getRequest();
+               $user = $this->context->getUser();
 
                // For message page not locally set, use the i18n message.
                // For other non-existent articles, use preload text if any.
@@ -1079,10 +1095,10 @@ class EditPage {
                        }
                        if ( $content === false ) {
                                # If requested, preload some text.
-                               $preload = $wgRequest->getVal( 'preload',
+                               $preload = $request->getVal( 'preload',
                                        // Custom preload text for new sections
                                        $this->section === 'new' ? 'MediaWiki:addsection-preload' : '' );
-                               $params = $wgRequest->getArray( 'preloadparams', [] );
+                               $params = $request->getArray( 'preloadparams', [] );
 
                                $content = $this->getPreloadedContent( $preload, $params );
                        }
@@ -1090,15 +1106,15 @@ class EditPage {
                } else {
                        if ( $this->section != '' ) {
                                // Get section edit text (returns $def_text for invalid sections)
-                               $orig = $this->getOriginalContent( $wgUser );
+                               $orig = $this->getOriginalContent( $user );
                                $content = $orig ? $orig->getSection( $this->section ) : null;
 
                                if ( !$content ) {
                                        $content = $def_content;
                                }
                        } else {
-                               $undoafter = $wgRequest->getInt( 'undoafter' );
-                               $undo = $wgRequest->getInt( 'undo' );
+                               $undoafter = $request->getInt( 'undoafter' );
+                               $undo = $request->getInt( 'undo' );
 
                                if ( $undo > 0 && $undoafter > 0 ) {
                                        $undorev = Revision::newFromId( $undo );
@@ -1118,8 +1134,8 @@ class EditPage {
                                                        $undoMsg = 'failure';
                                                } else {
                                                        $oldContent = $this->page->getContent( Revision::RAW );
-                                                       $popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
-                                                       $newContent = $content->preSaveTransform( $this->mTitle, $wgUser, $popts );
+                                                       $popts = ParserOptions::newFromUserAndLang( $user, $wgContLang );
+                                                       $newContent = $content->preSaveTransform( $this->mTitle, $user, $popts );
 
                                                        if ( $newContent->equals( $oldContent ) ) {
                                                                # Tell the user that the undo results in no change,
@@ -1166,12 +1182,13 @@ class EditPage {
 
                                        // Messages: undo-success, undo-failure, undo-norev, undo-nochange
                                        $class = ( $undoMsg == 'success' ? '' : 'error ' ) . "mw-undo-{$undoMsg}";
-                                       $this->editFormPageTop .= $wgOut->parse( "<div class=\"{$class}\">" .
+                                       $this->editFormPageTop .= $this->context->getOutput()->parse(
+                                               "<div class=\"{$class}\">" .
                                                wfMessage( 'undo-' . $undoMsg )->plain() . '</div>', true, /* interface */true );
                                }
 
                                if ( $content === false ) {
-                                       $content = $this->getOriginalContent( $wgUser );
+                                       $content = $this->getOriginalContent( $user );
                                }
                        }
                }
@@ -1368,10 +1385,10 @@ class EditPage {
         * @private
         */
        function tokenOk( &$request ) {
-               global $wgUser;
                $token = $request->getVal( 'wpEditToken' );
-               $this->mTokenOk = $wgUser->matchEditToken( $token );
-               $this->mTokenOkExceptSuffix = $wgUser->matchEditTokenNoSuffix( $token );
+               $user = $this->context->getUser();
+               $this->mTokenOk = $user->matchEditToken( $token );
+               $this->mTokenOkExceptSuffix = $user->matchEditTokenNoSuffix( $token );
                return $this->mTokenOk;
        }
 
@@ -1402,7 +1419,7 @@ class EditPage {
                        $val = 'restored';
                }
 
-               $response = RequestContext::getMain()->getRequest()->response();
+               $response = $this->context->getRequest()->response();
                $response->setCookie( $postEditKey, $val, time() + self::POST_EDIT_COOKIE_DURATION, [
                        'httpOnly' => false,
                ] );
@@ -1410,15 +1427,13 @@ class EditPage {
 
        /**
         * Attempt submission
-        * @param array $resultDetails See docs for $result in internalAttemptSave
+        * @param array|bool $resultDetails See docs for $result in internalAttemptSave
         * @throws UserBlockedError|ReadOnlyError|ThrottledError|PermissionsError
         * @return Status The resulting status object.
         */
        public function attemptSave( &$resultDetails = false ) {
-               global $wgUser;
-
                # Allow bots to exempt some edits from bot flagging
-               $bot = $wgUser->isAllowed( 'bot' ) && $this->bot;
+               $bot = $this->context->getUser()->isAllowed( 'bot' ) && $this->bot;
                $status = $this->internalAttemptSave( $resultDetails, $bot );
 
                Hooks::run( 'EditPage::attemptSave:after', [ $this, $status, $resultDetails ] );
@@ -1436,8 +1451,6 @@ class EditPage {
         * @return bool False, if output is done, true if rest of the form should be displayed
         */
        private function handleStatus( Status $status, $resultDetails ) {
-               global $wgUser, $wgOut;
-
                /**
                 * @todo FIXME: once the interface for internalAttemptSave() is made
                 *   nicer, this should use the message in $status
@@ -1451,9 +1464,11 @@ class EditPage {
                        }
                }
 
+               $out = $this->context->getOutput();
+
                // "wpExtraQueryRedirect" is a hidden input to modify
                // after save URL and is not used by actual edit form
-               $request = RequestContext::getMain()->getRequest();
+               $request = $this->context->getRequest();
                $extraQueryRedirect = $request->getVal( 'wpExtraQueryRedirect' );
 
                switch ( $status->value ) {
@@ -1474,7 +1489,7 @@ class EditPage {
 
                        case self::AS_CANNOT_USE_CUSTOM_MODEL:
                        case self::AS_PARSE_ERROR:
-                               $wgOut->addWikiText( '<div class="error">' . "\n" . $status->getWikiText() . '</div>' );
+                               $out->addWikiText( '<div class="error">' . "\n" . $status->getWikiText() . '</div>' );
                                return true;
 
                        case self::AS_SUCCESS_NEW_ARTICLE:
@@ -1487,7 +1502,7 @@ class EditPage {
                                        }
                                }
                                $anchor = isset( $resultDetails['sectionanchor'] ) ? $resultDetails['sectionanchor'] : '';
-                               $wgOut->redirect( $this->mTitle->getFullURL( $query ) . $anchor );
+                               $out->redirect( $this->mTitle->getFullURL( $query ) . $anchor );
                                return false;
 
                        case self::AS_SUCCESS_UPDATE:
@@ -1515,7 +1530,7 @@ class EditPage {
                                        }
                                }
 
-                               $wgOut->redirect( $this->mTitle->getFullURL( $extraQuery ) . $sectionanchor );
+                               $out->redirect( $this->mTitle->getFullURL( $extraQuery ) . $sectionanchor );
                                return false;
 
                        case self::AS_SPAM_ERROR:
@@ -1523,7 +1538,7 @@ class EditPage {
                                return false;
 
                        case self::AS_BLOCKED_PAGE_FOR_USER:
-                               throw new UserBlockedError( $wgUser->getBlock() );
+                               throw new UserBlockedError( $this->context->getUser()->getBlock() );
 
                        case self::AS_IMAGE_REDIRECT_ANON:
                        case self::AS_IMAGE_REDIRECT_LOGGED:
@@ -1584,7 +1599,7 @@ class EditPage {
 
                // Run new style post-section-merge edit filter
                if ( !Hooks::run( 'EditFilterMergedContent',
-                               [ $this->mArticle->getContext(), $content, $status, $this->summary,
+                               [ $this->context, $content, $status, $this->summary,
                                $user, $this->minoredit ] )
                ) {
                        # Error messages etc. could be handled within the hook...
@@ -1669,10 +1684,11 @@ class EditPage {
         * time.
         */
        function internalAttemptSave( &$result, $bot = false ) {
-               global $wgUser, $wgRequest, $wgParser, $wgMaxArticleSize;
-               global $wgContentHandlerUseDB;
+               global $wgParser, $wgMaxArticleSize, $wgContentHandlerUseDB;
 
                $status = Status::newGood();
+               $user = $this->context->getUser();
+               $request = $this->context->getRequest();
 
                if ( !Hooks::run( 'EditPage::attemptSave', [ $this ] ) ) {
                        wfDebug( "Hook 'EditPage::attemptSave' aborted article saving\n" );
@@ -1681,11 +1697,11 @@ class EditPage {
                        return $status;
                }
 
-               $spam = $wgRequest->getText( 'wpAntispam' );
+               $spam = $request->getText( 'wpAntispam' );
                if ( $spam !== '' ) {
                        wfDebugLog(
                                'SimpleAntiSpam',
-                               $wgUser->getName() .
+                               $user->getName() .
                                ' editing "' .
                                $this->mTitle->getPrefixedText() .
                                '" submitted bogus field "' .
@@ -1714,9 +1730,9 @@ class EditPage {
                # Check image redirect
                if ( $this->mTitle->getNamespace() == NS_FILE &&
                        $textbox_content->isRedirect() &&
-                       !$wgUser->isAllowed( 'upload' )
+                       !$user->isAllowed( 'upload' )
                ) {
-                               $code = $wgUser->isAnon() ? self::AS_IMAGE_REDIRECT_ANON : self::AS_IMAGE_REDIRECT_LOGGED;
+                               $code = $user->isAnon() ? self::AS_IMAGE_REDIRECT_ANON : self::AS_IMAGE_REDIRECT_LOGGED;
                                $status->setResult( false, $code );
 
                                return $status;
@@ -1741,7 +1757,7 @@ class EditPage {
                }
                if ( $match !== false ) {
                        $result['spam'] = $match;
-                       $ip = $wgRequest->getIP();
+                       $ip = $request->getIP();
                        $pdbk = $this->mTitle->getPrefixedDBkey();
                        $match = str_replace( "\n", '', $match );
                        wfDebugLog( 'SpamRegex', "$ip spam regex hit [[$pdbk]]: \"$match\"" );
@@ -1764,10 +1780,10 @@ class EditPage {
                        return $status;
                }
 
-               if ( $wgUser->isBlockedFrom( $this->mTitle, false ) ) {
+               if ( $user->isBlockedFrom( $this->mTitle, false ) ) {
                        // Auto-block user's IP if the account was "hard" blocked
                        if ( !wfReadOnly() ) {
-                               $wgUser->spreadAnyEditBlock();
+                               $user->spreadAnyEditBlock();
                        }
                        # Check block state against master, thus 'false'.
                        $status->setResult( false, self::AS_BLOCKED_PAGE_FOR_USER );
@@ -1782,8 +1798,8 @@ class EditPage {
                        return $status;
                }
 
-               if ( !$wgUser->isAllowed( 'edit' ) ) {
-                       if ( $wgUser->isAnon() ) {
+               if ( !$user->isAllowed( 'edit' ) ) {
+                       if ( $user->isAnon() ) {
                                $status->setResult( false, self::AS_READ_ONLY_PAGE_ANON );
                                return $status;
                        } else {
@@ -1799,7 +1815,7 @@ class EditPage {
                                $status->fatal( 'editpage-cannot-use-custom-model' );
                                $status->value = self::AS_CANNOT_USE_CUSTOM_MODEL;
                                return $status;
-                       } elseif ( !$wgUser->isAllowed( 'editcontentmodel' ) ) {
+                       } elseif ( !$user->isAllowed( 'editcontentmodel' ) ) {
                                $status->setResult( false, self::AS_NO_CHANGE_CONTENT_MODEL );
                                return $status;
 
@@ -1810,7 +1826,7 @@ class EditPage {
 
                if ( $this->changeTags ) {
                        $changeTagsStatus = ChangeTags::canAddTagsAccompanyingChange(
-                               $this->changeTags, $wgUser );
+                               $this->changeTags, $user );
                        if ( !$changeTagsStatus->isOK() ) {
                                $changeTagsStatus->value = self::AS_CHANGE_TAG_ERROR;
                                return $changeTagsStatus;
@@ -1822,7 +1838,7 @@ class EditPage {
                        $status->value = self::AS_READ_ONLY_PAGE;
                        return $status;
                }
-               if ( $wgUser->pingLimiter() || $wgUser->pingLimiter( 'linkpurge', 0 ) ) {
+               if ( $user->pingLimiter() || $user->pingLimiter( 'linkpurge', 0 ) ) {
                        $status->fatal( 'actionthrottledtext' );
                        $status->value = self::AS_RATE_LIMITED;
                        return $status;
@@ -1842,7 +1858,7 @@ class EditPage {
 
                if ( $new ) {
                        // Late check for create permission, just in case *PARANOIA*
-                       if ( !$this->mTitle->userCan( 'create', $wgUser ) ) {
+                       if ( !$this->mTitle->userCan( 'create', $user ) ) {
                                $status->fatal( 'nocreatetext' );
                                $status->value = self::AS_NO_CREATE_PERMISSION;
                                wfDebug( __METHOD__ . ": no create permission\n" );
@@ -1866,7 +1882,7 @@ class EditPage {
                                return $status;
                        }
 
-                       if ( !$this->runPostMergeFilters( $textbox_content, $status, $wgUser ) ) {
+                       if ( !$this->runPostMergeFilters( $textbox_content, $status, $user ) ) {
                                return $status;
                        }
 
@@ -1902,7 +1918,7 @@ class EditPage {
                        ) {
                                $this->isConflict = true;
                                if ( $this->section == 'new' ) {
-                                       if ( $this->page->getUserText() == $wgUser->getName() &&
+                                       if ( $this->page->getUserText() == $user->getName() &&
                                                $this->page->getComment() == $this->newSectionSummary()
                                        ) {
                                                // Probably a duplicate submission of a new comment.
@@ -1918,7 +1934,7 @@ class EditPage {
                                } elseif ( $this->section == ''
                                        && Revision::userWasLastToEdit(
                                                DB_MASTER, $this->mTitle->getArticleID(),
-                                               $wgUser->getId(), $this->edittime
+                                               $user->getId(), $this->edittime
                                        )
                                ) {
                                        # Suppress edit conflict with self, except for section edits where merging is required.
@@ -1988,7 +2004,7 @@ class EditPage {
                                return $status;
                        }
 
-                       if ( !$this->runPostMergeFilters( $content, $status, $wgUser ) ) {
+                       if ( !$this->runPostMergeFilters( $content, $status, $user ) ) {
                                return $status;
                        }
 
@@ -2009,7 +2025,7 @@ class EditPage {
                                        return $status;
                                }
                        } elseif ( !$this->allowBlankSummary
-                               && !$content->equals( $this->getOriginalContent( $wgUser ) )
+                               && !$content->equals( $this->getOriginalContent( $user ) )
                                && !$content->isRedirect()
                                && md5( $this->summary ) == $this->autoSumm
                        ) {
@@ -2079,7 +2095,7 @@ class EditPage {
                        $this->summary,
                        $flags,
                        false,
-                       $wgUser,
+                       $user,
                        $content->getDefaultFormat(),
                        $this->changeTags
                );
@@ -2102,7 +2118,7 @@ class EditPage {
                $result['nullEdit'] = $doEditStatus->hasMessage( 'edit-no-change' );
                if ( $result['nullEdit'] ) {
                        // We don't know if it was a null edit until now, so increment here
-                       $wgUser->pingLimiter( 'linkpurge' );
+                       $user->pingLimiter( 'linkpurge' );
                }
                $result['redirect'] = $content->isRedirect();
 
@@ -2111,7 +2127,7 @@ class EditPage {
                // If the content model changed, add a log entry
                if ( $changingContentModel ) {
                        $this->addContentModelChangeLogEntry(
-                               $wgUser,
+                               $user,
                                $new ? false : $oldContentModel,
                                $this->contentModel,
                                $this->summary
@@ -2145,13 +2161,12 @@ class EditPage {
         * Register the change of watch status
         */
        protected function updateWatchlist() {
-               global $wgUser;
+               $user = $this->context->getUser();
 
-               if ( !$wgUser->isLoggedIn() ) {
+               if ( !$user->isLoggedIn() ) {
                        return;
                }
 
-               $user = $wgUser;
                $title = $this->mTitle;
                $watch = $this->watchthis;
                // Do this in its own transaction to reduce contention...
@@ -2266,29 +2281,32 @@ class EditPage {
        }
 
        function setHeaders() {
-               global $wgOut, $wgUser, $wgAjaxEditStash;
+               global $wgAjaxEditStash;
+
+               $out = $this->context->getOutput();
+               $user = $this->context->getUser();
 
-               $wgOut->addModules( 'mediawiki.action.edit' );
-               $wgOut->addModuleStyles( 'mediawiki.action.edit.styles' );
+               $out->addModules( 'mediawiki.action.edit' );
+               $out->addModuleStyles( 'mediawiki.action.edit.styles' );
 
-               if ( $wgUser->getOption( 'showtoolbar' ) ) {
+               if ( $user->getOption( 'showtoolbar' ) ) {
                        // The addition of default buttons is handled by getEditToolbar() which
                        // has its own dependency on this module. The call here ensures the module
                        // is loaded in time (it has position "top") for other modules to register
                        // buttons (e.g. extensions, gadgets, user scripts).
-                       $wgOut->addModules( 'mediawiki.toolbar' );
+                       $out->addModules( 'mediawiki.toolbar' );
                }
 
-               if ( $wgUser->getOption( 'uselivepreview' ) ) {
-                       $wgOut->addModules( 'mediawiki.action.edit.preview' );
+               if ( $user->getOption( 'uselivepreview' ) ) {
+                       $out->addModules( 'mediawiki.action.edit.preview' );
                }
 
-               if ( $wgUser->getOption( 'useeditwarning' ) ) {
-                       $wgOut->addModules( 'mediawiki.action.edit.editWarning' );
+               if ( $user->getOption( 'useeditwarning' ) ) {
+                       $out->addModules( 'mediawiki.action.edit.editWarning' );
                }
 
                # Enabled article-related sidebar, toplinks, etc.
-               $wgOut->setArticleRelated( true );
+               $out->setArticleRelated( true );
 
                $contextTitle = $this->getContextTitle();
                if ( $this->isConflict ) {
@@ -2311,10 +2329,10 @@ class EditPage {
                if ( $displayTitle === false ) {
                        $displayTitle = $contextTitle->getPrefixedText();
                }
-               $wgOut->setPageTitle( wfMessage( $msg, $displayTitle ) );
+               $out->setPageTitle( wfMessage( $msg, $displayTitle ) );
                # Transmit the name of the message to JavaScript for live preview
                # Keep Resources.php/mediawiki.action.edit.preview in sync with the possible keys
-               $wgOut->addJsConfigVars( [
+               $out->addJsConfigVars( [
                        'wgEditMessage' => $msg,
                        'wgAjaxEditStash' => $wgAjaxEditStash,
                ] );
@@ -2324,16 +2342,16 @@ class EditPage {
         * Show all applicable editing introductions
         */
        protected function showIntro() {
-               global $wgOut, $wgUser;
                if ( $this->suppressIntro ) {
                        return;
                }
 
+               $out = $this->context->getOutput();
                $namespace = $this->mTitle->getNamespace();
 
                if ( $namespace == NS_MEDIAWIKI ) {
                        # Show a warning if editing an interface message
-                       $wgOut->wrapWikiMsg( "<div class='mw-editinginterface'>\n$1\n</div>", 'editinginterface' );
+                       $out->wrapWikiMsg( "<div class='mw-editinginterface'>\n$1\n</div>", 'editinginterface' );
                        # If this is a default message (but not css or js),
                        # show a hint that it is translatable on translatewiki.net
                        if ( !$this->mTitle->hasContentModel( CONTENT_MODEL_CSS )
@@ -2341,7 +2359,7 @@ class EditPage {
                        ) {
                                $defaultMessageText = $this->mTitle->getDefaultMessageText();
                                if ( $defaultMessageText !== false ) {
-                                       $wgOut->wrapWikiMsg( "<div class='mw-translateinterface'>\n$1\n</div>",
+                                       $out->wrapWikiMsg( "<div class='mw-translateinterface'>\n$1\n</div>",
                                                'translateinterface' );
                                }
                        }
@@ -2353,11 +2371,11 @@ class EditPage {
                                # there must be a description url to show a hint to shared repo
                                if ( $descUrl ) {
                                        if ( !$this->mTitle->exists() ) {
-                                               $wgOut->wrapWikiMsg( "<div class=\"mw-sharedupload-desc-create\">\n$1\n</div>", [
+                                               $out->wrapWikiMsg( "<div class=\"mw-sharedupload-desc-create\">\n$1\n</div>", [
                                                                        'sharedupload-desc-create', $file->getRepo()->getDisplayName(), $descUrl
                                                ] );
                                        } else {
-                                               $wgOut->wrapWikiMsg( "<div class=\"mw-sharedupload-desc-edit\">\n$1\n</div>", [
+                                               $out->wrapWikiMsg( "<div class=\"mw-sharedupload-desc-edit\">\n$1\n</div>", [
                                                                        'sharedupload-desc-edit', $file->getRepo()->getDisplayName(), $descUrl
                                                ] );
                                        }
@@ -2373,12 +2391,12 @@ class EditPage {
                        $ip = User::isIP( $username );
                        $block = Block::newFromTarget( $user, $user );
                        if ( !( $user && $user->isLoggedIn() ) && !$ip ) { # User does not exist
-                               $wgOut->wrapWikiMsg( "<div class=\"mw-userpage-userdoesnotexist error\">\n$1\n</div>",
+                               $out->wrapWikiMsg( "<div class=\"mw-userpage-userdoesnotexist error\">\n$1\n</div>",
                                        [ 'userpage-userdoesnotexist', wfEscapeWikiText( $username ) ] );
                        } elseif ( !is_null( $block ) && $block->getType() != Block::TYPE_AUTO ) {
                                # Show log extract if the user is currently blocked
                                LogEventsList::showLogExtract(
-                                       $wgOut,
+                                       $out,
                                        'block',
                                        MWNamespace::getCanonicalName( NS_USER ) . ':' . $block->getTarget(),
                                        '',
@@ -2398,8 +2416,8 @@ class EditPage {
                        $helpLink = wfExpandUrl( Skin::makeInternalOrExternalUrl(
                                wfMessage( 'helppage' )->inContentLanguage()->text()
                        ) );
-                       if ( $wgUser->isLoggedIn() ) {
-                               $wgOut->wrapWikiMsg(
+                       if ( $this->context->getUser()->isLoggedIn() ) {
+                               $out->wrapWikiMsg(
                                        // Suppress the external link icon, consider the help url an internal one
                                        "<div class=\"mw-newarticletext plainlinks\">\n$1\n</div>",
                                        [
@@ -2408,7 +2426,7 @@ class EditPage {
                                        ]
                                );
                        } else {
-                               $wgOut->wrapWikiMsg(
+                               $out->wrapWikiMsg(
                                        // Suppress the external link icon, consider the help url an internal one
                                        "<div class=\"mw-newarticletextanon plainlinks\">\n$1\n</div>",
                                        [
@@ -2420,7 +2438,7 @@ class EditPage {
                }
                # Give a notice if the user is editing a deleted/moved page...
                if ( !$this->mTitle->exists() ) {
-                       LogEventsList::showLogExtract( $wgOut, [ 'delete', 'move' ], $this->mTitle,
+                       LogEventsList::showLogExtract( $out, [ 'delete', 'move' ], $this->mTitle,
                                '',
                                [
                                        'lim' => 10,
@@ -2441,9 +2459,8 @@ class EditPage {
                if ( $this->editintro ) {
                        $title = Title::newFromText( $this->editintro );
                        if ( $title instanceof Title && $title->exists() && $title->userCan( 'read' ) ) {
-                               global $wgOut;
                                // Added using template syntax, to take <noinclude>'s into account.
-                               $wgOut->addWikiTextTitleTidy(
+                               $this->context->getOutput()->addWikiTextTitleTidy(
                                        '<div class="mw-editintro">{{:' . $title->getFullText() . '}}</div>',
                                        $this->mTitle
                                );
@@ -2493,7 +2510,7 @@ class EditPage {
         * content.
         *
         * @param string|null|bool $text Text to unserialize
-        * @return Content The content object created from $text. If $text was false
+        * @return Content|bool|null The content object created from $text. If $text was false
         *   or null, false resp. null will be  returned instead.
         *
         * @throws MWException If unserializing the text results in a Content
@@ -2525,8 +2542,6 @@ class EditPage {
         * use the EditPage::showEditForm:fields hook instead.
         */
        function showEditForm( $formCallback = null ) {
-               global $wgOut, $wgUser;
-
                # need to parse the preview early so that we know which templates are used,
                # otherwise users with "show preview after edit box" will get a blank list
                # we parse this near the beginning so that setHeaders can do the title
@@ -2536,7 +2551,8 @@ class EditPage {
                        $previewOutput = $this->getPreviewText();
                }
 
-               Hooks::run( 'EditPage::showEditForm:initial', [ &$this, &$wgOut ] );
+               $out = $this->context->getOutput();
+               Hooks::run( 'EditPage::showEditForm:initial', [ &$this, &$out ] );
 
                $this->setHeaders();
 
@@ -2544,13 +2560,14 @@ class EditPage {
                        return;
                }
 
-               $wgOut->addHTML( $this->editFormPageTop );
+               $out->addHTML( $this->editFormPageTop );
 
-               if ( $wgUser->getOption( 'previewontop' ) ) {
+               $user = $this->context->getUser();
+               if ( $user->getOption( 'previewontop' ) ) {
                        $this->displayPreviewArea( $previewOutput, true );
                }
 
-               $wgOut->addHTML( $this->editFormTextTop );
+               $out->addHTML( $this->editFormTextTop );
 
                $showToolbar = true;
                if ( $this->wasDeletedSinceLastEdit() ) {
@@ -2559,14 +2576,14 @@ class EditPage {
                                // Add an confirmation checkbox and explanation.
                                $showToolbar = false;
                        } else {
-                               $wgOut->wrapWikiMsg( "<div class='error mw-deleted-while-editing'>\n$1\n</div>",
+                               $out->wrapWikiMsg( "<div class='error mw-deleted-while-editing'>\n$1\n</div>",
                                        'deletedwhileediting' );
                        }
                }
 
                // @todo add EditForm plugin interface and use it here!
                //       search for textarea1 and textares2, and allow EditForm to override all uses.
-               $wgOut->addHTML( Html::openElement(
+               $out->addHTML( Html::openElement(
                        'form',
                        [
                                'id' => self::EDITFORM_ID,
@@ -2579,11 +2596,11 @@ class EditPage {
 
                if ( is_callable( $formCallback ) ) {
                        wfWarn( 'The $formCallback parameter to ' . __METHOD__ . 'is deprecated' );
-                       call_user_func_array( $formCallback, [ &$wgOut ] );
+                       call_user_func_array( $formCallback, [ &$out ] );
                }
 
                // Add an empty field to trip up spambots
-               $wgOut->addHTML(
+               $out->addHTML(
                        Xml::openElement( 'div', [ 'id' => 'antispam-container', 'style' => 'display: none;' ] )
                        . Html::rawElement(
                                'label',
@@ -2602,7 +2619,7 @@ class EditPage {
                        . Xml::closeElement( 'div' )
                );
 
-               Hooks::run( 'EditPage::showEditForm:fields', [ &$this, &$wgOut ] );
+               Hooks::run( 'EditPage::showEditForm:fields', [ &$this, &$out ] );
 
                // Put these up at the top to ensure they aren't lost on early form submission
                $this->showFormBeforeText();
@@ -2616,7 +2633,7 @@ class EditPage {
                        $key = $comment === ''
                                ? 'confirmrecreate-noreason'
                                : 'confirmrecreate';
-                       $wgOut->addHTML(
+                       $out->addHTML(
                                '<div class="mw-confirm-recreate">' .
                                        wfMessage( $key, $username, "<nowiki>$comment</nowiki>" )->parse() .
                                Xml::checkLabel( wfMessage( 'recreate' )->text(), 'wpRecreate', 'wpRecreate', false,
@@ -2628,7 +2645,7 @@ class EditPage {
 
                # When the summary is hidden, also hide them on preview/show changes
                if ( $this->nosummary ) {
-                       $wgOut->addHTML( Html::hidden( 'nosummary', true ) );
+                       $out->addHTML( Html::hidden( 'nosummary', true ) );
                }
 
                # If a blank edit summary was previously provided, and the appropriate
@@ -2639,15 +2656,15 @@ class EditPage {
                # For a bit more sophisticated detection of blank summaries, hash the
                # automatic one and pass that in the hidden field wpAutoSummary.
                if ( $this->missingSummary || ( $this->section == 'new' && $this->nosummary ) ) {
-                       $wgOut->addHTML( Html::hidden( 'wpIgnoreBlankSummary', true ) );
+                       $out->addHTML( Html::hidden( 'wpIgnoreBlankSummary', true ) );
                }
 
                if ( $this->undidRev ) {
-                       $wgOut->addHTML( Html::hidden( 'wpUndidRevision', $this->undidRev ) );
+                       $out->addHTML( Html::hidden( 'wpUndidRevision', $this->undidRev ) );
                }
 
                if ( $this->selfRedirect ) {
-                       $wgOut->addHTML( Html::hidden( 'wpIgnoreSelfRedirect', true ) );
+                       $out->addHTML( Html::hidden( 'wpIgnoreSelfRedirect', true ) );
                }
 
                if ( $this->hasPresetSummary ) {
@@ -2658,27 +2675,27 @@ class EditPage {
                }
 
                $autosumm = $this->autoSumm ? $this->autoSumm : md5( $this->summary );
-               $wgOut->addHTML( Html::hidden( 'wpAutoSummary', $autosumm ) );
+               $out->addHTML( Html::hidden( 'wpAutoSummary', $autosumm ) );
 
-               $wgOut->addHTML( Html::hidden( 'oldid', $this->oldid ) );
-               $wgOut->addHTML( Html::hidden( 'parentRevId', $this->getParentRevId() ) );
+               $out->addHTML( Html::hidden( 'oldid', $this->oldid ) );
+               $out->addHTML( Html::hidden( 'parentRevId', $this->getParentRevId() ) );
 
-               $wgOut->addHTML( Html::hidden( 'format', $this->contentFormat ) );
-               $wgOut->addHTML( Html::hidden( 'model', $this->contentModel ) );
+               $out->addHTML( Html::hidden( 'format', $this->contentFormat ) );
+               $out->addHTML( Html::hidden( 'model', $this->contentModel ) );
 
                if ( $this->section == 'new' ) {
                        $this->showSummaryInput( true, $this->summary );
-                       $wgOut->addHTML( $this->getSummaryPreview( true, $this->summary ) );
+                       $out->addHTML( $this->getSummaryPreview( true, $this->summary ) );
                }
 
-               $wgOut->addHTML( $this->editFormTextBeforeContent );
+               $out->addHTML( $this->editFormTextBeforeContent );
 
-               if ( !$this->isCssJsSubpage && $showToolbar && $wgUser->getOption( 'showtoolbar' ) ) {
-                       $wgOut->addHTML( EditPage::getEditToolbar( $this->mTitle ) );
+               if ( !$this->isCssJsSubpage && $showToolbar && $user->getOption( 'showtoolbar' ) ) {
+                       $out->addHTML( EditPage::getEditToolbar( $this->mTitle ) );
                }
 
                if ( $this->blankArticle ) {
-                       $wgOut->addHTML( Html::hidden( 'wpIgnoreBlankArticle', true ) );
+                       $out->addHTML( Html::hidden( 'wpIgnoreBlankArticle', true ) );
                }
 
                if ( $this->isConflict ) {
@@ -2696,7 +2713,7 @@ class EditPage {
                        $this->showContentForm();
                }
 
-               $wgOut->addHTML( $this->editFormTextAfterContent );
+               $out->addHTML( $this->editFormTextAfterContent );
 
                $this->showStandardInputs();
 
@@ -2706,19 +2723,19 @@ class EditPage {
 
                $this->showEditTools();
 
-               $wgOut->addHTML( $this->editFormTextAfterTools . "\n" );
+               $out->addHTML( $this->editFormTextAfterTools . "\n" );
 
-               $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'templatesUsed' ],
+               $out->addHTML( Html::rawElement( 'div', [ 'class' => 'templatesUsed' ],
                        Linker::formatTemplates( $this->getTemplates(), $this->preview, $this->section != '' ) ) );
 
-               $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'hiddencats' ],
+               $out->addHTML( Html::rawElement( 'div', [ 'class' => 'hiddencats' ],
                        Linker::formatHiddenCategories( $this->page->getHiddenCategories() ) ) );
 
                if ( $this->mParserOutput ) {
-                       $wgOut->setLimitReportData( $this->mParserOutput->getLimitReportData() );
+                       $out->setLimitReportData( $this->mParserOutput->getLimitReportData() );
                }
 
-               $wgOut->addModules( 'mediawiki.action.edit.collapsibleFooter' );
+               $out->addModules( 'mediawiki.action.edit.collapsibleFooter' );
 
                if ( $this->isConflict ) {
                        try {
@@ -2731,7 +2748,7 @@ class EditPage {
                                        $this->contentFormat,
                                        $ex->getMessage()
                                );
-                               $wgOut->addWikiText( '<div class="error">' . $msg->text() . '</div>' );
+                               $out->addWikiText( '<div class="error">' . $msg->text() . '</div>' );
                        }
                }
 
@@ -2745,14 +2762,14 @@ class EditPage {
                } else {
                        $mode = 'text';
                }
-               $wgOut->addHTML( Html::hidden( 'mode', $mode, [ 'id' => 'mw-edit-mode' ] ) );
+               $out->addHTML( Html::hidden( 'mode', $mode, [ 'id' => 'mw-edit-mode' ] ) );
 
                // Marker for detecting truncated form data.  This must be the last
                // parameter sent in order to be of use, so do not move me.
-               $wgOut->addHTML( Html::hidden( 'wpUltimateParam', true ) );
-               $wgOut->addHTML( $this->editFormTextBottom . "\n</form>\n" );
+               $out->addHTML( Html::hidden( 'wpUltimateParam', true ) );
+               $out->addHTML( $this->editFormTextBottom . "\n</form>\n" );
 
-               if ( !$wgUser->getOption( 'previewontop' ) ) {
+               if ( !$user->getOption( 'previewontop' ) ) {
                        $this->displayPreviewArea( $previewOutput, false );
                }
 
@@ -2778,21 +2795,23 @@ class EditPage {
         * @return bool
         */
        protected function showHeader() {
-               global $wgOut, $wgUser, $wgMaxArticleSize, $wgLang;
-               global $wgAllowUserCss, $wgAllowUserJs;
+               global $wgMaxArticleSize, $wgAllowUserCss, $wgAllowUserJs;
+
+               $out = $this->context->getOutput();
+               $user = $this->context->getUser();
 
                if ( $this->mTitle->isTalkPage() ) {
-                       $wgOut->addWikiMsg( 'talkpagetext' );
+                       $out->addWikiMsg( 'talkpagetext' );
                }
 
                // Add edit notices
                $editNotices = $this->mTitle->getEditNotices( $this->oldid );
                if ( count( $editNotices ) ) {
-                       $wgOut->addHTML( implode( "\n", $editNotices ) );
+                       $out->addHTML( implode( "\n", $editNotices ) );
                } else {
                        $msg = wfMessage( 'editnotice-notext' );
                        if ( !$msg->isDisabled() ) {
-                               $wgOut->addHTML(
+                               $out->addHTML(
                                        '<div class="mw-editnotice-notext">'
                                        . $msg->parseAsBlock()
                                        . '</div>'
@@ -2801,14 +2820,14 @@ class EditPage {
                }
 
                if ( $this->isConflict ) {
-                       $wgOut->wrapWikiMsg( "<div class='mw-explainconflict'>\n$1\n</div>", 'explainconflict' );
+                       $out->wrapWikiMsg( "<div class='mw-explainconflict'>\n$1\n</div>", 'explainconflict' );
                        $this->editRevId = $this->page->getLatest();
                } else {
                        if ( $this->section != '' && !$this->isSectionEditSupported() ) {
                                // We use $this->section to much before this and getVal('wgSection') directly in other places
                                // at this point we can't reset $this->section to '' to fallback to non-section editing.
                                // Someone is welcome to try refactoring though
-                               $wgOut->showErrorPage( 'sectioneditnotsupported-title', 'sectioneditnotsupported-text' );
+                               $out->showErrorPage( 'sectioneditnotsupported-title', 'sectioneditnotsupported-text' );
                                return false;
                        }
 
@@ -2822,31 +2841,31 @@ class EditPage {
                        }
 
                        if ( $this->missingComment ) {
-                               $wgOut->wrapWikiMsg( "<div id='mw-missingcommenttext'>\n$1\n</div>", 'missingcommenttext' );
+                               $out->wrapWikiMsg( "<div id='mw-missingcommenttext'>\n$1\n</div>", 'missingcommenttext' );
                        }
 
                        if ( $this->missingSummary && $this->section != 'new' ) {
-                               $wgOut->wrapWikiMsg( "<div id='mw-missingsummary'>\n$1\n</div>", 'missingsummary' );
+                               $out->wrapWikiMsg( "<div id='mw-missingsummary'>\n$1\n</div>", 'missingsummary' );
                        }
 
                        if ( $this->missingSummary && $this->section == 'new' ) {
-                               $wgOut->wrapWikiMsg( "<div id='mw-missingcommentheader'>\n$1\n</div>", 'missingcommentheader' );
+                               $out->wrapWikiMsg( "<div id='mw-missingcommentheader'>\n$1\n</div>", 'missingcommentheader' );
                        }
 
                        if ( $this->blankArticle ) {
-                               $wgOut->wrapWikiMsg( "<div id='mw-blankarticle'>\n$1\n</div>", 'blankarticle' );
+                               $out->wrapWikiMsg( "<div id='mw-blankarticle'>\n$1\n</div>", 'blankarticle' );
                        }
 
                        if ( $this->selfRedirect ) {
-                               $wgOut->wrapWikiMsg( "<div id='mw-selfredirect'>\n$1\n</div>", 'selfredirect' );
+                               $out->wrapWikiMsg( "<div id='mw-selfredirect'>\n$1\n</div>", 'selfredirect' );
                        }
 
                        if ( $this->hookError !== '' ) {
-                               $wgOut->addWikiText( $this->hookError );
+                               $out->addWikiText( $this->hookError );
                        }
 
                        if ( !$this->checkUnicodeCompliantBrowser() ) {
-                               $wgOut->addWikiMsg( 'nonunicodebrowser' );
+                               $out->addWikiMsg( 'nonunicodebrowser' );
                        }
 
                        if ( $this->section != 'new' ) {
@@ -2854,13 +2873,13 @@ class EditPage {
                                if ( $revision ) {
                                        // Let sysop know that this will make private content public if saved
 
-                                       if ( !$revision->userCan( Revision::DELETED_TEXT, $wgUser ) ) {
-                                               $wgOut->wrapWikiMsg(
+                                       if ( !$revision->userCan( Revision::DELETED_TEXT, $user ) ) {
+                                               $out->wrapWikiMsg(
                                                        "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
                                                        'rev-deleted-text-permission'
                                                );
                                        } elseif ( $revision->isDeleted( Revision::DELETED_TEXT ) ) {
-                                               $wgOut->wrapWikiMsg(
+                                               $out->wrapWikiMsg(
                                                        "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
                                                        'rev-deleted-text-view'
                                                );
@@ -2868,25 +2887,25 @@ class EditPage {
 
                                        if ( !$revision->isCurrent() ) {
                                                $this->mArticle->setOldSubtitle( $revision->getId() );
-                                               $wgOut->addWikiMsg( 'editingold' );
+                                               $out->addWikiMsg( 'editingold' );
                                        }
                                } elseif ( $this->mTitle->exists() ) {
                                        // Something went wrong
 
-                                       $wgOut->wrapWikiMsg( "<div class='errorbox'>\n$1\n</div>\n",
+                                       $out->wrapWikiMsg( "<div class='errorbox'>\n$1\n</div>\n",
                                                [ 'missing-revision', $this->oldid ] );
                                }
                        }
                }
 
                if ( wfReadOnly() ) {
-                       $wgOut->wrapWikiMsg(
+                       $out->wrapWikiMsg(
                                "<div id=\"mw-read-only-warning\">\n$1\n</div>",
                                [ 'readonlywarning', wfReadOnlyReason() ]
                        );
-               } elseif ( $wgUser->isAnon() ) {
+               } elseif ( $user->isAnon() ) {
                        if ( $this->formtype != 'preview' ) {
-                               $wgOut->wrapWikiMsg(
+                               $out->wrapWikiMsg(
                                        "<div id='mw-anon-edit-warning' class='warningbox'>\n$1\n</div>",
                                        [ 'anoneditwarning',
                                                // Log-in link
@@ -2900,7 +2919,7 @@ class EditPage {
                                        ]
                                );
                        } else {
-                               $wgOut->wrapWikiMsg( "<div id=\"mw-anon-preview-warning\" class=\"warningbox\">\n$1</div>",
+                               $out->wrapWikiMsg( "<div id=\"mw-anon-preview-warning\" class=\"warningbox\">\n$1</div>",
                                        'anonpreviewwarning'
                                );
                        }
@@ -2908,22 +2927,25 @@ class EditPage {
                        if ( $this->isCssJsSubpage ) {
                                # Check the skin exists
                                if ( $this->isWrongCaseCssJsPage ) {
-                                       $wgOut->wrapWikiMsg(
+                                       $out->wrapWikiMsg(
                                                "<div class='error' id='mw-userinvalidcssjstitle'>\n$1\n</div>",
                                                [ 'userinvalidcssjstitle', $this->mTitle->getSkinFromCssJsSubpage() ]
                                        );
                                }
-                               if ( $this->getTitle()->isSubpageOf( $wgUser->getUserPage() ) ) {
+                               if ( $this->getTitle()->isSubpageOf( $user->getUserPage() ) ) {
+                                       $out->wrapWikiMsg( '<div class="mw-usercssjspublic">$1</div>',
+                                               $this->isCssSubpage ? 'usercssispublic' : 'userjsispublic'
+                                       );
                                        if ( $this->formtype !== 'preview' ) {
                                                if ( $this->isCssSubpage && $wgAllowUserCss ) {
-                                                       $wgOut->wrapWikiMsg(
+                                                       $out->wrapWikiMsg(
                                                                "<div id='mw-usercssyoucanpreview'>\n$1\n</div>",
                                                                [ 'usercssyoucanpreview' ]
                                                        );
                                                }
 
                                                if ( $this->isJsSubpage && $wgAllowUserJs ) {
-                                                       $wgOut->wrapWikiMsg(
+                                                       $out->wrapWikiMsg(
                                                                "<div id='mw-userjsyoucanpreview'>\n$1\n</div>",
                                                                [ 'userjsyoucanpreview' ]
                                                        );
@@ -2943,7 +2965,7 @@ class EditPage {
                                # Then it must be protected based on static groups (regular)
                                $noticeMsg = 'protectedpagewarning';
                        }
-                       LogEventsList::showLogExtract( $wgOut, 'protect', $this->mTitle, '',
+                       LogEventsList::showLogExtract( $out, 'protect', $this->mTitle, '',
                                [ 'lim' => 1, 'msgKey' => [ $noticeMsg ] ] );
                }
                if ( $this->mTitle->isCascadeProtected() ) {
@@ -2959,10 +2981,10 @@ class EditPage {
                                }
                        }
                        $notice .= '</div>';
-                       $wgOut->wrapWikiMsg( $notice, [ 'cascadeprotectedwarning', $cascadeSourcesCount ] );
+                       $out->wrapWikiMsg( $notice, [ 'cascadeprotectedwarning', $cascadeSourcesCount ] );
                }
                if ( !$this->mTitle->exists() && $this->mTitle->getRestrictions( 'create' ) ) {
-                       LogEventsList::showLogExtract( $wgOut, 'protect', $this->mTitle, '',
+                       LogEventsList::showLogExtract( $out, 'protect', $this->mTitle, '',
                                [ 'lim' => 1,
                                        'showIfEmpty' => false,
                                        'msgKey' => [ 'titleprotectedwarning' ],
@@ -2973,20 +2995,21 @@ class EditPage {
                        $this->contentLength = strlen( $this->textbox1 );
                }
 
+               $lang = $this->context->getLanguage();
                if ( $this->tooBig || $this->contentLength > $wgMaxArticleSize * 1024 ) {
-                       $wgOut->wrapWikiMsg( "<div class='error' id='mw-edit-longpageerror'>\n$1\n</div>",
+                       $out->wrapWikiMsg( "<div class='error' id='mw-edit-longpageerror'>\n$1\n</div>",
                                [
                                        'longpageerror',
-                                       $wgLang->formatNum( round( $this->contentLength / 1024, 3 ) ),
-                                       $wgLang->formatNum( $wgMaxArticleSize )
+                                       $lang->formatNum( round( $this->contentLength / 1024, 3 ) ),
+                                       $lang->formatNum( $wgMaxArticleSize )
                                ]
                        );
                } else {
                        if ( !wfMessage( 'longpage-hint' )->isDisabled() ) {
-                               $wgOut->wrapWikiMsg( "<div id='mw-edit-longpage-hint'>\n$1\n</div>",
+                               $out->wrapWikiMsg( "<div id='mw-edit-longpage-hint'>\n$1\n</div>",
                                        [
                                                'longpage-hint',
-                                               $wgLang->formatSize( strlen( $this->textbox1 ) ),
+                                               $lang->formatSize( strlen( $this->textbox1 ) ),
                                                strlen( $this->textbox1 )
                                        ]
                                );
@@ -3051,7 +3074,6 @@ class EditPage {
         * @param string $summary The text of the summary to display
         */
        protected function showSummaryInput( $isSubjectPreview, $summary = "" ) {
-               global $wgOut;
                # Add a class if 'missingsummary' is triggered to allow styling of the summary line
                $summaryClass = $this->missingSummary ? 'mw-summarymissed' : 'mw-summary';
                if ( $isSubjectPreview ) {
@@ -3070,7 +3092,7 @@ class EditPage {
                        [ 'class' => $summaryClass ],
                        []
                );
-               $wgOut->addHTML( "{$label} {$input}" );
+               $this->context->getOutput()->addHTML( "{$label} {$input}" );
        }
 
        /**
@@ -3102,9 +3124,9 @@ class EditPage {
        }
 
        protected function showFormBeforeText() {
-               global $wgOut;
                $section = htmlspecialchars( $this->section );
-               $wgOut->addHTML( <<<HTML
+               $out = $this->context->getOutput();
+               $out->addHTML( <<<HTML
 <input type='hidden' value="{$section}" name="wpSection"/>
 <input type='hidden' value="{$this->starttime}" name="wpStarttime" />
 <input type='hidden' value="{$this->edittime}" name="wpEdittime" />
@@ -3114,12 +3136,11 @@ class EditPage {
 HTML
                );
                if ( !$this->checkUnicodeCompliantBrowser() ) {
-                       $wgOut->addHTML( Html::hidden( 'safemode', '1' ) );
+                       $out->addHTML( Html::hidden( 'safemode', '1' ) );
                }
        }
 
        protected function showFormAfterText() {
-               global $wgOut, $wgUser;
                /**
                 * To make it harder for someone to slip a user a page
                 * which submits an edit form to the wiki without their
@@ -3132,7 +3153,10 @@ HTML
                 * include the constant suffix to prevent editing from
                 * broken text-mangling proxies.
                 */
-               $wgOut->addHTML( "\n" . Html::hidden( "wpEditToken", $wgUser->getEditToken() ) . "\n" );
+               $token = $this->context->getUser()->getEditToken();
+               $this->context->getOutput()->addHTML(
+                       "\n" . Html::hidden( "wpEditToken", $token ) . "\n"
+               );
        }
 
        /**
@@ -3202,8 +3226,6 @@ HTML
        }
 
        protected function showTextbox( $text, $name, $customAttribs = [] ) {
-               global $wgOut, $wgUser;
-
                $wikitext = $this->safeUnicodeOutput( $text );
                if ( strval( $wikitext ) !== '' ) {
                        // Ensure there's a newline at the end, otherwise adding lines
@@ -3213,11 +3235,12 @@ HTML
                        $wikitext .= "\n";
                }
 
+               $user = $this->context->getUser();
                $attribs = $customAttribs + [
                        'accesskey' => ',',
                        'id' => $name,
-                       'cols' => $wgUser->getIntOption( 'cols' ),
-                       'rows' => $wgUser->getIntOption( 'rows' ),
+                       'cols' => $user->getIntOption( 'cols' ),
+                       'rows' => $user->getIntOption( 'rows' ),
                        // Avoid PHP notices when appending preferences
                        // (appending allows customAttribs['style'] to still work).
                        'style' => ''
@@ -3227,11 +3250,10 @@ HTML
                $attribs['lang'] = $pageLang->getHtmlCode();
                $attribs['dir'] = $pageLang->getDir();
 
-               $wgOut->addHTML( Html::textarea( $name, $wikitext, $attribs ) );
+               $this->context->getOutput()->addHTML( Html::textarea( $name, $wikitext, $attribs ) );
        }
 
        protected function displayPreviewArea( $previewOutput, $isOnTop = false ) {
-               global $wgOut;
                $classes = [];
                if ( $isOnTop ) {
                        $classes[] = 'ontop';
@@ -3243,7 +3265,8 @@ HTML
                        $attribs['style'] = 'display: none;';
                }
 
-               $wgOut->addHTML( Xml::openElement( 'div', $attribs ) );
+               $out = $this->context->getOutput();
+               $out->addHTML( Xml::openElement( 'div', $attribs ) );
 
                if ( $this->formtype == 'preview' ) {
                        $this->showPreview( $previewOutput );
@@ -3252,10 +3275,10 @@ HTML
                        $pageViewLang = $this->mTitle->getPageViewLanguage();
                        $attribs = [ 'lang' => $pageViewLang->getHtmlCode(), 'dir' => $pageViewLang->getDir(),
                                'class' => 'mw-content-' . $pageViewLang->getDir() ];
-                       $wgOut->addHTML( Html::rawElement( 'div', $attribs ) );
+                       $out->addHTML( Html::rawElement( 'div', $attribs ) );
                }
 
-               $wgOut->addHTML( '</div>' );
+               $out->addHTML( '</div>' );
 
                if ( $this->formtype == 'diff' ) {
                        try {
@@ -3267,7 +3290,7 @@ HTML
                                        $this->contentFormat,
                                        $ex->getMessage()
                                );
-                               $wgOut->addWikiText( '<div class="error">' . $msg->text() . '</div>' );
+                               $out->addWikiText( '<div class="error">' . $msg->text() . '</div>' );
                        }
                }
        }
@@ -3279,14 +3302,14 @@ HTML
         * @param string $text The HTML to be output for the preview.
         */
        protected function showPreview( $text ) {
-               global $wgOut;
                if ( $this->mTitle->getNamespace() == NS_CATEGORY ) {
                        $this->mArticle->openShowCategory();
                }
+               $out = $this->context->getOutput();
                # This hook seems slightly odd here, but makes things more
                # consistent for extensions.
-               Hooks::run( 'OutputPageBeforeHTML', [ &$wgOut, &$text ] );
-               $wgOut->addHTML( $text );
+               Hooks::run( 'OutputPageBeforeHTML', [ &$out, &$text ] );
+               $out->addHTML( $text );
                if ( $this->mTitle->getNamespace() == NS_CATEGORY ) {
                        $this->mArticle->closeShowCategory();
                }
@@ -3300,7 +3323,7 @@ HTML
         * save and then make a comparison.
         */
        function showDiff() {
-               global $wgUser, $wgContLang, $wgOut;
+               global $wgContLang;
 
                $oldtitlemsg = 'currentrev';
                # if message does not exist, show diff against the preloaded default
@@ -3331,8 +3354,9 @@ HTML
                        ContentHandler::runLegacyHooks( 'EditPageGetDiffText', [ $this, &$newContent ] );
                        Hooks::run( 'EditPageGetDiffContent', [ $this, &$newContent ] );
 
-                       $popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
-                       $newContent = $newContent->preSaveTransform( $this->mTitle, $wgUser, $popts );
+                       $user = $this->context->getUser();
+                       $popts = ParserOptions::newFromUserAndLang( $user, $wgContLang );
+                       $newContent = $newContent->preSaveTransform( $this->mTitle, $user, $popts );
                }
 
                if ( ( $oldContent && !$oldContent->isEmpty() ) || ( $newContent && !$newContent->isEmpty() ) ) {
@@ -3356,7 +3380,7 @@ HTML
                        $difftext = '';
                }
 
-               $wgOut->addHTML( '<div id="wikiDiff">' . $difftext . '</div>' );
+               $this->context->getOutput()->addHTML( '<div id="wikiDiff">' . $difftext . '</div>' );
        }
 
        /**
@@ -3365,8 +3389,7 @@ HTML
        protected function showHeaderCopyrightWarning() {
                $msg = 'editpage-head-copy-warn';
                if ( !wfMessage( $msg )->isDisabled() ) {
-                       global $wgOut;
-                       $wgOut->wrapWikiMsg( "<div class='editpage-head-copywarn'>\n$1\n</div>",
+                       $this->context->getOutput()->wrapWikiMsg( "<div class='editpage-head-copywarn'>\n$1\n</div>",
                                'editpage-head-copy-warn' );
                }
        }
@@ -3383,16 +3406,15 @@ HTML
                $msg = 'editpage-tos-summary';
                Hooks::run( 'EditPageTosSummary', [ $this->mTitle, &$msg ] );
                if ( !wfMessage( $msg )->isDisabled() ) {
-                       global $wgOut;
-                       $wgOut->addHTML( '<div class="mw-tos-summary">' );
-                       $wgOut->addWikiMsg( $msg );
-                       $wgOut->addHTML( '</div>' );
+                       $out = $this->context->getOutput();
+                       $out->addHTML( '<div class="mw-tos-summary">' );
+                       $out->addWikiMsg( $msg );
+                       $out->addHTML( '</div>' );
                }
        }
 
        protected function showEditTools() {
-               global $wgOut;
-               $wgOut->addHTML( '<div class="mw-editTools">' .
+               $this->context->getOutput()->addHTML( '<div class="mw-editTools">' .
                        wfMessage( 'edittools' )->inContentLanguage()->parse() .
                        '</div>' );
        }
@@ -3452,24 +3474,24 @@ HTML
        }
 
        protected function showStandardInputs( &$tabindex = 2 ) {
-               global $wgOut;
-               $wgOut->addHTML( "<div class='editOptions'>\n" );
+               $out = $this->context->getOutput();
+               $out->addHTML( "<div class='editOptions'>\n" );
 
                if ( $this->section != 'new' ) {
                        $this->showSummaryInput( false, $this->summary );
-                       $wgOut->addHTML( $this->getSummaryPreview( false, $this->summary ) );
+                       $out->addHTML( $this->getSummaryPreview( false, $this->summary ) );
                }
 
                $checkboxes = $this->getCheckboxes( $tabindex,
                        [ 'minor' => $this->minoredit, 'watch' => $this->watchthis ] );
-               $wgOut->addHTML( "<div class='editCheckboxes'>" . implode( $checkboxes, "\n" ) . "</div>\n" );
+               $out->addHTML( "<div class='editCheckboxes'>" . implode( $checkboxes, "\n" ) . "</div>\n" );
 
                // Show copyright warning.
-               $wgOut->addWikiText( $this->getCopywarn() );
-               $wgOut->addHTML( $this->editFormTextAfterWarn );
+               $out->addWikiText( $this->getCopywarn() );
+               $out->addHTML( $this->editFormTextAfterWarn );
 
-               $wgOut->addHTML( "<div class='editButtons'>\n" );
-               $wgOut->addHTML( implode( $this->getEditButtons( $tabindex ), "\n" ) . "\n" );
+               $out->addHTML( "<div class='editButtons'>\n" );
+               $out->addHTML( implode( $this->getEditButtons( $tabindex ), "\n" ) . "\n" );
 
                $cancel = $this->getCancelLink();
                if ( $cancel !== '' ) {
@@ -3489,13 +3511,13 @@ HTML
                        wfMessage( 'word-separator' )->escaped() .
                        wfMessage( 'newwindow' )->parse();
 
-               $wgOut->addHTML( "      <span class='cancelLink'>{$cancel}</span>\n" );
-               $wgOut->addHTML( "      <span class='editHelp'>{$edithelp}</span>\n" );
-               $wgOut->addHTML( "</div><!-- editButtons -->\n" );
+               $out->addHTML( "        <span class='cancelLink'>{$cancel}</span>\n" );
+               $out->addHTML( "        <span class='editHelp'>{$edithelp}</span>\n" );
+               $out->addHTML( "</div><!-- editButtons -->\n" );
 
-               Hooks::run( 'EditPage::showStandardInputs:options', [ $this, $wgOut, &$tabindex ] );
+               Hooks::run( 'EditPage::showStandardInputs:options', [ $this, $out, &$tabindex ] );
 
-               $wgOut->addHTML( "</div><!-- editOptions -->\n" );
+               $out->addHTML( "</div><!-- editOptions -->\n" );
        }
 
        /**
@@ -3503,10 +3525,9 @@ HTML
         * If you want to use another entry point to this function, be careful.
         */
        protected function showConflict() {
-               global $wgOut;
-
-               if ( Hooks::run( 'EditPageBeforeConflictDiff', [ &$this, &$wgOut ] ) ) {
-                       $stats = $wgOut->getContext()->getStats();
+               $out = $this->context->getOutput();
+               if ( Hooks::run( 'EditPageBeforeConflictDiff', [ &$this, &$out ] ) ) {
+                       $stats = $this->context->getStats();
                        $stats->increment( 'edit.failures.conflict' );
                        // Only include 'standard' namespaces to avoid creating unknown numbers of statsd metrics
                        if (
@@ -3516,7 +3537,7 @@ HTML
                                $stats->increment( 'edit.failures.conflict.byNamespaceId.' . $this->mTitle->getNamespace() );
                        }
 
-                       $wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
+                       $out->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
 
                        $content1 = $this->toEditContent( $this->textbox1 );
                        $content2 = $this->toEditContent( $this->textbox2 );
@@ -3529,7 +3550,7 @@ HTML
                                wfMessage( 'storedversion' )->text()
                        );
 
-                       $wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourtext" );
+                       $out->wrapWikiMsg( '<h2>$1</h2>', "yourtext" );
                        $this->showTextbox2();
                }
        }
@@ -3642,10 +3663,10 @@ HTML
         * @return string
         */
        function getPreviewText() {
-               global $wgOut, $wgRawHtml, $wgLang;
-               global $wgAllowUserCss, $wgAllowUserJs;
+               global $wgRawHtml, $wgAllowUserCss, $wgAllowUserJs;
 
-               $stats = $wgOut->getContext()->getStats();
+               $stats = $this->context->getStats();
+               $out = $this->context->getOutput();
 
                if ( $wgRawHtml && !$this->mTokenOk ) {
                        // Could be an offsite preview attempt. This is very unsafe if
@@ -3655,7 +3676,7 @@ HTML
                                // Do not put big scary notice, if previewing the empty
                                // string, which happens when you initially edit
                                // a category page, due to automatic preview-on-open.
-                               $parsedNote = $wgOut->parse( "<div class='previewnote'>" .
+                               $parsedNote = $out->parse( "<div class='previewnote'>" .
                                        wfMessage( 'session_fail_preview_html' )->text() . "</div>", true, /* interface */true );
                        }
                        $stats->increment( 'edit.failures.session_loss' );
@@ -3677,7 +3698,7 @@ HTML
 
                        # provide a anchor link to the editform
                        $continueEditing = '<span class="mw-continue-editing">' .
-                               '[[#' . self::EDITFORM_ID . '|' . $wgLang->getArrow() . ' ' .
+                               '[[#' . self::EDITFORM_ID . '|' . $this->context->getLanguage()->getArrow() . ' ' .
                                wfMessage( 'continue-editing' )->text() . ']]</span>';
                        if ( $this->mTriedSave && !$this->mTokenOk ) {
                                if ( $this->mTokenOkExceptSuffix ) {
@@ -3743,7 +3764,7 @@ HTML
                        $parserOutput = $parserResult['parserOutput'];
                        $previewHTML = $parserResult['html'];
                        $this->mParserOutput = $parserOutput;
-                       $wgOut->addParserOutputMetadata( $parserOutput );
+                       $out->addParserOutputMetadata( $parserOutput );
 
                        if ( count( $parserOutput->getWarnings() ) ) {
                                $note .= "\n\n" . implode( "\n\n", $parserOutput->getWarnings() );
@@ -3769,7 +3790,7 @@ HTML
 
                $previewhead = "<div class='previewnote'>\n" .
                        '<h2 id="mw-previewheader">' . wfMessage( 'preview' )->escaped() . "</h2>" .
-                       $wgOut->parse( $note, true, /* interface */true ) . $conflict . "</div>\n";
+                       $out->parse( $note, true, /* interface */true ) . $conflict . "</div>\n";
 
                $pageViewLang = $this->mTitle->getPageViewLanguage();
                $attribs = [ 'lang' => $pageViewLang->getHtmlCode(), 'dir' => $pageViewLang->getDir(),
@@ -3784,7 +3805,7 @@ HTML
         * @return ParserOptions
         */
        protected function getPreviewParserOptions() {
-               $parserOptions = $this->page->makeParserOptions( $this->mArticle->getContext() );
+               $parserOptions = $this->page->makeParserOptions( $this->context );
                $parserOptions->setIsPreview( true );
                $parserOptions->setIsSectionPreview( !is_null( $this->section ) && $this->section !== '' );
                $parserOptions->enableLimitReport();
@@ -3795,17 +3816,17 @@ HTML
         * Parse the page for a preview. Subclasses may override this class, in order
         * to parse with different options, or to otherwise modify the preview HTML.
         *
-        * @param Content @content The page content
-        * @return Associative array with keys:
+        * @param Content $content The page content
+        * @return array with keys:
         *   - parserOutput: The ParserOutput object
         *   - html: The HTML to be displayed
         */
        protected function doPreviewParse( Content $content ) {
-               global $wgUser;
+               $user = $this->context->getUser();
                $parserOptions = $this->getPreviewParserOptions();
-               $pstContent = $content->preSaveTransform( $this->mTitle, $wgUser, $parserOptions );
+               $pstContent = $content->preSaveTransform( $this->mTitle, $user, $parserOptions );
                $scopedCallback = $parserOptions->setupFakeRevision(
-                       $this->mTitle, $pstContent, $wgUser );
+                       $this->mTitle, $pstContent, $user );
                $parserOutput = $pstContent->getParserOutput( $this->mTitle, null, $parserOptions );
                ScopedCallback::consume( $scopedCallback );
                $parserOutput->setEditSectionTokens( false ); // no section edit links
@@ -3981,15 +4002,16 @@ HTML
         * @return array
         */
        public function getCheckboxes( &$tabindex, $checked ) {
-               global $wgUser, $wgUseMediaWikiUIEverywhere;
+               global $wgUseMediaWikiUIEverywhere;
 
                $checkboxes = [];
+               $user = $this->context->getUser();
 
                // don't show the minor edit checkbox if it's a new page or section
                if ( !$this->isNew ) {
                        $checkboxes['minor'] = '';
                        $minorLabel = wfMessage( 'minoredit' )->parse();
-                       if ( $wgUser->isAllowed( 'minoredit' ) ) {
+                       if ( $user->isAllowed( 'minoredit' ) ) {
                                $attribs = [
                                        'tabindex' => ++$tabindex,
                                        'accesskey' => wfMessage( 'accesskey-minoredit' )->text(),
@@ -4013,7 +4035,7 @@ HTML
 
                $watchLabel = wfMessage( 'watchthis' )->parse();
                $checkboxes['watch'] = '';
-               if ( $wgUser->isLoggedIn() ) {
+               if ( $user->isLoggedIn() ) {
                        $attribs = [
                                'tabindex' => ++$tabindex,
                                'accesskey' => wfMessage( 'accesskey-watch' )->text(),
@@ -4047,13 +4069,19 @@ HTML
        public function getEditButtons( &$tabindex ) {
                $buttons = [];
 
+               $labelAsPublish = $this->mArticle->getContext()->getConfig()->get( 'EditButtonPublishNotSave' );
+               if ( $labelAsPublish ) {
+                       $buttonLabelKey = $this->isNew ? 'publishpage' : 'publishchanges';
+               } else {
+                       $buttonLabelKey = $this->isNew ? 'savearticle' : 'savechanges';
+               }
+               $buttonLabel = wfMessage( $buttonLabelKey )->text();
                $attribs = [
                        'id' => 'wpSave',
                        'name' => 'wpSave',
                        'tabindex' => ++$tabindex,
                ] + Linker::tooltipAndAccesskeyAttribs( 'save' );
-               $buttons['save'] = Html::submitButton( wfMessage( 'savearticle' )->text(),
-                       $attribs, [ 'mw-ui-constructive' ] );
+               $buttons['save'] = Html::submitButton( $buttonLabel, $attribs, [ 'mw-ui-constructive' ] );
 
                ++$tabindex; // use the same for preview and live preview
                $attribs = [
@@ -4082,15 +4110,14 @@ HTML
         * they have attempted to edit a nonexistent section.
         */
        function noSuchSectionPage() {
-               global $wgOut;
-
-               $wgOut->prepareErrorPage( wfMessage( 'nosuchsectiontitle' ) );
+               $out = $this->context->getOutput();
+               $out->prepareErrorPage( wfMessage( 'nosuchsectiontitle' ) );
 
                $res = wfMessage( 'nosuchsectiontext', $this->section )->parseAsBlock();
                Hooks::run( 'EditPageNoSuchSection', [ &$this, &$res ] );
-               $wgOut->addHTML( $res );
+               $out->addHTML( $res );
 
-               $wgOut->returnToMain( false, $this->mTitle );
+               $out->returnToMain( false, $this->mTitle );
        }
 
        /**
@@ -4099,28 +4126,28 @@ HTML
         * @param string|array|bool $match Text (or array of texts) which triggered one or more filters
         */
        public function spamPageWithContent( $match = false ) {
-               global $wgOut, $wgLang;
                $this->textbox2 = $this->textbox1;
 
                if ( is_array( $match ) ) {
-                       $match = $wgLang->listToText( $match );
+                       $match = $this->context->getLanguage()->listToText( $match );
                }
-               $wgOut->prepareErrorPage( wfMessage( 'spamprotectiontitle' ) );
+               $out = $this->context->getOutput();
+               $out->prepareErrorPage( wfMessage( 'spamprotectiontitle' ) );
 
-               $wgOut->addHTML( '<div id="spamprotected">' );
-               $wgOut->addWikiMsg( 'spamprotectiontext' );
+               $out->addHTML( '<div id="spamprotected">' );
+               $out->addWikiMsg( 'spamprotectiontext' );
                if ( $match ) {
-                       $wgOut->addWikiMsg( 'spamprotectionmatch', wfEscapeWikiText( $match ) );
+                       $out->addWikiMsg( 'spamprotectionmatch', wfEscapeWikiText( $match ) );
                }
-               $wgOut->addHTML( '</div>' );
+               $out->addHTML( '</div>' );
 
-               $wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
+               $out->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
                $this->showDiff();
 
-               $wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourtext" );
+               $out->wrapWikiMsg( '<h2>$1</h2>', "yourtext" );
                $this->showTextbox2();
 
-               $wgOut->addReturnTo( $this->getContextTitle(), [ 'action' => 'edit' ] );
+               $out->addReturnTo( $this->getContextTitle(), [ 'action' => 'edit' ] );
        }
 
        /**
@@ -4130,9 +4157,9 @@ HTML
         * @return bool
         */
        private function checkUnicodeCompliantBrowser() {
-               global $wgBrowserBlackList, $wgRequest;
+               global $wgBrowserBlackList;
 
-               $currentbrowser = $wgRequest->getHeader( 'User-Agent' );
+               $currentbrowser = $this->context->getRequest()->getHeader( 'User-Agent' );
                if ( $currentbrowser === false ) {
                        // No User-Agent header sent? Trust it by default...
                        return true;
index 7dac0ec..2a00900 100644 (file)
@@ -286,6 +286,16 @@ class MediaWiki {
                                // may still be a wikipage redirect to another article or URL.
                                $article = $this->initializeArticle();
                                if ( is_object( $article ) ) {
+                                       $url = $request->getFullRequestURL(); // requested URL
+                                       if (
+                                               $request->getMethod() === 'GET' &&
+                                               $url === $article->getTitle()->getCanonicalURL() &&
+                                               $article->checkTouched() &&
+                                               $output->checkLastModified( $article->getTouched() )
+                                       ) {
+                                               wfDebug( __METHOD__ . ": done 304\n" );
+                                               return;
+                                       }
                                        $this->performAction( $article, $requestTitle );
                                } elseif ( is_string( $article ) ) {
                                        $output->redirect( $article );
@@ -803,10 +813,10 @@ class MediaWiki {
         */
        public function triggerJobs() {
                $jobRunRate = $this->config->get( 'JobRunRate' );
-               if ( $jobRunRate <= 0 || wfReadOnly() ) {
-                       return;
-               } elseif ( $this->getTitle()->isSpecial( 'RunJobs' ) ) {
+               if ( $this->getTitle()->isSpecial( 'RunJobs' ) ) {
                        return; // recursion guard
+               } elseif ( $jobRunRate <= 0 || wfReadOnly() ) {
+                       return;
                }
 
                if ( $jobRunRate < 1 ) {
@@ -843,7 +853,7 @@ class MediaWiki {
                        $query, $this->config->get( 'SecretKey' ) );
 
                $errno = $errstr = null;
-               $info = wfParseUrl( $this->config->get( 'Server' ) );
+               $info = wfParseUrl( $this->config->get( 'CanonicalServer' ) );
                MediaWiki\suppressWarnings();
                $host = $info['host'];
                $port = 80;
@@ -872,7 +882,8 @@ class MediaWiki {
                        return;
                }
 
-               $url = wfAppendQuery( wfScript( 'index' ), $query );
+               $special = SpecialPageFactory::getPage( 'RunJobs' );
+               $url = $special->getPageTitle()->getCanonicalURL( $query );
                $req = (
                        "POST $url HTTP/1.1\r\n" .
                        "Host: {$info['host']}\r\n" .
@@ -883,7 +894,7 @@ class MediaWiki {
                $runJobsLogger->info( "Running $n job(s) via '$url'" );
                // Send a cron API request to be performed in the background.
                // Give up if this takes too long to send (which should be rare).
-               stream_set_timeout( $sock, 1 );
+               stream_set_timeout( $sock, 2 );
                $bytes = fwrite( $sock, $req );
                if ( $bytes !== strlen( $req ) ) {
                        $runJobsLogger->error( "Failed to start cron API (socket write error)" );
index ac5fbe0..49891df 100644 (file)
@@ -28,6 +28,7 @@ use WatchedItemQueryService;
 use SkinFactory;
 use TitleFormatter;
 use TitleParser;
+use VirtualRESTServiceClient;
 use MediaWiki\Interwiki\InterwikiLookup;
 
 /**
@@ -571,6 +572,14 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'TitleParser' );
        }
 
+       /**
+        * @since 1.28
+        * @return VirtualRESTServiceClient
+        */
+       public function getVirtualRESTServiceClient() {
+               return $this->getService( 'VirtualRESTServiceClient' );
+       }
+
        ///////////////////////////////////////////////////////////////////////////
        // NOTE: When adding a service getter here, don't forget to add a test
        // case for it in MediaWikiServicesTest::provideGetters() and in
index 852a4ed..c7499b1 100644 (file)
@@ -3096,7 +3096,7 @@ class OutputPage extends ContextSource {
 
                $user = $this->getUser();
 
-               if ( !$this->getUser()->isLoggedIn() ) {
+               if ( !$user->isLoggedIn() ) {
                        // Anons have predictable edit tokens
                        return false;
                }
index dd68102..0039d2b 100644 (file)
@@ -117,6 +117,9 @@ class Pingback {
         *
         * This is public so we can display it in the installer
         *
+        * Developers: If you're adding a new piece of data to this, please ensure
+        * that you update https://www.mediawiki.org/wiki/Manual:$wgPingback
+        *
         * @return array
         */
        public function getSystemInfo() {
index 21c6377..33569e6 100644 (file)
@@ -209,6 +209,24 @@ return [
                return $services->getService( '_MediaWikiTitleCodec' );
        },
 
+       'VirtualRESTServiceClient' => function( MediaWikiServices $services ) {
+               $config = $services->getMainConfig()->get( 'VirtualRestConfig' );
+
+               $vrsClient = new VirtualRESTServiceClient( new MultiHttpClient( [] ) );
+               foreach ( $config['paths'] as $prefix => $serviceConfig ) {
+                       $class = $serviceConfig['class'];
+                       // Merge in the global defaults
+                       $constructArg = isset( $serviceConfig['options'] )
+                               ? $serviceConfig['options']
+                               : [];
+                       $constructArg += $config['global'];
+                       // Make the VRS service available at the mount point
+                       $vrsClient->mount( $prefix, [ 'class' => $class, 'config' => $constructArg ] );
+               }
+
+               return $vrsClient;
+       },
+
        ///////////////////////////////////////////////////////////////////////////
        // NOTE: When adding a service here, don't forget to add a getter function
        // in the MediaWikiServices class. The convenience getter should just call
index f733c47..b8756c5 100644 (file)
        "apihelp-linkaccount-example-link": "Iniciar el proceso de vincular a una cuenta de <kbd>Ejemplo</kbd>.",
        "apihelp-login-description": "Iniciar sesión y obtener las cookies de autenticación.\n\nEsta acción solo se debe utilizar en combinación con [[Special:BotPasswords]]; para la cuenta de inicio de sesión no se utiliza y puede fallar sin previo aviso. Para iniciar la sesión de forma segura a la cuenta principal, utilice <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
        "apihelp-login-description-nobotpasswords": "Iniciar sesión y obtener las cookies de autenticación.\n\nEsta acción esta obsoleta y puede fallar sin previo aviso. Para conectarse de forma segura, utilice <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
-       "apihelp-login-description-nonauthmanager": "Iniciar sesión y obtener cookies de autenticación.\n\nSi inicias sesión sin problemas, las cookies necesarias se incluirán en los encabezados de respuesta HTTP. Si se produce algún error al iniciar sesión y este persiste, se puede regular para evitar los ataques masivos automatizados de adivinar contraseñas.",
        "apihelp-login-param-name": "Nombre de usuario.",
        "apihelp-login-param-password": "Contraseña.",
        "apihelp-login-param-domain": "Dominio (opcional).",
        "apihelp-query+alllinks-example-unique-generator": "Obtiene todos los títulos enlazados, marcando los que falten.",
        "apihelp-query+alllinks-example-generator": "Obtiene páginas que contienen los enlaces.",
        "apihelp-query+allmessages-description": "Devolver los mensajes de este sitio.",
+       "apihelp-query+allmessages-param-messages": "Qué mensajes mostrar. <kbd>*</kbd> (por defecto) significa todos los mensajes.",
        "apihelp-query+allmessages-param-prop": "Qué propiedades se obtendrán.",
+       "apihelp-query+allmessages-param-enableparser": "Establecer para habilitar el analizador, se preprocesará el wikitexto del mensaje (sustitución de palabras mágicas, uso de plantillas, etc.).",
        "apihelp-query+allmessages-param-nocontent": "Si se establece, no incluya el contenido de los mensajes en la salida.",
        "apihelp-query+allmessages-param-args": "Los argumentos que se sustituyen en el mensaje.",
        "apihelp-query+allmessages-param-filter": "Devolver solo mensajes con nombres que contengan esta cadena.",
        "apihelp-query+mystashedfiles-description": "Obtener una lista de archivos en la corriente de carga de usuarios.",
        "apihelp-query+mystashedfiles-param-prop": "Propiedades a buscar para los archivos.",
        "apihelp-query+mystashedfiles-paramvalue-prop-size": "Buscar el tamaño del archivo y las dimensiones de la imagen.",
+       "apihelp-query+mystashedfiles-paramvalue-prop-type": "Obtener el tipo MIME y tipo multimedia del archivo.",
        "apihelp-query+mystashedfiles-param-limit": "Cuántos archivos obtener.",
        "apihelp-query+alltransclusions-param-from": "El título de la transclusión por la que empezar la enumeración.",
        "apihelp-query+alltransclusions-param-to": "El título de la transclusión por la que terminar la enumeración.",
        "apihelp-query+alltransclusions-param-limit": "Número de elementos que se desea obtener.",
        "apihelp-query+alltransclusions-example-unique": "Listar títulos transcluidos de forma única.",
        "apihelp-query+alltransclusions-example-unique-generator": "Obtiene todos los títulos transcluidos, marcando los que faltan.",
+       "apihelp-query+alltransclusions-example-generator": "Obtiene las páginas que contienen las transclusiones.",
        "apihelp-query+allusers-description": "Enumerar todos los usuarios registrados.",
        "apihelp-query+allusers-param-prefix": "Buscar todos los usuarios que empiecen con este valor.",
        "apihelp-query+allusers-param-group": "Incluir solo usuarios en los grupos dados.",
        "apihelp-query+allusers-paramvalue-prop-blockinfo": "Añade información sobre un bloque actual al usuario.",
        "apihelp-query+allusers-paramvalue-prop-groups": "Lista los grupos a los que el usuario pertenece. Esto utiliza más recursos del servidor y puede devolver menos resultados que el límite.",
        "apihelp-query+allusers-paramvalue-prop-rights": "Lista los permisos que tiene el usuario.",
+       "apihelp-query+allusers-paramvalue-prop-editcount": "Añade el número de ediciones del usuario.",
+       "apihelp-query+allusers-paramvalue-prop-registration": "Añade la marca de tiempo del momento en que el usuario se registró, si está disponible (puede estar en blanco).",
        "apihelp-query+allusers-param-limit": "Cuántos nombres de usuario se devolverán.",
        "apihelp-query+allusers-param-activeusers": "Solo listar usuarios activos en {{PLURAL:$1|el último día|los $1 últimos días}}.",
        "apihelp-query+allusers-example-Y": "Listar usuarios que empiecen por <kbd>Y</kbd>.",
        "apihelp-query+filerepoinfo-example-login": "Captura de las solicitudes que puede ser utilizadas al comienzo de inicio de sesión.",
+       "apihelp-query+backlinks-description": "Encuentra todas las páginas que enlazan a la página dada.",
        "apihelp-query+backlinks-param-pageid": "Identificador de página que buscar. No puede usarse junto con <var>$1title</var>",
        "apihelp-query+backlinks-param-filterredir": "Cómo filtrar redirecciones. Si se establece a <kbd>nonredirects</kbd> cuando está activo <var>$1redirect</var>, esto sólo se aplica al segundo nivel.",
        "apihelp-query+backlinks-param-limit": "Cuántas páginas en total se devolverán. Si está activo <var>$1redirect</var>, el límite aplica a cada nivel por separado (lo que significa que se pueden devolver hasta 2 * <var>$1limit</var> resultados).",
        "apihelp-query+blocks-paramvalue-prop-reason": "Añade la razón dada para el bloqueo.",
        "apihelp-query+blocks-example-simple": "Listar bloques.",
        "apihelp-query+categories-param-prop": "Qué propiedades adicionales obtener para cada categoría:",
+       "apihelp-query+categories-paramvalue-prop-timestamp": "Añade la marca de tiempo del momento en que se añadió la categoría.",
        "apihelp-query+categories-param-show": "Qué tipo de categorías mostrar.",
        "apihelp-query+categories-param-limit": "Cuántas categorías se devolverán.",
        "apihelp-query+categories-example-generator": "Obtener información acerca de todas las categorías utilizadas en la página <kbd>Albert Einstein</kbd>.",
        "apihelp-query+categoryinfo-description": "Devuelve información acerca de las categorías dadas.",
        "apihelp-query+categoryinfo-example-simple": "Obtener información acerca de <kbd>Category:Foo</kbd> y <kbd>Category:Bar</kbd>",
+       "apihelp-query+categorymembers-description": "Lista todas las páginas en una categoría dada.",
        "apihelp-query+categorymembers-param-prop": "Qué piezas de información incluir:",
        "apihelp-query+categorymembers-paramvalue-prop-ids": "Añade el identificador de página.",
        "apihelp-query+categorymembers-paramvalue-prop-title": "Agrega el título y el identificador del espacio de nombres de la página.",
        "apihelp-query+categorymembers-paramvalue-prop-type": "Añade el tipo en el que se categorizó la página (<samp>page</samp>, <samp>subcat</samp> or <samp>file</samp>).",
+       "apihelp-query+categorymembers-paramvalue-prop-timestamp": "Añade la marca de tiempo del momento en que se incluyó la página.",
        "apihelp-query+categorymembers-param-sort": "Propiedad por la que realizar la ordenación.",
        "apihelp-query+categorymembers-param-dir": "Dirección en la que desea ordenar.",
        "apihelp-query+categorymembers-param-startsortkey": "Utilizar $1starthexsortkey en su lugar.",
        "apihelp-query+filearchive-param-to": "El título de imagen para detener la enumeración.",
        "apihelp-query+filearchive-param-prefix": "Buscar todos los títulos de las imágenes que comiencen con este valor.",
        "apihelp-query+filearchive-param-prop": "Qué información de imagen se obtendrá:",
+       "apihelp-query+filearchive-paramvalue-prop-timestamp": "Añade la marca de tiempo de la versión subida.",
+       "apihelp-query+filearchive-paramvalue-prop-user": "Agrega el usuario que subió la versión de la imagen.",
        "apihelp-query+filearchive-paramvalue-prop-size": "Agrega el tamaño de la imagen en bytes y la altura, la anchura y el número de páginas (si es aplicable).",
        "apihelp-query+filearchive-paramvalue-prop-dimensions": "Alias del tamaño.",
        "apihelp-query+filearchive-paramvalue-prop-description": "Añade la descripción de la versión de la imagen.",
        "apihelp-query+imageinfo-param-extmetadatafilter": "Si se especifica y no vacío, sólo estas claves serán devueltos por $1prop=extmetadata.",
        "apihelp-query+imageinfo-param-urlparam": "Un controlador específico de la cadena de parámetro. Por ejemplo, los archivos Pdf pueden utilizar <kbd>page15-100px</kbd>. <var>$1urlwidth</var> debe ser utilizado y debe ser consistente con <var>$1urlparam</var>.",
        "apihelp-query+imageinfo-param-localonly": "Buscar solo archivos en el repositorio local.",
+       "apihelp-query+imageinfo-example-simple": "Obtener información sobre la versión actual de [[:File:Albert Einstein Head.jpg]].",
+       "apihelp-query+imageinfo-example-dated": "Obtener información sobre las versiones de [[:File:Test.jpg]] a partir de 2008.",
        "apihelp-query+images-description": "Devuelve todos los archivos contenidos en las páginas dadas.",
        "apihelp-query+images-param-limit": "Cuántos archivos se devolverán.",
        "apihelp-query+images-example-simple": "Obtener una lista de los archivos usados en la [[Main Page|Portada]].",
        "apihelp-query+info-example-protection": "Obtén información general y protección acerca de la página <kbd>Main Page</kbd>.",
        "apihelp-query+iwbacklinks-param-limit": "Cuántas páginas se devolverán.",
        "apihelp-query+iwbacklinks-param-prop": "Qué propiedades se obtendrán:",
+       "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "Añade el título del interwiki.",
        "apihelp-query+iwbacklinks-example-simple": "Obtener las páginas enlazadas a [[wikibooks:Test]]",
+       "apihelp-query+iwlinks-description": "Devuelve todos los enlaces interwiki de las páginas dadas.",
        "apihelp-query+iwlinks-param-prop": "Qué propiedades adicionales obtener para cada enlace interlingüe:",
        "apihelp-query+iwlinks-paramvalue-prop-url": "Añade el URL completo.",
+       "apihelp-query+iwlinks-param-limit": "Cuántos enlaces interwiki se desea devolver.",
+       "apihelp-query+iwlinks-param-prefix": "Devolver únicamente enlaces interwiki con este prefijo.",
        "apihelp-query+langbacklinks-param-lang": "Idioma del enlace de idioma.",
        "apihelp-query+langbacklinks-param-limit": "Cuántas páginas en total se devolverán.",
        "apihelp-query+langbacklinks-param-prop": "Qué propiedades se obtendrán:",
        "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "Añade el título del enlace de idioma.",
        "apihelp-query+langbacklinks-example-simple": "Obtener las páginas enlazadas a [[:fr:Test]]",
        "apihelp-query+langbacklinks-example-generator": "Obtener información acerca de las páginas enlazadas a [[:fr:Test]].",
+       "apihelp-query+langlinks-param-url": "Obtener la URL completa o no (no se puede usar con <var>$1prop</var>).",
        "apihelp-query+langlinks-param-prop": "Qué propiedades adicionales obtener para cada enlace interlingüe:",
        "apihelp-query+langlinks-paramvalue-prop-url": "Añade el URL completo.",
        "apihelp-query+langlinks-paramvalue-prop-autonym": "Añade el nombre del idioma nativo.",
        "apihelp-query+recentchanges-param-excludeuser": "No listar cambios de este usuario.",
        "apihelp-query+recentchanges-param-tag": "Listar solo los cambios con esta etiqueta.",
        "apihelp-query+recentchanges-param-prop": "Incluir piezas adicionales de información:",
+       "apihelp-query+recentchanges-paramvalue-prop-comment": "Añade el comentario de la edición.",
        "apihelp-query+recentchanges-paramvalue-prop-parsedcomment": "Añade el comentario analizado para la edición.",
        "apihelp-query+recentchanges-paramvalue-prop-flags": "Añade marcas para la edición.",
+       "apihelp-query+recentchanges-paramvalue-prop-timestamp": "Añade la marca de tiempo de la edición.",
+       "apihelp-query+recentchanges-paramvalue-prop-title": "Añade el título de la página de la edición.",
+       "apihelp-query+recentchanges-paramvalue-prop-ids": "Añade los códigos ID de la página, de los cambios recientes y de las revisiones antigua y nueva.",
+       "apihelp-query+recentchanges-paramvalue-prop-sizes": "Añade la longitud antigua y la longitud nueva de la página en bytes.",
+       "apihelp-query+recentchanges-paramvalue-prop-redirect": "Etiqueta la edición si la página es una redirección.",
        "apihelp-query+recentchanges-paramvalue-prop-patrolled": "Etiqueta ediciones verificables como verificadas o no verificadas.",
        "apihelp-query+recentchanges-param-token": "Usa <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> en su lugar.",
        "apihelp-query+recentchanges-param-limit": "Cuántos cambios en total se devolverán.",
        "apihelp-query+redirects-paramvalue-prop-pageid": "Identificador de página de cada redirección.",
        "apihelp-query+redirects-paramvalue-prop-title": "Título de cada redirección.",
        "apihelp-query+redirects-paramvalue-prop-fragment": "Fragmento de cada redirección, si los hubiere.",
+       "apihelp-query+redirects-param-namespace": "Incluir solo páginas de estos espacios de nombres.",
        "apihelp-query+redirects-param-limit": "Cuántas redirecciones se devolverán.",
        "apihelp-query+redirects-example-simple": "Mostrar una lista de las redirecciones a la [[Main Page|Portada]]",
+       "apihelp-query+redirects-example-generator": "Obtener información sobre todas las redirecciones a la [[Main Page|Portada]]",
+       "apihelp-query+revisions-param-end": "Enumerar hasta esta marca de tiempo.",
+       "apihelp-query+revisions-param-user": "Incluir solo las revisiones realizadas por el usuario.",
+       "apihelp-query+revisions-param-excludeuser": "Excluir las revisiones realizadas por el usuario.",
        "apihelp-query+revisions-example-last5": "Mostrar las últimas 5 revisiones de la <kbd>Main Page</kbd>.",
        "apihelp-query+revisions+base-param-prop": "Las propiedades que se obtendrán para cada revisión:",
        "apihelp-query+revisions+base-paramvalue-prop-ids": "El identificador de la revisión.",
index 7970800..938c098 100644 (file)
@@ -6,6 +6,7 @@
                ]
        },
        "apihelp-main-param-action": "Kurį veiksmą atlikti.",
+       "apihelp-main-param-curtimestamp": "Prie rezultato pridėti dabartinę laiko žymę.",
        "apihelp-block-description": "Blokuoti vartotoją.",
        "apihelp-block-param-reason": "Blokavimo priežastis.",
        "apihelp-block-param-nocreate": "Neleisti kurti paskyrų.",
        "apihelp-edit-param-text": "Puslapio turinys.",
        "apihelp-edit-param-minor": "Smulkus pakeitimas.",
        "apihelp-edit-param-notminor": "Nesmulkus pakeitimas.",
+       "apihelp-edit-param-createonly": "Neredaguoti puslapio jei jis jau egzistuoja.",
+       "apihelp-edit-param-watch": "Pridėti puslapį į dabartinio vartotojo stebimųjų sąrašą.",
+       "apihelp-edit-param-unwatch": "Pašalinti puslapį iš dabartinio vartotojo stebimųjų sąrašo.",
        "apihelp-edit-param-redirect": "Automatiškai išspręsti peradresavimus.",
        "apihelp-edit-example-edit": "Redaguoti puslapį.",
        "apihelp-emailuser-description": "Siųsti el. laišką naudotojui.",
+       "apihelp-emailuser-param-target": "El. laiško gavėjas.",
        "apihelp-expandtemplates-param-title": "Puslapio pavadinimas.",
+       "apihelp-feedcontributions-param-feedformat": "Srauto formatas.",
+       "apihelp-feedcontributions-param-year": "Nuo metų (ir anksčiau).",
+       "apihelp-feedcontributions-param-month": "Nuo mėnesio (ir anksčiau).",
+       "apihelp-feedcontributions-param-tagfilter": "Filtruoti įnašus, kurie turi šias žymes.",
+       "apihelp-feedcontributions-param-deletedonly": "Rodyti tik ištrintus įnašus.",
+       "apihelp-feedcontributions-param-hideminor": "Slėpti nedidelius pakeitimus.",
+       "apihelp-feedrecentchanges-param-feedformat": "Srauto formatas.",
+       "apihelp-feedrecentchanges-param-from": "Rodyti pakeitimus nuo tada.",
        "apihelp-feedrecentchanges-param-hideminor": "Slėpti smulkius pakeitimus.",
        "apihelp-feedrecentchanges-param-hidebots": "Slėpti robotų pakeitimus.",
        "apihelp-feedrecentchanges-param-hideanons": "Slėpti vartotojų anonimų pakeitimus.",
        "apihelp-feedrecentchanges-param-hideliu": "Slėpti užsiregistravusių vartotojų pakeitimus.",
        "apihelp-feedrecentchanges-param-hidemyself": "Slėpti pakeitimus, atliktus dabartinio vartotojo.",
        "apihelp-feedrecentchanges-param-tagfilter": "Filtruoti pagal žymę.",
+       "apihelp-feedrecentchanges-param-target": "Rodyti tik keitimus puslapiuose, pasiekiamuose iš šio puslapio.",
        "apihelp-feedrecentchanges-example-simple": "Parodyti naujausius keitimus.",
+       "apihelp-feedwatchlist-param-feedformat": "Srauto formatas.",
        "apihelp-filerevert-param-comment": "Įkėlimo komentaras.",
+       "apihelp-help-example-recursive": "Visa pagalba viename puslapyje.",
+       "apihelp-help-example-help": "Pačio pagalbos modulio pagalba.",
+       "apihelp-imagerotate-description": "Pasukti viena ar daugiau paveikslėlių.",
+       "apihelp-imagerotate-param-rotation": "Kiek laipsnių pasukti paveikslėlį pagal laikrodžio rodyklę.",
+       "apihelp-imagerotate-example-generator": "Pasukti visus paveikslėlius <kbd>Category:Flip</kbd> <kbd>180</kbd> laipsnių.",
        "apihelp-import-param-xml": "XML failas įkeltas.",
        "apihelp-login-param-name": "Vartotojo vardas.",
        "apihelp-login-param-password": "Slaptažodis.",
        "apihelp-login-param-domain": "Domenas (neprivaloma).",
+       "apihelp-login-example-login": "Prisijungti.",
+       "apihelp-logout-description": "Atsijungti ir išvalyti sesijos duomenis.",
+       "apihelp-logout-example-logout": "Atjungti dabartinė vartotoją.",
+       "apihelp-managetags-example-delete": "Ištrinti <kbd>vandlaism</kbd> žymę su priežastimi <kbd>Misspelt</kbd>",
+       "apihelp-managetags-example-activate": "Aktyvuoti žymę pavadinimu <kbd>spam</kbd> su priežastimi <kbd>For use in edit patrolling</kbd>",
+       "apihelp-managetags-example-deactivate": "Išjungti žymę pavadinimu <kbd>spam</kbd> su priežastimi <kbd>No longer required</kbd>",
+       "apihelp-mergehistory-description": "Sujungti puslapio istorijas.",
+       "apihelp-mergehistory-param-reason": "Istorijos sujungimo priežastis.",
+       "apihelp-mergehistory-example-merge": "Sujungti visą <kbd>Oldpage</kbd> istoriją į <kbd>Newpage</kbd>.",
+       "apihelp-move-description": "Perkelti puslapį.",
+       "apihelp-move-param-to": "Pavadinimas, į kuri pervadinamas puslapis.",
+       "apihelp-move-param-reason": "Pervadinimo priežastis.",
+       "apihelp-move-param-movetalk": "Pervadinti aptarimo puslapį, jei jis egzistuoja.",
+       "apihelp-move-param-noredirect": "Nekurti nukreipimo.",
+       "apihelp-move-param-watch": "Pridėti puslapį ir nukreipimą į dabartinio vartotojo stebimųjų sąrašą.",
+       "apihelp-move-param-unwatch": "Pašalinti puslapį ir nukreipimą iš dabartinio vartotojo stebimųjų sąrašo.",
+       "apihelp-move-param-ignorewarnings": "Ignuoruoti bet kokius įspėjimus.",
+       "apihelp-move-example-move": "Perkelti <kbd>Badtitle</kbd> į <kbd>Goodtitle</kbd> nepaliekant nukreipimo.",
+       "apihelp-opensearch-description": "Ieškoti viki naudojant OpenSearch protokolą.",
+       "apihelp-opensearch-param-limit": "Maksimalus grąžinamas rezultatų skaičius.",
+       "apihelp-opensearch-example-te": "Rasti puslapius prasidedančius su <kbd>Te</kbd>.",
+       "apihelp-options-example-reset": "Nustatyti visus pageidavimus iš naujo.",
+       "apihelp-options-example-change": "Keisti <kbd>skin</kbd> ir <kbd>hideminor</kbd> pageidavimus.",
+       "apihelp-options-example-complex": "Nustatyti visus pageidavimus iš naujo, tada nustatyti <kbd>skin</kbd> ir <kbd>nickname</kbd>.",
+       "apihelp-paraminfo-description": "Gauti informaciją apie API modulius.",
+       "apihelp-protect-example-protect": "Apsaugoti puslapį.",
+       "apihelp-query+allcategories-param-dir": "Rūšiavimo kryptis.",
+       "apihelp-query+allcategories-param-min": "Gražinti tik kategorijas, kuriuose yra bent tiek narių.",
+       "apihelp-query+allcategories-param-max": "Gražinti tik kategorijas, kuriuose yra iki tiek narių.",
+       "apihelp-query+allcategories-param-limit": "Kiek kategorijų gražinti.",
+       "apihelp-query+allcategories-paramvalue-prop-size": "Prideda puslapių kategorijoje skaičių.",
        "apihelp-query+alldeletedrevisions-example-user": "Sąrašas paskutinių 50 ištrintų indėlių pagal vartotoją\n<kbd>Pavyzdys</kbd>.",
+       "apihelp-query+alllinks-paramvalue-prop-title": "Prideda nuorodos pavadinimą.",
+       "apihelp-query+alllinks-param-limit": "Kiek objektų iš viso gražinti.",
+       "apihelp-query+allmessages-param-lang": "Gražinti pranešimus šia kalba.",
        "apihelp-query+allrevisions-param-namespace": "Rodyti puslapius tik šioje vardų srityje.",
        "apihelp-query+backlinks-example-simple": "Rodyti nuorodas <kbd>Pagrindinis puslapis</kbd>.",
+       "apihelp-query+blocks-paramvalue-prop-id": "Prideda bloko ID.",
+       "apihelp-query+blocks-paramvalue-prop-user": "Prideda užblokuoto vartotojo vardą.",
+       "apihelp-query+blocks-paramvalue-prop-userid": "Prideda užblokuoto vartotojo ID.",
+       "apihelp-query+blocks-paramvalue-prop-by": "Prideda užblokuoto vartotojo vardą.",
+       "apihelp-query+blocks-paramvalue-prop-byid": "Prideda užblokuoto vartotojo ID.",
+       "apihelp-query+blocks-paramvalue-prop-timestamp": "Prideda blokavimo laiko žymę.",
+       "apihelp-query+blocks-paramvalue-prop-expiry": "Prideda blokavimo pabaigos laiko žymes.",
+       "apihelp-query+blocks-paramvalue-prop-reason": "Prideda blokavimo priežastį.",
+       "apihelp-query+blocks-paramvalue-prop-range": "Prideda blokavimo paveiktų IP adresų diapazoną.",
        "apihelp-query+watchlist-paramvalue-type-external": "Išoriniai keitimai.",
        "apihelp-query+watchlist-paramvalue-type-new": "Puslapio sukūrimai.",
        "apihelp-stashedit-param-title": "Puslapio pavadinimas buvo redaguotas.",
index fe254af..881c8c2 100644 (file)
@@ -49,6 +49,8 @@ abstract class Collation {
                switch ( $collationName ) {
                        case 'uppercase':
                                return new UppercaseCollation;
+                       case 'numeric':
+                               return new NumericUppercaseCollation;
                        case 'identity':
                                return new IdentityCollation;
                        case 'uca-default':
diff --git a/includes/collation/NumericUppercaseCollation.php b/includes/collation/NumericUppercaseCollation.php
new file mode 100644 (file)
index 0000000..4bf2f73
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Collation that orders text with numbers "naturally", so that 'Foo 1' < 'Foo 2' < 'Foo 12'.
+ *
+ * Note that this only works in terms of sequences of digits, and the behavior for decimal fractions
+ * or pretty-formatted numbers may be unexpected.
+ *
+ * @since 1.28
+ */
+class NumericUppercaseCollation extends UppercaseCollation {
+       public function getSortKey( $string ) {
+               $sortkey = parent::getSortKey( $string );
+
+               // For each sequence of digits, insert the digit '0' and then the length of the sequence
+               // (encoded in two bytes) before it. That's all folks, it sorts correctly now! The '0' ensures
+               // correct position (where digits would normally sort), then the length will be compared putting
+               // shorter numbers before longer ones; if identical, then the characters will be compared, which
+               // generates the correct results for numbers of equal length.
+               $sortkey = preg_replace_callback( '/\d+/', function ( $matches ) {
+                       $len = strlen( $matches[0] );
+                       // This allows sequences of up to 65536 numeric characters to be handled correctly. One byte
+                       // would allow only for 256, which doesn't feel future-proof.
+                       $prefix = chr( floor( $len / 256 ) ) . chr( $len % 256 );
+                       return '0' . $prefix . $matches[0];
+               }, $sortkey );
+
+               return $sortkey;
+       }
+
+       public function getFirstLetter( $string ) {
+               if ( preg_match( '/^\d/', $string ) ) {
+                       // Note that we pass 0 and 9 as normal params, not numParams(). This only works for 0-9
+                       // and not localised digits, so we don't want them to be converted.
+                       return wfMessage( 'category-header-numerals' )->params( 0, 9 )->text();
+               } else {
+                       return parent::getFirstLetter( $string );
+               }
+       }
+}
index 40d9277..14c8182 100644 (file)
@@ -86,7 +86,7 @@ class JsonContent extends TextContent {
                        return $this;
                }
 
-               return new static( $this->beautifyJSON() );
+               return new static( self::normalizeLineEndings( $this->beautifyJSON() ) );
        }
 
        /**
index de650b9..7bb4def 100644 (file)
@@ -147,9 +147,28 @@ class TextContent extends AbstractContent {
                }
        }
 
+       /**
+        * Do a "\r\n" -> "\n" and "\r" -> "\n" transformation
+        * as well as trim trailing whitespace
+        *
+        * This was formerly part of Parser::preSaveTransform, but
+        * for non-wikitext content models they probably still want
+        * to normalize line endings without all of the other PST
+        * changes.
+        *
+        * @since 1.28
+        * @param $text
+        * @return string
+        */
+       public static function normalizeLineEndings( $text ) {
+               return str_replace( [ "\r\n", "\r" ], "\n", rtrim( $text ) );
+       }
+
        /**
         * Returns a Content object with pre-save transformations applied.
-        * This implementation just trims trailing whitespace and normalizes newlines.
+        *
+        * At a minimum, subclasses should make sure to call TextContent::normalizeLineEndings()
+        * either directly or part of Parser::preSaveTransform().
         *
         * @param Title $title
         * @param User $user
@@ -159,8 +178,7 @@ class TextContent extends AbstractContent {
         */
        public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
                $text = $this->getNativeData();
-               $pst = rtrim( $text );
-               $pst = str_replace( [ "\r\n", "\r" ], "\n", $pst );
+               $pst = self::normalizeLineEndings( $text );
 
                return ( $text === $pst ) ? $this : new static( $pst, $this->getModel() );
        }
index a63819d..9296728 100644 (file)
@@ -138,7 +138,6 @@ class WikitextContent extends TextContent {
 
                $text = $this->getNativeData();
                $pst = $wgParser->preSaveTransform( $text, $title, $user, $popts );
-               rtrim( $pst );
 
                return ( $text === $pst ) ? $this : new static( $pst );
        }
index 3cd09e2..577c98d 100644 (file)
@@ -129,25 +129,11 @@ class CloneDatabase {
         */
        public static function changePrefix( $prefix ) {
                global $wgDBprefix;
-               wfGetLBFactory()->forEachLB( [ 'CloneDatabase', 'changeLBPrefix' ], [ $prefix ] );
+               wfGetLBFactory()->forEachLB( function( $lb ) use ( $prefix ) {
+                       $lb->forEachOpenConnection( function ( $db ) use ( $prefix ) {
+                               $db->tablePrefix( $prefix );
+                       } );
+               } );
                $wgDBprefix = $prefix;
        }
-
-       /**
-        * @param LoadBalancer $lb
-        * @param string $prefix
-        * @return void
-        */
-       public static function changeLBPrefix( $lb, $prefix ) {
-               $lb->forEachOpenConnection( [ 'CloneDatabase', 'changeDBPrefix' ], [ $prefix ] );
-       }
-
-       /**
-        * @param DatabaseBase $db
-        * @param string $prefix
-        * @return void
-        */
-       public static function changeDBPrefix( $db, $prefix ) {
-               $db->tablePrefix( $prefix );
-       }
 }
index fa3756c..93814d2 100644 (file)
@@ -38,7 +38,14 @@ abstract class DatabaseMysqlBase extends Database {
        protected $lagDetectionOptions = [];
        /** @var bool bool Whether to use GTID methods */
        protected $useGTIDs = false;
-
+       /** @var string|null */
+       protected $sslKeyPath;
+       /** @var string|null */
+       protected $sslCertPath;
+       /** @var string|null */
+       protected $sslCAPath;
+       /** @var string[]|null */
+       protected $sslCiphers;
        /** @var string|null */
        private $serverVersion = null;
 
@@ -53,6 +60,10 @@ abstract class DatabaseMysqlBase extends Database {
         *       ID of this server's master will be used. Set the "conds" field to
         *       override the query conditions, e.g. ['shard' => 's1'].
         *   - useGTIDs : use GTID methods like MASTER_GTID_WAIT() when possible.
+        *   - sslKeyPath : path to key file [default: null]
+        *   - sslCertPath : path to certificate file [default: null]
+        *   - sslCAPath : parth to certificate authority PEM files [default: null]
+        *   - sslCiphers : array list of allowable ciphers [default: null]
         * @param array $params
         */
        function __construct( array $params ) {
@@ -65,6 +76,12 @@ abstract class DatabaseMysqlBase extends Database {
                        ? $params['lagDetectionOptions']
                        : [];
                $this->useGTIDs = !empty( $params['useGTIDs' ] );
+               foreach ( [ 'KeyPath', 'CertPath', 'CAPath', 'Ciphers' ] as $name ) {
+                       $var = "ssl{$name}";
+                       if ( isset( $params[$var] ) ) {
+                               $this->$var = $params[$var];
+                       }
+               }
        }
 
        /**
index cb580cc..e468601 100644 (file)
@@ -81,9 +81,18 @@ class DatabaseMysqli extends DatabaseMysqlBase {
                        $socket = $hostAndSocket[1];
                }
 
+               $mysqli = mysqli_init();
+
                $connFlags = 0;
                if ( $this->mFlags & DBO_SSL ) {
                        $connFlags |= MYSQLI_CLIENT_SSL;
+                       $mysqli->ssl_set(
+                               $this->sslKeyPath,
+                               $this->sslCertPath,
+                               null,
+                               $this->sslCAPath,
+                               $this->sslCiphers
+                       );
                }
                if ( $this->mFlags & DBO_COMPRESS ) {
                        $connFlags |= MYSQLI_CLIENT_COMPRESS;
@@ -92,7 +101,6 @@ class DatabaseMysqli extends DatabaseMysqlBase {
                        $realServer = 'p:' . $realServer;
                }
 
-               $mysqli = mysqli_init();
                if ( $wgDBmysql5 ) {
                        // Tell the server we're communicating with it in UTF-8.
                        // This may engage various charset conversions.
index 0aefbfa..cccf71a 100644 (file)
@@ -144,33 +144,38 @@ abstract class DBLockManager extends QuorumLockManager {
         * @param string $lockDb
         * @return IDatabase
         * @throws DBError
+        * @throws UnexpectedValueException
         */
        protected function getConnection( $lockDb ) {
                if ( !isset( $this->conns[$lockDb] ) ) {
-                       $db = null;
                        if ( $lockDb === 'localDBMaster' ) {
-                               $db = $this->getLocalLB()->getConnection( DB_MASTER, [], $this->domain );
+                               $lb = $this->getLocalLB();
+                               $db = $lb->getConnection( DB_MASTER, [], $this->domain );
+                               # Do not mess with settings if the LoadBalancer is the main singleton
+                               # to avoid clobbering the settings of handles from wfGetDB( DB_MASTER ).
+                               $init = ( wfGetLB() !== $lb );
                        } elseif ( isset( $this->dbServers[$lockDb] ) ) {
                                $config = $this->dbServers[$lockDb];
                                $db = DatabaseBase::factory( $config['type'], $config );
+                               $init = true;
+                       } else {
+                               throw new UnexpectedValueException( "No server called '$lockDb'." );
                        }
-                       if ( !$db ) {
-                               return null; // config error?
+
+                       if ( $init ) {
+                               $db->clearFlag( DBO_TRX );
+                               # If the connection drops, try to avoid letting the DB rollback
+                               # and release the locks before the file operations are finished.
+                               # This won't handle the case of DB server restarts however.
+                               $options = [];
+                               if ( $this->lockExpiry > 0 ) {
+                                       $options['connTimeout'] = $this->lockExpiry;
+                               }
+                               $db->setSessionOptions( $options );
+                               $this->initConnection( $lockDb, $db );
                        }
+
                        $this->conns[$lockDb] = $db;
-                       $this->conns[$lockDb]->clearFlag( DBO_TRX );
-                       # If the connection drops, try to avoid letting the DB rollback
-                       # and release the locks before the file operations are finished.
-                       # This won't handle the case of DB server restarts however.
-                       $options = [];
-                       if ( $this->lockExpiry > 0 ) {
-                               $options['connTimeout'] = $this->lockExpiry;
-                       }
-                       $this->conns[$lockDb]->setSessionOptions( $options );
-                       $this->initConnection( $lockDb, $this->conns[$lockDb] );
-               }
-               if ( !$this->conns[$lockDb]->trxLevel() ) {
-                       $this->conns[$lockDb]->begin( __METHOD__ ); // start transaction
                }
 
                return $this->conns[$lockDb];
index c51df16..0536091 100644 (file)
@@ -23,6 +23,8 @@ class MySqlLockManager extends DBLockManager {
        protected function initConnection( $lockDb, IDatabase $db ) {
                # Let this transaction see lock rows from other transactions
                $db->query( "SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;" );
+               # Do everything in a transaction as it all gets rolled back eventually
+               $db->startAtomic( __CLASS__ );
        }
 
        /**
index 6095aee..4121ecb 100644 (file)
@@ -81,10 +81,12 @@ class RedisLockManager extends QuorumLockManager {
        protected function getLocksOnServer( $lockSrv, array $pathsByType ) {
                $status = Status::newGood();
 
+               $pathList = call_user_func_array( 'array_merge', array_values( $pathsByType ) );
+
                $server = $this->lockServers[$lockSrv];
                $conn = $this->redisPool->getConnection( $server );
                if ( !$conn ) {
-                       foreach ( array_merge( array_values( $pathsByType ) ) as $path ) {
+                       foreach ( $pathList as $path ) {
                                $status->fatal( 'lockmanager-fail-acquirelock', $path );
                        }
 
@@ -157,7 +159,7 @@ LUA;
                }
 
                if ( $res === false ) {
-                       foreach ( array_merge( array_values( $pathsByType ) ) as $path ) {
+                       foreach ( $pathList as $path ) {
                                $status->fatal( 'lockmanager-fail-acquirelock', $path );
                        }
                } else {
@@ -172,10 +174,12 @@ LUA;
        protected function freeLocksOnServer( $lockSrv, array $pathsByType ) {
                $status = Status::newGood();
 
+               $pathList = call_user_func_array( 'array_merge', array_values( $pathsByType ) );
+
                $server = $this->lockServers[$lockSrv];
                $conn = $this->redisPool->getConnection( $server );
                if ( !$conn ) {
-                       foreach ( array_merge( array_values( $pathsByType ) ) as $path ) {
+                       foreach ( $pathList as $path ) {
                                $status->fatal( 'lockmanager-fail-releaselock', $path );
                        }
 
@@ -225,7 +229,7 @@ LUA;
                }
 
                if ( $res === false ) {
-                       foreach ( array_merge( array_values( $pathsByType ) ) as $path ) {
+                       foreach ( $pathList as $path ) {
                                $status->fatal( 'lockmanager-fail-releaselock', $path );
                        }
                } else {
index 7e6e651..40141c9 100644 (file)
@@ -2216,8 +2216,9 @@ class LocalFileDeleteBatch {
        }
 
        protected function doDBInserts() {
+               $now = time();
                $dbw = $this->file->repo->getMasterDB();
-               $encTimestamp = $dbw->addQuotes( $dbw->timestamp() );
+               $encTimestamp = $dbw->addQuotes( $dbw->timestamp( $now ) );
                $encUserId = $dbw->addQuotes( $this->user->getId() );
                $encReason = $dbw->addQuotes( $this->reason );
                $encGroup = $dbw->addQuotes( 'deleted' );
@@ -2239,15 +2240,15 @@ class LocalFileDeleteBatch {
                }
 
                if ( $deleteCurrent ) {
-                       $concat = $dbw->buildConcat( [ "img_sha1", $encExt ] );
-                       $where = [ 'img_name' => $this->file->getName() ];
-                       $dbw->insertSelect( 'filearchive', 'image',
+                       $dbw->insertSelect(
+                               'filearchive',
+                               'image',
                                [
                                        'fa_storage_group' => $encGroup,
                                        'fa_storage_key' => $dbw->conditional(
                                                [ 'img_sha1' => '' ],
                                                $dbw->addQuotes( '' ),
-                                               $concat
+                                               $dbw->buildConcat( [ "img_sha1", $encExt ] )
                                        ),
                                        'fa_deleted_user' => $encUserId,
                                        'fa_deleted_timestamp' => $encTimestamp,
@@ -2268,44 +2269,56 @@ class LocalFileDeleteBatch {
                                        'fa_user' => 'img_user',
                                        'fa_user_text' => 'img_user_text',
                                        'fa_timestamp' => 'img_timestamp',
-                                       'fa_sha1' => 'img_sha1',
-                               ], $where, __METHOD__ );
+                                       'fa_sha1' => 'img_sha1'
+                               ],
+                               [ 'img_name' => $this->file->getName() ],
+                               __METHOD__
+                       );
                }
 
                if ( count( $oldRels ) ) {
-                       $concat = $dbw->buildConcat( [ "oi_sha1", $encExt ] );
-                       $where = [
-                               'oi_name' => $this->file->getName(),
-                               'oi_archive_name' => array_keys( $oldRels ) ];
-                       $dbw->insertSelect( 'filearchive', 'oldimage',
+                       $res = $dbw->select(
+                               'oldimage',
+                               OldLocalFile::selectFields(),
                                [
-                                       'fa_storage_group' => $encGroup,
-                                       'fa_storage_key' => $dbw->conditional(
-                                               [ 'oi_sha1' => '' ],
-                                               $dbw->addQuotes( '' ),
-                                               $concat
-                                       ),
-                                       'fa_deleted_user' => $encUserId,
-                                       'fa_deleted_timestamp' => $encTimestamp,
-                                       'fa_deleted_reason' => $encReason,
-                                       'fa_deleted' => $this->suppress ? $bitfield : 'oi_deleted',
-
-                                       'fa_name' => 'oi_name',
-                                       'fa_archive_name' => 'oi_archive_name',
-                                       'fa_size' => 'oi_size',
-                                       'fa_width' => 'oi_width',
-                                       'fa_height' => 'oi_height',
-                                       'fa_metadata' => 'oi_metadata',
-                                       'fa_bits' => 'oi_bits',
-                                       'fa_media_type' => 'oi_media_type',
-                                       'fa_major_mime' => 'oi_major_mime',
-                                       'fa_minor_mime' => 'oi_minor_mime',
-                                       'fa_description' => 'oi_description',
-                                       'fa_user' => 'oi_user',
-                                       'fa_user_text' => 'oi_user_text',
-                                       'fa_timestamp' => 'oi_timestamp',
-                                       'fa_sha1' => 'oi_sha1',
-                               ], $where, __METHOD__ );
+                                       'oi_name' => $this->file->getName(),
+                                       'oi_archive_name' => array_keys( $oldRels )
+                               ],
+                               __METHOD__,
+                               [ 'FOR UPDATE' ]
+                       );
+                       $rowsInsert = [];
+                       foreach ( $res as $row ) {
+                               $rowsInsert[] = [
+                                       // Deletion-specific fields
+                                       'fa_storage_group' => 'deleted',
+                                       'fa_storage_key' => ( $row->oi_sha1 === '' )
+                                               ? ''
+                                               : "{$row->oi_sha1}{$dotExt}",
+                                       'fa_deleted_user' => $this->user->getId(),
+                                       'fa_deleted_timestamp' => $dbw->timestamp( $now ),
+                                       'fa_deleted_reason' => $this->reason,
+                                       // Counterpart fields
+                                       'fa_deleted' => $this->suppress ? $bitfield : $row->oi_deleted,
+                                       'fa_name' => $row->oi_name,
+                                       'fa_archive_name' => $row->oi_archive_name,
+                                       'fa_size' => $row->oi_size,
+                                       'fa_width' => $row->oi_width,
+                                       'fa_height' => $row->oi_height,
+                                       'fa_metadata' => $row->oi_metadata,
+                                       'fa_bits' => $row->oi_bits,
+                                       'fa_media_type' => $row->oi_media_type,
+                                       'fa_major_mime' => $row->oi_major_mime,
+                                       'fa_minor_mime' => $row->oi_minor_mime,
+                                       'fa_description' => $row->oi_description,
+                                       'fa_user' => $row->oi_user,
+                                       'fa_user_text' => $row->oi_user_text,
+                                       'fa_timestamp' => $row->oi_timestamp,
+                                       'fa_sha1' => $row->oi_sha1
+                               ];
+                       }
+
+                       $dbw->insert( 'filearchive', $rowsInsert, __METHOD__ );
                }
        }
 
index ff37e24..3c88594 100644 (file)
@@ -354,6 +354,26 @@ class HTMLForm extends ContextSource {
                $this->mFieldTree = $loadedDescriptor;
        }
 
+       /**
+        * @param string $fieldname
+        * @return bool
+        */
+       public function hasField( $fieldname ) {
+               return isset( $this->mFlatFields[$fieldname] );
+       }
+
+       /**
+        * @param string $fieldname
+        * @return HTMLFormField
+        * @throws DomainException on invalid field name
+        */
+       public function getField( $fieldname ) {
+               if ( !$this->hasField( $fieldname ) ) {
+                       throw new DomainException( __METHOD__ . ': no field named ' . $fieldname );
+               }
+               return $this->mFlatFields[$fieldname];
+       }
+
        /**
         * Set format in which to display the form
         *
index dd53f5e..25b4cca 100644 (file)
@@ -61,7 +61,7 @@ abstract class HTMLFormField {
         * @return bool
         */
        public function canDisplayErrors() {
-               return true;
+               return $this->hasVisibleOutput();
        }
 
        /**
@@ -455,10 +455,6 @@ abstract class HTMLFormField {
                        $this->mFilterCallback = $params['filter-callback'];
                }
 
-               if ( isset( $params['flatlist'] ) ) {
-                       $this->mClass .= ' mw-htmlform-flatlist';
-               }
-
                if ( isset( $params['hidelabel'] ) ) {
                        $this->mShowEmptyLabels = false;
                }
index a231b2f..c9fcb09 100644 (file)
@@ -4,6 +4,29 @@
  * Multi-select field
  */
 class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable {
+       /**
+        * @param array $params
+        *   In adition to the usual HTMLFormField parameters, this can take the following fields:
+        *   - dropdown: If given, the options will be displayed inside a dropdown with a text field that
+        *     can be used to filter them. This is desirable mostly for very long lists of options.
+        *     This only works for users with JavaScript support and falls back to the list of checkboxes.
+        *   - flatlist: If given, the options will be displayed on a single line (wrapping to following
+        *     lines if necessary), rather than each one on a line of its own. This is desirable mostly
+        *     for very short lists of concisely labelled options.
+        */
+       public function __construct( $params ) {
+               parent::__construct( $params );
+
+               // For backwards compatibility, also handle the old way with 'cssclass' => 'mw-chosen'
+               if ( isset( $params['dropdown'] ) || strpos( $this->mClass, 'mw-chosen' ) !== false ) {
+                       $this->mClass .= ' mw-htmlform-dropdown';
+               }
+
+               if ( isset( $params['flatlist'] ) ) {
+                       $this->mClass .= ' mw-htmlform-flatlist';
+               }
+       }
+
        function validate( $value, $alldata ) {
                $p = parent::validate( $value, $alldata );
 
@@ -28,6 +51,10 @@ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable
        }
 
        function getInputHTML( $value ) {
+               if ( isset( $this->mParams['dropdown'] ) ) {
+                       $this->mParent->getOutput()->addModules( 'jquery.chosen' );
+               }
+
                $value = HTMLFormField::forceToStringRecursive( $value );
                $html = $this->formatOptions( $this->getOptions(), $value );
 
index 976befe..f9f035d 100644 (file)
@@ -4,6 +4,21 @@
  * Radio checkbox fields.
  */
 class HTMLRadioField extends HTMLFormField {
+       /**
+        * @param array $params
+        *   In adition to the usual HTMLFormField parameters, this can take the following fields:
+        *   - flatlist: If given, the options will be displayed on a single line (wrapping to following
+        *     lines if necessary), rather than each one on a line of its own. This is desirable mostly
+        *     for very short lists of concisely labelled options.
+        */
+       public function __construct( $params ) {
+               parent::__construct( $params );
+
+               if ( isset( $params['flatlist'] ) ) {
+                       $this->mClass .= ' mw-htmlform-flatlist';
+               }
+       }
+
        function validate( $value, $alldata ) {
                $p = parent::validate( $value, $alldata );
 
index b1c3d48..09f3a40 100644 (file)
@@ -30,7 +30,8 @@
                        "Matiia",
                        "AlvaroMolina",
                        "Indiralena",
-                       "Peter Bowman"
+                       "Peter Bowman",
+                       "Dgstranz"
                ]
        },
        "config-desc": "El instalador de MediaWiki",
        "config-subscribe": "Suscribirse a la [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce lista de correo de anuncios de versiones].",
        "config-subscribe-help": "Esta es una lista de divulgación de bajo volumen para anuncios de lanzamiento de versiones nuevas, incluyendo anuncios de seguridad importantes.\nTe recomendamos suscribirte y actualizar tu instalación MediaWiki cada vez que se lance una nueva versión.",
        "config-subscribe-noemail": "Has intentado suscribirte a la lista de correo de anuncios de nuevos lanzamientos sin proporcionar una dirección de correo electrónico.\nProporciona una dirección de correo electrónico si quieres suscribirte a la lista de correo.",
+       "config-pingback": "Compartir datos sobre esta instalación con los desarrolladores de MediaWiki.",
+       "config-pingback-help": "Si seleccionas esta opción, MediaWiki enviará periódicamente a https://www.mediawiki.org datos básicos sobre esta instancia de MediaWiki. Se trata de datos tales como el tipo de sistema, la versión de PHP y la base de datos elegida. La Fundación Wikimedia comparte estos datos con los desarrolladores de MediaWiki para ayudar a guiar el desarrollo futuro. Se enviarán los siguientes datos para tu sistema:\n<pre>$1</pre>",
        "config-almost-done": "¡Ya casi has terminado!\nAhora puedes saltarte el resto de los pasos e instalar el wiki ya.",
        "config-optional-continue": "Hazme más preguntas.",
        "config-optional-skip": "Ya estoy aburrido, sólo instala el wiki.",
index f97b6dc..cc197c8 100644 (file)
@@ -56,8 +56,8 @@
        "config-env-php": "A PHP verziója: $1",
        "config-env-hhvm": "HHVM verziója: $1",
        "config-unicode-using-intl": "A rendszer Unicode normalizálására az [http://pecl.php.net/intl intl PECL kiterjesztést] használja.",
-       "config-unicode-pure-php-warning": "'''Figyelmeztetés''': Az Unicode normalizáláshoz szükséges [http://pecl.php.net/intl intl PECL kiterjesztés] nem érhető el, helyette a lassú, PHP alapú implementáció lesz használva.\nHa nagy látogatottságú oldalt üzemeltetsz, itt találhatsz további információkat [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations a témáról].",
-       "config-unicode-update-warning": "'''Figyelmeztetés''': Az Unicode normalizáláshoz szükséges burkolókönyvtár [http://site.icu-project.org/ ICU projekt] függvénykönyvtárának régebbi változatát használja.\nHa ügyelni kívánsz a Unicode használatára, fontold meg a [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations frissítését].",
+       "config-unicode-pure-php-warning": "<strong>Figyelmeztetés:</strong> Az Unicode normalizáláshoz szükséges [http://pecl.php.net/intl intl PECL kiterjesztés] nem érhető el, helyette a lassú, PHP-alapú implementáció lesz használatban.\nHa nagy látogatottságú oldalt üzemeltetsz, [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations itt] találhatsz további információkat a témáról.",
+       "config-unicode-update-warning": "<strong>Figyelmeztetés:</strong> Az Unicode normalizáláshoz szükséges burkolókönyvtár [http://site.icu-project.org/ ICU projekt] függvénykönyvtárának régebbi változatát használja.\nHa ügyelni kívánsz a Unicode használatára, fontold meg a [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations frissítését].",
        "config-no-db": "Nem sikerült egyetlen használható adatbázis-illesztőprogramot sem találni. Telepítened kell egyet a PHP-hez.\nA következő {{PLURAL:$2|adatbázistípus támogatott|adatbázistípusok támogatottak}}: $1.\n\nHa a PHP-t magad fordítottad, konfiguráld újra úgy, hogy engedélyezve legyen egy adatbáziskliens, pl. a <code>./configure --with-mysql</code> parancs használatával.\nHa a PHP-t Debian vagy Ubuntu csomaggal telepítetted, akkor szükséged lesz például a php5-mysql csomagra is.",
        "config-outdated-sqlite": "<strong>Figyelmeztetés:</strong> SQLite $1 verziód van, ami alacsonyabb a legalább szükséges $2 verziónál. Az SQLite nem lesz elérhető.",
        "config-no-fts3": "'''Figyelmeztetés''': Az SQLite [//sqlite.org/fts3.html FTS3 modul] nélkül lett fordítva, a keresési funkciók nem fognak működni ezen a rendszeren.",
        "config-ns-site-name": "Ugyanaz, mint a wiki neve: $1",
        "config-ns-other": "Más (meg kell adni)",
        "config-ns-other-default": "SajátWiki",
-       "config-project-namespace-help": "A Wikipédia példáját követve számos wiki elkülöníti egy '''projekt névtérbe''' az irányelveit a tartalommal rendelkező lapoktól\nAz ebben a névtérben található lapok nevei egy előtaggal kezdődnek, amit itt adhatsz meg.\nÁltalában az előtag a wiki nevéből származik, de nem tartalmazhat írásjeleket, például „#”-t vagy „:”-t.",
+       "config-project-namespace-help": "A Wikipédia példáját követve számos wiki elkülöníti az irányelveit a tartalmi lapoktól egy '''projektnévtérbe'''.\nAz ebben a névtérben található lapok nevei egy előtaggal kezdődnek, amit itt adhatsz meg.\nÁltalában az előtag a wiki nevéből származik, de nem tartalmazhat írásjeleket, például „#”-t vagy „:”-t.",
        "config-ns-invalid": "A megadott névtér („<nowiki>$1</nowiki>”) érvénytelen.\nVálassz másik projektnévteret!",
        "config-ns-conflict": "A megadott névtér („<nowiki>$1</nowiki>”) ütközik az egyik alapértelmezett MediaWiki-névtérrel.\nVálassz másik projektnévteret!",
        "config-admin-box": "Adminisztrátori fiók",
        "config-logo": "A logó URL-címe:",
        "config-logo-help": "A MediaWiki alapértelmezett felülete helyet ad egy 135×160 pixeles logónak a bal felső sarokban.\nTölts fel egy megfelelő méretű képet, majd írd be ide az URL-címét!\n\nHasználhatsz  <code>$wgStylePath</code>-t vagy <code>$wgScriptPath</code>-t, ha más méretű a logód.\n\nHa nem szeretnél logót használni, egyszerűen hagyd üresen a mezőt.",
        "config-instantcommons": "Instant Commons engedélyezése",
-       "config-instantcommons-help": "Az [https://www.mediawiki.org/wiki/InstantCommons Instant Commons] lehetővé teszi, hogy a wikin használhassák a [https://commons.wikimedia.org/ Wikimedia Commons] oldalon található képeket, hangokat és más médiafájlokat.\nA használatához a MediaWikinek internethozzáférésre van szüksége.\n\nA funkcióról és hogy hogyan állítható be más wikik esetén [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos a kézikönyvben] találhatsz további információkat.",
+       "config-instantcommons-help": "Az [https://www.mediawiki.org/wiki/InstantCommons Instant Commons] lehetővé teszi, hogy a wikin használhassák a [https://commons.wikimedia.org/ Wikimédia Commons] oldalon található képeket, hangokat és más médiafájlokat.\nA használatához a MediaWikinek internet-hozzáférésre van szüksége.\n\nA funkcióról és hogy hogyan állítható be más wikik esetén [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos a kézikönyvben] találhatsz további információkat.",
        "config-cc-error": "A Creative Commons-licencválasztó nem tért vissza eredménnyel.\nAdd meg kézzel a licencet.",
        "config-cc-again": "Válassz újra…",
        "config-cc-not-chosen": "Válaszd ki a kívánt Creative Commons licencet, majd kattints a „proceed”!",
        "config-install-mainpage": "Kezdőlap létrehozása az alapértelmezett tartalommal",
        "config-install-extension-tables": "Táblák létrehozása az engedélyezett kiterjesztésekhez",
        "config-install-mainpage-failed": "Nemsikerült létrehozni a kezdőlapot: $1",
-       "config-install-done": "'''Gratulálunk!'''\nA MediaWiki telepítése sikeresen befejeződött.\n\nA telepítő elkészítette a <code>LocalSettings.php</code> fájlt, amely tartalmazza az összes beállítást.\n\nEzt le kell tölteni, majd elhelyezni a wiki telepítési könyvtárába (az a könyvtár, ahol az index.php is található).\n\nA letöltés automatikusan elindul. Ha mégsem indulna el, vagy megszakítottad, az alábbi linkre kattintva újra letöltheted:\n\n$3\n\n'''Megjegyzés''': Ha ezt most nem teszed meg, és kilépsz a telepítésből, az elkészített konfigurációs fájlt nem tudod elérni a későbbiekben.\n\nHa végeztél a fájl elhelyezésével, '''[$2 beléphetsz a wikibe]'''.",
+       "config-install-done": "<strong>Gratulálunk!</strong>\nA MediaWiki telepítése sikeresen befejeződött.\n\nA telepítő elkészítette a <code>LocalSettings.php</code> fájlt, amely tartalmazza az összes beállítást.\n\nEzt le kell tölteni, majd elhelyezni a wiki telepítési könyvtárába (az a könyvtár, ahol az index.php is található).\n\nA letöltés automatikusan elindul. Ha mégsem indulna el, vagy megszakítottad, az alábbi linkre kattintva újra letöltheted:\n\n$3\n\n<strong>Megjegyzés:</strong> Ha ezt most nem teszed meg, és kilépsz a telepítésből, az elkészített konfigurációs fájlt nem tudod elérni a későbbiekben.\n\nHa végeztél a fájl elhelyezésével, <strong>[$2 beléphetsz a wikibe]</strong>.",
        "config-download-localsettings": "<code>LocalSettings.php</code> letöltése",
        "config-help": "segítség",
        "config-help-tooltip": "kattints a kibontáshoz",
        "config-nofile": "\"$1\" fájl nem található. Törölve lett?",
        "config-extension-link": "Tudtad, hogy a wikid támogat [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions kiterjesztéseket]?\n\nBöngészhetsz [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category kiterjesztéseket kategóriánként] vagy válogathatsz a [https://www.mediawiki.org/wiki/Extension_Matrix kiterjesztésmátrixból] az összes kiterjesztés áttekintéséhez.",
-       "mainpagetext": "'''A MediaWiki telepítése sikeresen befejeződött.'''",
+       "mainpagetext": "<strong>A MediaWiki telepítése sikeresen befejeződött.</strong>",
        "mainpagedocfooter": "Ha segítségre van szükséged a wikiszoftver használatához, akkor keresd fel a [https://meta.wikimedia.org/wiki/Help:Contents User's Guide] oldalt.\n\n== Alapok (angol nyelven) ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Beállítások listája]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki GyIK]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki-kiadások levelezőlistája]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources A MediaWiki fordítása a saját nyelvedre]"
 }
index fa2af13..22cceb4 100644 (file)
        "config-install-user": "Kuriamas duomenų bazės naudotojas",
        "config-install-user-alreadyexists": "Naudotojas „$1“ jau yra",
        "config-install-user-create-failed": "Nepavyko sukurti naudotojo „$1“: $2",
+       "config-install-user-missing": "Nurodytas vartotojas „$1“ neegzistuoja.",
+       "config-install-user-missing-create": "Nurodytas vartotojas „$1“ neegzistuoja.\nPrašome pažymėti „sukurti paskyrą“ laukelį žemiau jei norite jį sukurti.",
        "config-install-tables": "Kuriamos lentelės",
+       "config-install-tables-exist": "<strong>Įspėjimas:</strong> MediaWiki lentelės, atrodo, jau egzistuoja.\nKūrimas praleidžiamas.",
+       "config-install-tables-failed": "<strong>Klaida:</strong> Lentelės sukūrimas nepavyko dėl šios klaidos: $1",
+       "config-install-interwiki-list": "Nepavyko perskaityti failo <code>interwiki.list</code>.",
+       "config-install-interwiki-exists": "<strong>Įspėjimas:</strong> Interwiki lentelė, atrodo, jau turi įrašų.\nNumatytasis sąrašas praleidžiamas.",
        "config-install-stats": "Inicijuojamos statistikos",
        "config-install-keys": "Generuojami slapti raktai",
        "config-install-sysop": "Administratoriaus vartotojo paskyra kuriama",
        "config-help": "pagalba",
        "config-help-tooltip": "spustelėkite išplėtimui",
        "config-nofile": "Failas \"$1\" nerastas. Ar jis buvo ištrintas?",
-       "mainpagetext": "'''MediaWiki sėkmingai įdiegta.'''",
+       "mainpagetext": "<strong>MediaWiki sėkmingai įdiegta.</strong>",
        "mainpagedocfooter": "Informacijos apie wiki programinės įrangos naudojimą, ieškokite [https://meta.wikimedia.org/wiki/Help:Contents žinyne].\n\n== Pradžiai ==\n\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Konfigūracijos nustatymų sąrašas]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki DUK]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki pranešimai paštu apie naujas versijas]"
 }
index f2f56d0..08aa8c1 100644 (file)
        "config-subscribe": "Theo dõi [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce danh sách thư thông báo phát hành].",
        "config-subscribe-help": "thông báo an ninh.\nBạn nên đồng ý với nó và cập nhật bản cài đặt MediaWiki của bạn khi phiên bản mới xuất hiện.",
        "config-subscribe-noemail": "Bạn đã cố gắng để đăng ký vào danh sách thư thông báo phát hành mà không cung cấp một địa chỉ thư điện tử nào cả.\nVui lòng cung cấp một địa chỉ thư điện tử nếu bạn muốn đăng ký vào danh sách thư.",
+       "config-pingback": "Chia sẻ dữ liệu về bản cài đặt này với nhóm phát triển MediaWiki.",
        "config-almost-done": "Bạn gần như đã hoàn tất!\nBây giờ bạn có thể bỏ qua cấu hình còn lại và cài đặt wiki ngay bây giờ.",
        "config-optional-continue": "Hỏi tôi về thêm chi tiết.",
        "config-optional-skip": "Chán quá, cài đặt wiki rỗi.",
index b9f4592..3a1da13 100644 (file)
@@ -261,7 +261,6 @@ class JobQueueDB extends JobQueue {
        protected function doPop() {
                $dbw = $this->getMasterDB();
                try {
-                       $dbw->commit( __METHOD__, 'flush' ); // flush existing transaction
                        $autoTrx = $dbw->getFlag( DBO_TRX ); // get current setting
                        $dbw->clearFlag( DBO_TRX ); // make each query its own transaction
                        $scopedReset = new ScopedCallback( function () use ( $dbw, $autoTrx ) {
@@ -457,7 +456,6 @@ class JobQueueDB extends JobQueue {
 
                $dbw = $this->getMasterDB();
                try {
-                       $dbw->commit( __METHOD__, 'flush' ); // flush existing transaction
                        $autoTrx = $dbw->getFlag( DBO_TRX ); // get current setting
                        $dbw->clearFlag( DBO_TRX ); // make each query its own transaction
                        $scopedReset = new ScopedCallback( function () use ( $dbw, $autoTrx ) {
index ad0abf2..5f48dca 100644 (file)
@@ -21,6 +21,7 @@
  * @ingroup JobQueue
  */
 
+use MediaWiki\MediaWikiServices;
 use MediaWiki\Logger\LoggerFactory;
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerInterface;
@@ -122,7 +123,8 @@ class JobRunner implements LoggerAwareInterface {
                }
 
                // Flush any pending DB writes for sanity
-               wfGetLBFactory()->commitAll( __METHOD__ );
+               $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+               $lbFactory->commitAll( __METHOD__ );
 
                // Catch huge single updates that lead to slave lag
                $trxProfiler = Profiler::instance()->getTransactionProfiler();
@@ -176,9 +178,11 @@ class JobRunner implements LoggerAwareInterface {
                                        $backoffs = $this->syncBackoffDeltas( $backoffs, $backoffDeltas, $wait );
                                }
 
+                               $lbFactory->commitMasterChanges( __METHOD__ ); // flush any JobQueueDB writes
                                $info = $this->executeJob( $job, $stats, $popTime );
                                if ( $info['status'] !== false || !$job->allowRetries() ) {
                                        $group->ack( $job ); // succeeded or job cannot be retried
+                                       $lbFactory->commitMasterChanges( __METHOD__ ); // flush any JobQueueDB writes
                                }
 
                                // Back off of certain jobs for a while (for throttling and for errors)
@@ -212,7 +216,7 @@ class JobRunner implements LoggerAwareInterface {
                                $timePassed = microtime( true ) - $lastCheckTime;
                                if ( $timePassed >= self::LAG_CHECK_PERIOD || $timePassed < 0 ) {
                                        try {
-                                               wfGetLBFactory()->waitForReplication( [
+                                               $lbFactory->waitForReplication( [
                                                        'ifWritesSince' => $lastCheckTime,
                                                        'timeout' => self::MAX_ALLOWED_LAG
                                                ] );
@@ -257,6 +261,7 @@ class JobRunner implements LoggerAwareInterface {
                $msg = $job->toString() . " STARTING";
                $this->logger->debug( $msg );
                $this->debugCallback( $msg );
+               $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
 
                // Run the job...
                $rssStart = $this->getMaxRssKb();
@@ -284,7 +289,7 @@ class JobRunner implements LoggerAwareInterface {
                // Commit all outstanding connections that are in a transaction
                // to get a fresh repeatable read snapshot on every connection.
                // Note that jobs are still responsible for handling slave lag.
-               wfGetLBFactory()->commitAll( __METHOD__ );
+               $lbFactory->commitAll( __METHOD__ );
                // Clear out title cache data from prior snapshots
                LinkCache::singleton()->clear();
                $timeMs = intval( ( microtime( true ) - $jobStartTime ) * 1000 );
index a333d75..0864e5c 100644 (file)
@@ -45,9 +45,9 @@
  */
 class VirtualRESTServiceClient {
        /** @var MultiHttpClient */
-       protected $http;
-       /** @var VirtualRESTService[] Map of (prefix => VirtualRESTService) */
-       protected $instances = [];
+       private $http;
+       /** @var array Map of (prefix => VirtualRESTService|array) */
+       private $instances = [];
 
        const VALID_MOUNT_REGEX = '#^/[0-9a-z]+/([0-9a-z]+/)*$#';
 
@@ -61,15 +61,24 @@ class VirtualRESTServiceClient {
        /**
         * Map a prefix to service handler
         *
+        * If $instance is in array, it must have these keys:
+        *   - class : string; fully qualified VirtualRESTService class name
+        *   - config : array; map of parameters that is the first __construct() argument
+        *
         * @param string $prefix Virtual path
-        * @param VirtualRESTService $instance
+        * @param VirtualRESTService|array $instance Service or info to yield the service
         */
-       public function mount( $prefix, VirtualRESTService $instance ) {
+       public function mount( $prefix, $instance ) {
                if ( !preg_match( self::VALID_MOUNT_REGEX, $prefix ) ) {
                        throw new UnexpectedValueException( "Invalid service mount point '$prefix'." );
                } elseif ( isset( $this->instances[$prefix] ) ) {
                        throw new UnexpectedValueException( "A service is already mounted on '$prefix'." );
                }
+               if ( !( $instance instanceof VirtualRESTService ) ) {
+                       if ( !isset( $instance['class'] ) || !isset( $instance['config'] ) ) {
+                               throw new UnexpectedValueException( "Missing 'class' or 'config' ('$prefix')." );
+                       }
+               }
                $this->instances[$prefix] = $instance;
        }
 
@@ -104,7 +113,7 @@ class VirtualRESTServiceClient {
                };
 
                $matches = []; // matching prefixes (mount points)
-               foreach ( $this->instances as $prefix => $service ) {
+               foreach ( $this->instances as $prefix => $unused ) {
                        if ( strpos( $path, $prefix ) === 0 ) {
                                $matches[] = $prefix;
                        }
@@ -112,8 +121,8 @@ class VirtualRESTServiceClient {
                usort( $matches, $cmpFunc );
 
                // Return the most specific prefix and corresponding service
-               return isset( $matches[0] )
-                       ? [ $matches[0], $this->instances[$matches[0]] ]
+               return $matches
+                       ? [ $matches[0], $this->getInstance( $matches[0] ) ]
                        : [ null, null ];
        }
 
@@ -216,7 +225,7 @@ class VirtualRESTServiceClient {
                        // defer the original or to set a proxy response to the original.
                        $newReplaceReqsByService = [];
                        foreach ( $replaceReqsByService as $prefix => $servReqs ) {
-                               $service = $this->instances[$prefix];
+                               $service = $this->getInstance( $prefix );
                                foreach ( $service->onRequests( $servReqs, $idFunc ) as $index => $req ) {
                                        // Services use unique IDs for replacement requests
                                        if ( isset( $servReqs[$index] ) || isset( $origPending[$index] ) ) {
@@ -250,7 +259,7 @@ class VirtualRESTServiceClient {
                        // forced by setting 'response' rather than actually be sent over the wire.
                        $newReplaceReqsByService = [];
                        foreach ( $checkReqIndexesByPrefix as $prefix => $servReqIndexes ) {
-                               $service = $this->instances[$prefix];
+                               $service = $this->getInstance( $prefix );
                                // $doneReqs actually has the requests (with 'response' set)
                                $servReqs = array_intersect_key( $doneReqs, $servReqIndexes );
                                foreach ( $service->onResponses( $servReqs, $idFunc ) as $index => $req ) {
@@ -288,4 +297,26 @@ class VirtualRESTServiceClient {
 
                return $responses;
        }
+
+       /**
+        * @param string $prefix
+        * @return VirtualRESTService
+        */
+       private function getInstance( $prefix ) {
+               if ( !isset( $this->instances[$prefix] ) ) {
+                       throw new RunTimeException( "No service registered at prefix '{$prefix}'." );
+               }
+
+               if ( !( $this->instances[$prefix] instanceof VirtualRESTService ) ) {
+                       $config = $this->instances[$prefix]['config'];
+                       $class = $this->instances[$prefix]['class'];
+                       $service = new $class( $config );
+                       if ( !( $service instanceof VirtualRESTService ) ) {
+                               throw new UnexpectedValueException( "Registered service has the wrong class." );
+                       }
+                       $this->instances[$prefix] = $service;
+               }
+
+               return $this->instances[$prefix];
+       }
 }
index 84936a4..9ab28aa 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup Cache
  */
 
+use \MediaWiki\MediaWikiServices;
+
 /**
  * Class to store objects in the database
  *
@@ -276,6 +278,7 @@ class SqlBagOStuff extends BagOStuff {
                        if ( isset( $dataRows[$key] ) ) { // HIT?
                                $row = $dataRows[$key];
                                $this->debug( "get: retrieved data; expiry time is " . $row->exptime );
+                               $db = null;
                                try {
                                        $db = $this->getDB( $row->serverIndex );
                                        if ( $this->isExpired( $db, $row->exptime ) ) { // MISS
@@ -284,7 +287,7 @@ class SqlBagOStuff extends BagOStuff {
                                                $values[$key] = $this->unserialize( $db->decodeBlob( $row->value ) );
                                        }
                                } catch ( DBQueryError $e ) {
-                                       $this->handleWriteError( $e, $row->serverIndex );
+                                       $this->handleWriteError( $e, $db, $row->serverIndex );
                                }
                        } else { // MISS
                                $this->debug( 'get: no matching rows' );
@@ -306,10 +309,11 @@ class SqlBagOStuff extends BagOStuff {
                $result = true;
                $exptime = (int)$expiry;
                foreach ( $keysByTable as $serverIndex => $serverKeys ) {
+                       $db = null;
                        try {
                                $db = $this->getDB( $serverIndex );
                        } catch ( DBError $e ) {
-                               $this->handleWriteError( $e, $serverIndex );
+                               $this->handleWriteError( $e, $db, $serverIndex );
                                $result = false;
                                continue;
                        }
@@ -342,7 +346,7 @@ class SqlBagOStuff extends BagOStuff {
                                                __METHOD__
                                        );
                                } catch ( DBError $e ) {
-                                       $this->handleWriteError( $e, $serverIndex );
+                                       $this->handleWriteError( $e, $db, $serverIndex );
                                        $result = false;
                                }
 
@@ -364,6 +368,7 @@ class SqlBagOStuff extends BagOStuff {
 
        protected function cas( $casToken, $key, $value, $exptime = 0 ) {
                list( $serverIndex, $tableName ) = $this->getTableByKey( $key );
+               $db = null;
                try {
                        $db = $this->getDB( $serverIndex );
                        $exptime = intval( $exptime );
@@ -394,7 +399,7 @@ class SqlBagOStuff extends BagOStuff {
                                __METHOD__
                        );
                } catch ( DBQueryError $e ) {
-                       $this->handleWriteError( $e, $serverIndex );
+                       $this->handleWriteError( $e, $db, $serverIndex );
 
                        return false;
                }
@@ -404,6 +409,7 @@ class SqlBagOStuff extends BagOStuff {
 
        public function delete( $key ) {
                list( $serverIndex, $tableName ) = $this->getTableByKey( $key );
+               $db = null;
                try {
                        $db = $this->getDB( $serverIndex );
                        $db->delete(
@@ -411,7 +417,7 @@ class SqlBagOStuff extends BagOStuff {
                                [ 'keyname' => $key ],
                                __METHOD__ );
                } catch ( DBError $e ) {
-                       $this->handleWriteError( $e, $serverIndex );
+                       $this->handleWriteError( $e, $db, $serverIndex );
                        return false;
                }
 
@@ -420,6 +426,7 @@ class SqlBagOStuff extends BagOStuff {
 
        public function incr( $key, $step = 1 ) {
                list( $serverIndex, $tableName ) = $this->getTableByKey( $key );
+               $db = null;
                try {
                        $db = $this->getDB( $serverIndex );
                        $step = intval( $step );
@@ -455,7 +462,7 @@ class SqlBagOStuff extends BagOStuff {
                                $newValue = null;
                        }
                } catch ( DBError $e ) {
-                       $this->handleWriteError( $e, $serverIndex );
+                       $this->handleWriteError( $e, $db, $serverIndex );
                        return null;
                }
 
@@ -473,6 +480,7 @@ class SqlBagOStuff extends BagOStuff {
 
        public function changeTTL( $key, $expiry = 0 ) {
                list( $serverIndex, $tableName ) = $this->getTableByKey( $key );
+               $db = null;
                try {
                        $db = $this->getDB( $serverIndex );
                        $db->update(
@@ -485,7 +493,7 @@ class SqlBagOStuff extends BagOStuff {
                                return false;
                        }
                } catch ( DBError $e ) {
-                       $this->handleWriteError( $e, $serverIndex );
+                       $this->handleWriteError( $e, $db, $serverIndex );
                        return false;
                }
 
@@ -542,6 +550,7 @@ class SqlBagOStuff extends BagOStuff {
         */
        public function deleteObjectsExpiringBefore( $timestamp, $progressCallback = false ) {
                for ( $serverIndex = 0; $serverIndex < $this->numServers; $serverIndex++ ) {
+                       $db = null;
                        try {
                                $db = $this->getDB( $serverIndex );
                                $dbTimestamp = $db->timestamp( $timestamp );
@@ -604,7 +613,7 @@ class SqlBagOStuff extends BagOStuff {
                                        }
                                }
                        } catch ( DBError $e ) {
-                               $this->handleWriteError( $e, $serverIndex );
+                               $this->handleWriteError( $e, $db, $serverIndex );
                                return false;
                        }
                }
@@ -618,13 +627,14 @@ class SqlBagOStuff extends BagOStuff {
         */
        public function deleteAll() {
                for ( $serverIndex = 0; $serverIndex < $this->numServers; $serverIndex++ ) {
+                       $db = null;
                        try {
                                $db = $this->getDB( $serverIndex );
                                for ( $i = 0; $i < $this->shards; $i++ ) {
                                        $db->delete( $this->getTableNameByShard( $i ), '*', __METHOD__ );
                                }
                        } catch ( DBError $e ) {
-                               $this->handleWriteError( $e, $serverIndex );
+                               $this->handleWriteError( $e, $db, $serverIndex );
                                return false;
                        }
                }
@@ -694,26 +704,19 @@ class SqlBagOStuff extends BagOStuff {
         * Handle a DBQueryError which occurred during a write operation.
         *
         * @param DBError $exception
+        * @param IDatabase|null $db DB handle or null if connection failed
         * @param int $serverIndex
         * @throws Exception
         */
-       protected function handleWriteError( DBError $exception, $serverIndex ) {
-               if ( $exception instanceof DBConnectionError ) {
+       protected function handleWriteError( DBError $exception, IDatabase $db = null, $serverIndex ) {
+               if ( !$db ) {
                        $this->markServerDown( $exception, $serverIndex );
-               }
-               if ( $exception->db && $exception->db->wasReadOnlyError() ) {
-                       if ( $exception->db->trxLevel() ) {
-                               if ( !$this->serverInfos ) {
-                                       // Errors like deadlocks and connection drops already cause rollback.
-                                       // For consistency, we have no choice but to throw an error and trigger
-                                       // complete rollback if the main DB is also being used as the cache DB.
-                                       throw $exception;
-                               }
-
-                               try {
-                                       $exception->db->rollback( __METHOD__ );
-                               } catch ( DBError $e ) {
-                               }
+               } elseif ( $db->wasReadOnlyError() ) {
+                       if ( $db->trxLevel() && $this->usesMainDB() ) {
+                               // Errors like deadlocks and connection drops already cause rollback.
+                               // For consistency, we have no choice but to throw an error and trigger
+                               // complete rollback if the main DB is also being used as the cache DB.
+                               throw $exception;
                        }
                }
 
@@ -733,7 +736,7 @@ class SqlBagOStuff extends BagOStuff {
         * @param DBError $exception
         * @param int $serverIndex
         */
-       protected function markServerDown( $exception, $serverIndex ) {
+       protected function markServerDown( DBError $exception, $serverIndex ) {
                unset( $this->conns[$serverIndex] ); // bug T103435
 
                if ( isset( $this->connFailureTimes[$serverIndex] ) ) {
@@ -770,11 +773,19 @@ class SqlBagOStuff extends BagOStuff {
                }
        }
 
+       /**
+        * @return bool Whether the main DB is used, e.g. wfGetDB( DB_MASTER )
+        */
+       protected function usesMainDB() {
+               return !$this->serverInfos;
+       }
+
        protected function waitForSlaves() {
-               if ( !$this->serverInfos ) {
+               if ( $this->usesMainDB() ) {
                        // Main LB is used; wait for any slaves to catch up
                        try {
-                               wfGetLBFactory()->waitForReplication( [ 'wiki' => wfWikiID() ] );
+                               $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+                               $lbFactory->waitForReplication( [ 'wiki' => wfWikiID() ] );
                                return true;
                        } catch ( DBReplicationWaitError $e ) {
                                return false;
index 6396aaa..b3a97f7 100644 (file)
@@ -543,13 +543,8 @@ class Article implements Page {
                                }
                        }
 
-                       # Is it client cached?
-                       if ( $outputPage->checkLastModified( $timestamp ) ) {
-                               wfDebug( __METHOD__ . ": done 304\n" );
-
-                               return;
-                       # Try file cache
-                       } elseif ( $wgUseFileCache && $this->tryFileCache() ) {
+                       # Try to stream the output from file cache
+                       if ( $wgUseFileCache && $this->tryFileCache() ) {
                                wfDebug( __METHOD__ . ": done file cache\n" );
                                # tell wgOut that output is taken care of
                                $outputPage->disable();
index 033eb67..4066501 100644 (file)
@@ -504,13 +504,13 @@ class WikiPage implements Page, IDBAccessObject {
 
        /**
         * Loads page_touched and returns a value indicating if it should be used
-        * @return bool True if not a redirect
+        * @return bool True if this page exists and is not a redirect
         */
        public function checkTouched() {
                if ( !$this->mDataLoaded ) {
                        $this->loadPageData();
                }
-               return !$this->mIsRedirect;
+               return ( $this->mId && !$this->mIsRedirect );
        }
 
        /**
@@ -2873,6 +2873,10 @@ class WikiPage implements Page, IDBAccessObject {
                        return $status;
                }
 
+               // Given the lock above, we can be confident in the title and page ID values
+               $namespace = $this->getTitle()->getNamespace();
+               $dbKey = $this->getTitle()->getDBkey();
+
                // At this point we are now comitted to returning an OK
                // status unless some DB query error or other exception comes up.
                // This way callers don't have to call rollback() if $status is bad
@@ -2893,54 +2897,50 @@ class WikiPage implements Page, IDBAccessObject {
                        $bitfield = 'rev_deleted';
                }
 
-               /**
-                * For now, shunt the revision data into the archive table.
-                * Text is *not* removed from the text table; bulk storage
-                * is left intact to avoid breaking block-compression or
-                * immutable storage schemes.
-                *
-                * For backwards compatibility, note that some older archive
-                * table entries will have ar_text and ar_flags fields still.
-                *
-                * In the future, we may keep revisions and mark them with
-                * the rev_deleted field, which is reserved for this purpose.
-                */
-
-               $row = [
-                       'ar_namespace'  => 'page_namespace',
-                       'ar_title'      => 'page_title',
-                       'ar_comment'    => 'rev_comment',
-                       'ar_user'       => 'rev_user',
-                       'ar_user_text'  => 'rev_user_text',
-                       'ar_timestamp'  => 'rev_timestamp',
-                       'ar_minor_edit' => 'rev_minor_edit',
-                       'ar_rev_id'     => 'rev_id',
-                       'ar_parent_id'  => 'rev_parent_id',
-                       'ar_text_id'    => 'rev_text_id',
-                       'ar_text'       => '\'\'', // Be explicit to appease
-                       'ar_flags'      => '\'\'', // MySQL's "strict mode"...
-                       'ar_len'        => 'rev_len',
-                       'ar_page_id'    => 'page_id',
-                       'ar_deleted'    => $bitfield,
-                       'ar_sha1'       => 'rev_sha1',
-               ];
+               // For now, shunt the revision data into the archive table.
+               // Text is *not* removed from the text table; bulk storage
+               // is left intact to avoid breaking block-compression or
+               // immutable storage schemes.
+               // In the future, we may keep revisions and mark them with
+               // the rev_deleted field, which is reserved for this purpose.
 
-               if ( $wgContentHandlerUseDB ) {
-                       $row['ar_content_model'] = 'rev_content_model';
-                       $row['ar_content_format'] = 'rev_content_format';
-               }
-
-               // Copy all the page revisions into the archive table
-               $dbw->insertSelect(
-                       'archive',
-                       [ 'page', 'revision' ],
-                       $row,
-                       [
-                               'page_id' => $id,
-                               'page_id = rev_page'
-                       ],
-                       __METHOD__
+               // Get all of the page revisions
+               $res = $dbw->select(
+                       'revision',
+                       Revision::selectFields(),
+                       [ 'rev_page' => $id ],
+                       __METHOD__,
+                       'FOR UPDATE'
                );
+               // Build their equivalent archive rows
+               $rowsInsert = [];
+               foreach ( $res as $row ) {
+                       $rowInsert = [
+                               'ar_namespace'  => $namespace,
+                               'ar_title'      => $dbKey,
+                               'ar_comment'    => $row->rev_comment,
+                               'ar_user'       => $row->rev_user,
+                               'ar_user_text'  => $row->rev_user_text,
+                               'ar_timestamp'  => $row->rev_timestamp,
+                               'ar_minor_edit' => $row->rev_minor_edit,
+                               'ar_rev_id'     => $row->rev_id,
+                               'ar_parent_id'  => $row->rev_parent_id,
+                               'ar_text_id'    => $row->rev_text_id,
+                               'ar_text'       => '',
+                               'ar_flags'      => '',
+                               'ar_len'        => $row->rev_len,
+                               'ar_page_id'    => $id,
+                               'ar_deleted'    => $bitfield,
+                               'ar_sha1'       => $row->rev_sha1,
+                       ];
+                       if ( $wgContentHandlerUseDB ) {
+                               $rowInsert['ar_content_model'] = $row->rev_content_model;
+                               $rowInsert['ar_content_format'] = $row->rev_content_format;
+                       }
+                       $rowsInsert[] = $rowInsert;
+               }
+               // Copy them into the archive table
+               $dbw->insert( 'archive', $rowsInsert, __METHOD__ );
                // Save this so we can pass it to the ArticleDeleteComplete hook.
                $archivedRevisionCount = $dbw->affectedRows();
 
index 38eb621..b116bd4 100644 (file)
@@ -4364,7 +4364,11 @@ class Parser {
                $this->startParse( $title, $options, self::OT_WIKI, $clearState );
                $this->setUser( $user );
 
-               $text = str_replace( [ "\r\n", "\r" ], "\n", $text );
+               // We still normalize line endings for backwards-compatibility
+               // with other code that just calls PST, but this should already
+               // be handled in TextContent subclasses
+               $text = TextContent::normalizeLineEndings( $text );
+
                if ( $options->getPreSaveTransform() ) {
                        $text = $this->pstPass2( $text, $user );
                }
@@ -4442,9 +4446,6 @@ class Parser {
                        $text = preg_replace( $p2, '[[\\1]]', $text );
                }
 
-               # Trim trailing whitespace
-               $text = rtrim( $text );
-
                return $text;
        }
 
index cf1a4d0..22c38cb 100644 (file)
@@ -616,36 +616,6 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
                        $form->setId( 'userlogin2' );
                }
 
-               // add pre/post text
-               // header used by ConfirmEdit, CondfirmAccount, Persona, WikimediaIncubator, SemanticSignup
-               // should be above the error message but HTMLForm doesn't support that
-               $form->addHeaderText( $fakeTemplate->get( 'header' ) );
-
-               // FIXME the old form used this for error/warning messages which does not play well with
-               // HTMLForm (maybe it could with a subclass?); for now only display it for signups
-               // (where the JS username validation needs it) and alway empty
-               if ( $this->isSignup() ) {
-                       // used by the mediawiki.special.userlogin.signup.js module
-                       $statusAreaAttribs = [ 'id' => 'mw-createacct-status-area' ];
-                       // $statusAreaAttribs += $msg ? [ 'class' => "{$msgType}box" ] : [ 'style' => 'display: none;' ];
-                       $form->addHeaderText( Html::element( 'div', $statusAreaAttribs ) );
-               }
-
-               // header used by MobileFrontend
-               $form->addHeaderText( $fakeTemplate->get( 'formheader' ) );
-
-               // blank signup footer for site customization
-               if ( $this->isSignup() && $this->showExtraInformation() ) {
-                       // Use signupend-https for HTTPS requests if it's not blank, signupend otherwise
-                       $signupendMsg = $this->msg( 'signupend' );
-                       $signupendHttpsMsg = $this->msg( 'signupend-https' );
-                       if ( !$signupendMsg->isDisabled() ) {
-                               $signupendText = ( $usingHTTPS && !$signupendHttpsMsg->isBlank() )
-                                       ? $signupendHttpsMsg ->parse() : $signupendMsg->parse();
-                               $form->addPostText( Html::rawElement( 'div', [ 'id' => 'signupend' ], $signupendText ) );
-                       }
-               }
-
                // warning header for non-standard workflows (e.g. security reauthentication)
                if ( !$this->isSignup() && $this->getUser()->isLoggedIn() ) {
                        $reauthMessage = $this->securityLevel ? 'userlogin-reauth' : 'userlogin-loggedin';
@@ -653,52 +623,6 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
                                $this->msg( $reauthMessage )->params( $this->getUser()->getName() )->parse() ) );
                }
 
-               if ( !$this->isSignup() && $this->showExtraInformation() ) {
-                       $passwordReset = new PasswordReset( $this->getConfig(), AuthManager::singleton() );
-                       if ( $passwordReset->isAllowed( $this->getUser() ) ) {
-                               $form->addFooterText( Html::rawElement(
-                                       'div',
-                                       [ 'class' => 'mw-ui-vform-field mw-form-related-link-container' ],
-                                       Linker::link(
-                                               SpecialPage::getTitleFor( 'PasswordReset' ),
-                                               $this->msg( 'userlogin-resetpassword-link' )->escaped()
-                                       )
-                               ) );
-                       }
-
-                       // Don't show a "create account" link if the user can't.
-                       if ( $this->showCreateAccountLink() ) {
-                               // link to the other action
-                               $linkTitle = $this->getTitleFor( $this->isSignup() ? 'Userlogin' :'CreateAccount' );
-                               $linkq = $this->getReturnToQueryStringFragment();
-                               // Pass any language selection on to the mode switch link
-                               if ( $wgLoginLanguageSelector && $this->mLanguage ) {
-                                       $linkq .= '&uselang=' . $this->mLanguage;
-                               }
-
-                               $loggedIn = $this->getUser()->isLoggedIn();
-                               $createOrLoginHtml = Html::rawElement( 'div',
-                                       [ 'id' => 'mw-createaccount' . ( !$loggedIn ? '-cta' : '' ),
-                                               'class' => ( $loggedIn ? 'mw-form-related-link-container' : 'mw-ui-vform-field' ) ],
-                                       ( $loggedIn ? '' : $this->msg( 'userlogin-noaccount' )->escaped() )
-                                       . Html::element( 'a',
-                                               [
-                                                       'id' => 'mw-createaccount-join' . ( $loggedIn ? '-loggedin' : '' ),
-                                                       'href' => $linkTitle->getLocalURL( $linkq ),
-                                                       'class' => ( $loggedIn ? '' : 'mw-ui-button' ),
-                                                       'tabindex' => 100,
-                                               ],
-                                               $this->msg(
-                                                       ( $this->getUser()->isLoggedIn() ?
-                                                               'userlogin-createanother' :
-                                                               'userlogin-joinproject'
-                                                       ) )->escaped()
-                                       )
-                               );
-                               $form->addFooterText( $createOrLoginHtml );
-                       }
-               }
-
                $form->suppressDefaultSubmit();
 
                $this->authForm = $form;
@@ -837,7 +761,7 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
                array $requests, array $fieldInfo, array &$formDescriptor, $action
        ) {
                $coreFieldDescriptors = $this->getFieldDefinitions( $this->fakeTemplate );
-               $specialFields = array_merge( [ 'extraInput', 'linkcontainer', 'entryError' ],
+               $specialFields = array_merge( [ 'extraInput' ],
                        array_keys( $this->fakeTemplate->getExtraInputDefinitions() ) );
 
                // keep the ordering from getCoreFieldDescriptors() where there is no explicit weight
@@ -846,14 +770,19 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
                                $formDescriptor[$fieldName] : [];
 
                        // remove everything that is not in the fieldinfo, is not marked as a supplemental field
-                       // to something in the fieldinfo, and is not a generic or B/C field or a submit button
+                       // to something in the fieldinfo, is not B/C for the pre-AuthManager templates,
+                       // and is not an info field or a submit button
                        if (
                                !isset( $fieldInfo[$fieldName] )
                                && (
                                        !isset( $coreField['baseField'] )
                                        || !isset( $fieldInfo[$coreField['baseField']] )
-                               ) && !in_array( $fieldName, $specialFields, true )
-                               && ( !isset( $coreField['type'] ) || $coreField['type'] !== 'submit' )
+                               )
+                               && !in_array( $fieldName, $specialFields, true )
+                               && (
+                                       !isset( $coreField['type'] )
+                                       || !in_array( $coreField['type'], [ 'submit', 'info' ], true )
+                               )
                        ) {
                                $coreFieldDescriptors[$fieldName] = null;
                                continue;
@@ -892,13 +821,12 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
         * @return array
         */
        protected function getFieldDefinitions( $template ) {
-               global $wgEmailConfirmToEdit;
+               global $wgEmailConfirmToEdit, $wgLoginLanguageSelector;
 
                $isLoggedIn = $this->getUser()->isLoggedIn();
                $continuePart = $this->isContinued() ? 'continue-' : '';
                $anotherPart = $isLoggedIn ? 'another-' : '';
-               $expiration = $this->getRequest()->getSession()->getProvider()
-                       ->getRememberUserDuration();
+               $expiration = $this->getRequest()->getSession()->getProvider()->getRememberUserDuration();
                $expirationDays = ceil( $expiration / ( 3600 * 24 ) );
                $secureLoginLink = '';
                if ( $this->mSecureLoginUrl ) {
@@ -910,6 +838,14 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
 
                if ( $this->isSignup() ) {
                        $fieldDefinitions = [
+                               'statusarea' => [
+                                       // used by the mediawiki.special.userlogin.signup.js module for error display
+                                       // FIXME merge this with HTMLForm's normal status (error) area
+                                       'type' => 'info',
+                                       'raw' => true,
+                                       'default' => Html::element( 'div', [ 'id' => 'mw-createacct-status-area' ] ),
+                                       'weight' => -105,
+                               ],
                                'username' => [
                                        'label-message' => 'userlogin-yourname',
                                        // FIXME help-message does not match old formatting
@@ -1056,6 +992,7 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
                                ],
                        ];
                }
+
                $fieldDefinitions['username'] += [
                        'type' => 'text',
                        'name' => 'wpName',
@@ -1072,6 +1009,19 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
                        // 'required' => true,
                ];
 
+               if ( $template->get( 'header' ) || $template->get( 'formheader' ) ) {
+                       // B/C for old extensions that haven't been converted to AuthManager (or have been
+                       // but somebody is using the old version) and still use templates via the
+                       // UserCreateForm/UserLoginForm hook.
+                       // 'header' used by ConfirmEdit, CondfirmAccount, Persona, WikimediaIncubator, SemanticSignup
+                       // 'formheader' used by MobileFrontend
+                       $fieldDefinitions['header'] = [
+                               'type' => 'info',
+                               'raw' => true,
+                               'default' => $template->get( 'header' ) ?: $template->get( 'formheader' ),
+                               'weight' => - 110,
+                       ];
+               }
                if ( $this->mEntryError ) {
                        $fieldDefinitions['entryError'] = [
                                'type' => 'info',
@@ -1082,9 +1032,77 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
                                'weight' => -100,
                        ];
                }
-
                if ( !$this->showExtraInformation() ) {
-                       unset( $fieldDefinitions['linkcontainer'] );
+                       unset( $fieldDefinitions['linkcontainer'], $fieldDefinitions['signupend'] );
+               }
+               if ( $this->isSignup() && $this->showExtraInformation() ) {
+                       // blank signup footer for site customization
+                       // uses signupend-https for HTTPS requests if it's not blank, signupend otherwise
+                       $signupendMsg = $this->msg( 'signupend' );
+                       $signupendHttpsMsg = $this->msg( 'signupend-https' );
+                       if ( !$signupendMsg->isDisabled() ) {
+                               $usingHTTPS = $this->getRequest()->getProtocol() === 'https';
+                               $signupendText = ( $usingHTTPS && !$signupendHttpsMsg->isBlank() )
+                                       ? $signupendHttpsMsg ->parse() : $signupendMsg->parse();
+                               $fieldDefinitions['signupend'] = [
+                                       'type' => 'info',
+                                       'raw' => true,
+                                       'default' => Html::rawElement( 'div', [ 'id' => 'signupend' ], $signupendText ),
+                                       'weight' => 225,
+                               ];
+                       }
+               }
+               if ( !$this->isSignup() && $this->showExtraInformation() ) {
+                       $passwordReset = new PasswordReset( $this->getConfig(), AuthManager::singleton() );
+                       if ( $passwordReset->isAllowed( $this->getUser() ) ) {
+                               $fieldDefinitions['passwordReset'] = [
+                                       'type' => 'info',
+                                       'raw' => true,
+                                       'cssclass' => 'mw-form-related-link-container',
+                                       'default' => Linker::link(
+                                               SpecialPage::getTitleFor( 'PasswordReset' ),
+                                               $this->msg( 'userlogin-resetpassword-link' )->escaped()
+                                       ),
+                                       'weight' => 230,
+                               ];
+                       }
+
+                       // Don't show a "create account" link if the user can't.
+                       if ( $this->showCreateAccountLink() ) {
+                               // link to the other action
+                               $linkTitle = $this->getTitleFor( $this->isSignup() ? 'Userlogin' :'CreateAccount' );
+                               $linkq = $this->getReturnToQueryStringFragment();
+                               // Pass any language selection on to the mode switch link
+                               if ( $wgLoginLanguageSelector && $this->mLanguage ) {
+                                       $linkq .= '&uselang=' . $this->mLanguage;
+                               }
+                               $loggedIn = $this->getUser()->isLoggedIn();
+
+                               $fieldDefinitions['createOrLogin'] = [
+                                       'type' => 'info',
+                                       'raw' => true,
+                                       'linkQuery' => $linkq,
+                                       'default' => function ( $params ) use ( $loggedIn, $linkTitle ) {
+                                               return Html::rawElement( 'div',
+                                                       [ 'id' => 'mw-createaccount' . ( !$loggedIn ? '-cta' : '' ),
+                                                               'class' => ( $loggedIn ? 'mw-form-related-link-container' : 'mw-ui-vform-field' ) ],
+                                                       ( $loggedIn ? '' : $this->msg( 'userlogin-noaccount' )->escaped() )
+                                                       . Html::element( 'a',
+                                                               [
+                                                                       'id' => 'mw-createaccount-join' . ( $loggedIn ? '-loggedin' : '' ),
+                                                                       'href' => $linkTitle->getLocalURL( $params['linkQuery'] ),
+                                                                       'class' => ( $loggedIn ? '' : 'mw-ui-button' ),
+                                                                       'tabindex' => 100,
+                                                               ],
+                                                               $this->msg(
+                                                                       $loggedIn ? 'userlogin-createanother' : 'userlogin-joinproject'
+                                                               )->escaped()
+                                                       )
+                                               );
+                                       },
+                                       'weight' => 235,
+                               ];
+                       }
                }
 
                $fieldDefinitions = $this->getBCFieldDefinitions( $fieldDefinitions, $template );
index 2b43a49..73beafc 100644 (file)
@@ -119,7 +119,12 @@ class SpecialCreateAccount extends LoginSignupSpecialPage {
                                } else {
                                        $out->addWikiMsg( 'accountcreatedtext', $user->getName() );
                                }
-                               $out->addReturnTo( $this->getPageTitle() );
+
+                               $rt = Title::newFromText( $this->mReturnTo );
+                               $out->addReturnTo(
+                                       ( $rt && !$rt->isExternal() ) ? $rt : $this->getPageTitle(),
+                                       wfCgiToArray( $this->mReturnToQuery )
+                               );
                                return;
                        }
                }
index d11fbe6..9cb6d4b 100644 (file)
@@ -91,7 +91,7 @@ class SpecialMyLanguage extends RedirectSpecialArticle {
 
                $uiCode = $this->getLanguage()->getCode();
                $proposed = $base->getSubpage( $uiCode );
-               if ( $uiCode !== $this->getConfig()->get( 'LanguageCode' ) && $proposed && $proposed->exists() ) {
+               if ( $proposed && $proposed->exists() && $uiCode !== $base->getPageLanguage()->getCode() ) {
                        return $proposed;
                } elseif ( $provided && $provided->exists() ) {
                        return $provided;
index ce5533f..e1e2049 100644 (file)
@@ -40,7 +40,6 @@ class SpecialRunJobs extends UnlistedSpecialPage {
 
        public function execute( $par = '' ) {
                $this->getOutput()->disable();
-
                if ( wfReadOnly() ) {
                        // HTTP 423 Locked
                        HttpStatus::header( 423 );
index 8b39d77..cb3b4b8 100644 (file)
@@ -1036,6 +1036,7 @@ class Language {
         *    xin  n (month number) in Iranian calendar
         *    xiy  y (two digit year) in Iranian calendar
         *    xiY  Y (full year) in Iranian calendar
+        *    xit  t (days in month) in Iranian calendar
         *
         *    xjj  j (day number) in Hebrew calendar
         *    xjF  F (month name) in Hebrew calendar
@@ -1331,6 +1332,13 @@ class Language {
                                        }
                                        $num = substr( $iranian[0], -2 );
                                        break;
+                               case 'xit':
+                                       $usedIranianYear = true;
+                                       if ( !$iranian ) {
+                                               $iranian = self::tsToIranian( $ts );
+                                       }
+                                       $num = self::$IRANIAN_DAYS[$iranian[1] - 1];
+                                       break;
                                case 'a':
                                        $usedAMPM = true;
                                        $s .= intval( substr( $ts, 8, 2 ) ) < 12 ? 'am' : 'pm';
index 7bdc097..d6534b6 100644 (file)
        "passwordreset-emailtext-user": "Gebruiker $1 op die webtuiste {{SITENAME}} het u gebruikersgegewens vir {{SITENAME}} ($4) opgevra.\nDie volgende {{PLURAL:$3|gebruiker is|gebruikers is}} aan die e-posadres gekoppel:\n\n$2\n\n{{PLURAL:$3|Die tydelike wagwoord verval|Hierdie tydelike wagwoorde verval}} oor {{PLURAL:$5|een dag|$5 dae}}.\nMeld asseblief aan en verander u wagwoord nou. As u dit nie versoek het nie, of as u die oorspronklike wagwoord nog ken en dit nie wil verander nie, ignoreer die berig en hou aan om u ou wagwoord te gebruik.",
        "passwordreset-emailelement": "Gebruikersnaam: \n$1\n\nTydelike wagwoord: \n$2",
        "passwordreset-emailsentemail": "'n E-pos is gestuur om u wagwoord te herstel.",
-       "passwordreset-emailsent-capture": "'n E-pos vir die herstel van 'n wagwoord is gestuur. Dit word hieronder vertoon.",
-       "passwordreset-emailerror-capture": "'n E-pos vir die herstel van 'n wagwoord is saamgestel. Dit word hieronder vertoon. Die uitstuur daarvan na die {{GENDER:$2|gebruiker}} het egter gefaal: $1",
        "changeemail": "Wysig E-posadres",
        "changeemail-header": "Wysig rekening se e-posadres",
        "changeemail-no-info": "U moet aangemeld wees om regstreeks toegang tot die bladsy te kry.",
        "undo-nochange": "Die wysiging is klaarblyklik reeds teruggerol.",
        "undo-summary": "Rol weergawe $1 deur [[Special:Contributions/$2|$2]] ([[User talk:$2|bespreek]]) terug.",
        "undo-summary-username-hidden": "Rol weergawe $1 deur 'n versteekte gebruiker terug",
-       "cantcreateaccounttitle": "Kan nie rekening skep nie",
        "cantcreateaccount-text": "Die registrasie van nuwe rekeninge vanaf die IP-adres ('''$1''') is geblok deur [[User:$3|$3]].\n\nDie rede verskaf deur $3 is ''$2''",
        "viewpagelogs": "Bekyk logboeke vir hierdie bladsy",
        "nohistory": "Daar is geen wysigingsgeskiedenis vir hierdie bladsy nie.",
        "mediastatistics-header-total": "Alle lêers",
        "json-error-syntax": "Sintaksfout",
        "headline-anchor-title": "Skakel na die afdeling",
-       "special-characters-group-latin": "Latyns",
-       "special-characters-group-latinextended": "Latyns uitgebreid",
+       "special-characters-group-latin": "Latyn",
+       "special-characters-group-latinextended": "Latyn uitgebrei",
        "special-characters-group-ipa": "IFA",
        "special-characters-group-symbols": "Simbole",
        "special-characters-group-greek": "Grieks",
+       "special-characters-group-greekextended": "Grieks uitgebrei",
        "special-characters-group-cyrillic": "Cyrillies",
        "special-characters-group-arabic": "Arabies",
        "special-characters-group-arabicextended": "Arabies uitgebrei",
        "special-characters-group-gujarati": "Gujarati",
        "special-characters-group-devanagari": "Devanagari",
        "special-characters-group-thai": "Thai",
-       "special-characters-group-lao": "Lao",
+       "special-characters-group-lao": "Laosiaans",
        "special-characters-group-khmer": "Khmer",
        "special-characters-title-minus": "minusteken",
        "mw-widgets-dateinput-no-date": "Geen datum gekies nie",
index 5e8b4b2..3b40a05 100644 (file)
        "activeusers-hidebots": "أخف البوتات",
        "activeusers-hidesysops": "أخف الإداريين",
        "activeusers-noresult": "لم يعثر على أي مستخدمين",
-       "activeusers-submit": "لعرض المستخدمين النشطين",
+       "activeusers-submit": "عرض المستخدمين النشطين",
        "listgrouprights": "صلاحيات مجموعات المستخدمين",
        "listgrouprights-summary": "التالي قائمة بمجموعات المستخدمين المعرفة في هذا الويكي، بصلاحياتهم المصاحبة.\nربما تكون هناك [[{{MediaWiki:Listgrouprights-helppage}}|معلومات إضافية]] حول الصلاحيات المنفردة.",
        "listgrouprights-key": "عنوان:\n* <span class=\"listgrouprights-granted\">صلاحية ممنوحة</span>\n* <span class=\"listgrouprights-revoked\">صلاحية مسحوبة</span>",
index e5a0f8d..51f186e 100644 (file)
        "tagline": "Зьвесткі з {{GRAMMAR:родны|{{SITENAME}}}}",
        "help": "Дапамога",
        "search": "Пошук",
-       "search-ignored-headings": " #<!-- не зьмяняйце гэты радок --> <pre>\n# Загалоўкі, якія мусіць ігнараваць пошукавы рухавік.\n# Зьмены будуць ужытыя па наступным індэксаваньні старонкі.\n# Вы можаце змусіць пераіндэксаваць старонку пустым рэдагаваньнем.\n# Сынтакс наступны:\n#   * Усё, што пачынаецца з \"#\" — камэнтар\n#   * Усякі непусты радок — загаловак, які трэба ігнараваць\nКрыніцы\nВонкавыя спасылкі\nГлядзіце таксама\n #</pre> <!-- не зьмяняйце гэты радок -->",
+       "search-ignored-headings": " #<!-- не зьмяняйце гэты радок --> <pre>\n# Загалоўкі, якія мусіць ігнараваць пошукавы рухавік.\n# Зьмены будуць ужытыя па наступным індэксаваньні старонкі.\n# Вы можаце змусіць пераіндэксаваць старонку пустым рэдагаваньнем.\n# Сынтакс наступны:\n#   * Усё, што пачынаецца з «#» і да канца радку — камэнтар\n#   * Усякі непусты радок — загаловак, які трэба ігнараваць\nКрыніцы\nВонкавыя спасылкі\nГлядзіце таксама\n #</pre> <!-- не зьмяняйце гэты радок -->",
        "searchbutton": "Пошук",
        "go": "Старонка",
        "searcharticle": "Старонка",
        "grant-group-high-volume": "Выкананьне дзеяньняў з высокай інтэнсіўнасьцю",
        "grant-group-customization": "Налады і перавагі",
        "grant-group-administration": "Выкананьне адміністрацыйных дзеяньняў",
+       "grant-group-private-information": "Доступ да прыватных зьвестак пра вас",
        "grant-group-other": "Розная актыўнасьць",
        "grant-blockusers": "Блякаваньне і разблякаваньне ўдзельнікаў",
        "grant-createaccount": "Стварыць рахункі",
        "grant-highvolume": "Рэдагаваньне з высокай інтэнсіўнасьцю",
        "grant-oversight": "Хаваньне ўдзельнікаў і вэрсіяў старонак",
        "grant-patrol": "Патруляваньне зьменаў старонак",
+       "grant-privateinfo": "Доступ да прыватных зьвестак",
        "grant-protect": "Абарона і зьняцьце абароны старонак",
        "grant-rollback": "Адкат зьменаў старонак",
        "grant-sendemail": "Адпраўка лістоў электроннай пошты іншым удзельнікам",
        "uploadstash-errclear": "Не атрымалася ачысьціць файлы.",
        "uploadstash-refresh": "Абнавіць сьпіс файлаў.",
        "uploadstash-thumbnail": "прагляд мініятуры",
+       "uploadstash-exception": "Не магу захаваць загрузку ў сховішчы ($1): «$2».",
        "invalid-chunk-offset": "Няслушнае зрушэньне фрагмэнту",
        "img-auth-accessdenied": "Доступ забаронены",
        "img-auth-nopathinfo": "Адсутнічае PATH_INFO.\nВаш сэрвэр не ўстаноўлены на пропуск гэтай інфармацыі.\nМагчма, ён працуе праз CGI і не падтрымлівае img_auth.\nГлядзіце https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "undeletedrevisions": "{{PLURAL:$1|адноўленая $1 вэрсія|адноўленыя $1 вэрсіі|адноўленыя $1 вэрсіяў}}",
        "undeletedrevisions-files": "адноўленыя $1 {{PLURAL:$1|вэрсія|вэрсіі|вэрсіяў}} і $2 {{PLURAL:$2|файл|файлы|файлаў}}",
        "undeletedfiles": "{{PLURAL:$1|адноўлены $1 файл|адноўленыя $1 файлы|адноўленыя $1 файлаў}}",
-       "cannotundelete": "Ð\9fамÑ\8bлка Ð°Ð´Ð½Ð°Ñ\9eленÑ\8cня:\n$1",
+       "cannotundelete": "Ð\9dекаÑ\82оÑ\80Ñ\8bÑ\8f Ð°Ð±Ð¾ Ñ\9eÑ\81е Ð°Ð´Ð½Ð°Ñ\9eленÑ\8cнÑ\96 Ð½Ðµ Ð±Ñ\8bлÑ\96 Ð²Ñ\8bкананÑ\8bя:\n$1",
        "undeletedpage": "'''Старонка $1 была адноўленая'''\n\nГлядзіце [[Special:Log/delete|журнал выдаленьняў]] для прагляду апошніх выдаленьняў і аднаўненьняў.",
        "undelete-header": "Глядзіце [[Special:Log/delete|журнал выдаленьняў]] для прагляду апошніх выдаленьняў.",
        "undelete-search-title": "Пошук выдаленых старонак",
        "sp-contributions-newbies-sub": "Унёсак пачынаючых",
        "sp-contributions-newbies-title": "Унёсак удзельнікаў з новых рахункаў",
        "sp-contributions-blocklog": "журнал блякаваньняў",
-       "sp-contributions-suppresslog": "выдалены ўнёсак удзельніка",
-       "sp-contributions-deleted": "выдалены ўнёсак удзельніка",
+       "sp-contributions-suppresslog": "выдалены ўнёсак {{GENDER:$1|удзельніка|удзельніцы}}",
+       "sp-contributions-deleted": "выдалены ўнёсак {{GENDER:$1|удзельніка|удзельніцы}}",
        "sp-contributions-uploads": "загрузкі",
        "sp-contributions-logs": "журналы падзеяў",
        "sp-contributions-talk": "гутаркі",
        "log-action-filter-import": "Тып імпарту:",
        "log-action-filter-move": "Тып пераносу:",
        "log-action-filter-all": "Усе",
+       "log-action-filter-block-block": "Заблякаваць",
+       "log-action-filter-block-reblock": "Зьмяненьне блякаваньня",
+       "log-action-filter-block-unblock": "Разблякаваць",
+       "log-action-filter-contentmodel-change": "Зьмена мадэлі зьместу",
+       "log-action-filter-delete-delete": "Выдаленьне старонкі",
+       "log-action-filter-delete-restore": "Аднаўленьне старонкі",
+       "log-action-filter-delete-event": "Выдаленьне журналу",
+       "log-action-filter-delete-revision": "Выдаленьне вэрсіі",
+       "log-action-filter-managetags-create": "Стварэньне цэтлікаў",
+       "log-action-filter-managetags-delete": "Выдаленьне цэтлікаў",
+       "log-action-filter-managetags-activate": "Актывацыя цэтлікаў",
+       "log-action-filter-managetags-deactivate": "Дэактывацыя цэтлікаў",
+       "log-action-filter-newusers-autocreate": "Аўтаматычнае стварэньне",
+       "log-action-filter-patrol-autopatrol": "Аўтаматычнае патруляваньне",
+       "log-action-filter-protect-protect": "Абарона",
+       "log-action-filter-protect-unprotect": "Зьняцьце абароны",
+       "log-action-filter-rights-autopromote": "Аўтаматычнае зьмяненьне",
+       "log-action-filter-upload-upload": "Новая загрузка",
+       "authmanager-realname-label": "Сапраўднае імя",
+       "authmanager-provider-temporarypassword": "Часовы пароль",
        "changecredentials": "Зьмена ўліковых зьвестак",
        "removecredentials": "Выдаленьне ўліковых зьвестак",
        "removecredentials-submit": "Выдаліць уліковыя зьвесткі",
index 5252461..42348b0 100644 (file)
        "tagline": "З пляцоўкі {{SITENAME}}",
        "help": "Даведка",
        "search": "Знайсці",
+       "search-ignored-headings": " #<!-- не змяняйце гэты радок --> <pre>\n# Загалоўкі, якія будзе ігнараваць рухавік пошуку.\n# Змены набудуць моц па наступным індэксаванні старонкі.\n# Вы можаце змусіць пераіндэксаванне старонкі, зрабіўшы пустое рэдагаванне.\n# Сінтаксіс наступны:\n#   * Усё ад сімвала \"#\" да канца радка - каментарый.\n#   * Кожны непусты радок - дакладны загаловак, які трэба ігнараваць, з рэгістрам і інш.\nКрыніцы\nСпасылкі\nГл. таксама\n #</pre> <!-- не змяняйце гэты радок -->",
        "searchbutton": "Знайсці",
        "go": "Пераход",
        "searcharticle": "Артыкул",
        "nocookiesnew": "Рахунак быў створаны, але ў сістэму вы не ўвайшлі. {{SITENAME}} карыстаецца квіткамі (кукі), каб апрацоўваць уваходы ўдзельнікаў, а гэтая функцыянальнасць адключана ў вашым браўзеры. Уключыце квіткі ў браўзеры, тады ўваходзьце са сваімі новымі імем удзельніка і паролем.",
        "nocookieslogin": "{{SITENAME}} карыстаецца квіткамі (кукі), каб пазнаваць удзельнікаў. У вашым браўзеры квіткі не дазволены. Дазвольце іх працу і паспрабуйце ізноў.",
        "nocookiesfornew": "Уліковы запіс карыстальніка не быў створаны, бо мы не змаглі пацвердзіць яго крыніцы. \nУпэўніцеся, што кукі ўключаныя, абнавіце старонку і паспрабуйце яшчэ раз.",
-       "createacct-loginerror": "Уліковы запіс быў паспяхова створаны, але Вы не змаглі аўтарызавацц аўтаматычна. Калі ласка, перайдзіце да старонкі [[Адмысловае:Імя_ўдзельніка|ручной аўтарызацыі]].",
+       "createacct-loginerror": "Уліковы запіс быў паспяхова створаны, але Вы не змаглі аўтарызавацца аўтаматычна. Калі ласка, перайдзіце да старонкі [[Special:UserLogin|ручной аўтарызацыі]].",
        "noname": "Вы не вызначылі правільнага імя ўдзельніка.",
        "loginsuccesstitle": "Паспяховы ўваход у сістэму",
        "loginsuccess": "<strong>Цяпер Вы ўвайшлі на {{SITENAME}} як \"$1\".</strong>",
        "passwordreset-emailelement": "Імя ўдзельніка: \n$1\n\nЧасовы пароль: \n$2",
        "passwordreset-emailsentemail": "Калі гэты адрас электроннай пошты злучаны з вашым уліковым запісам, будзе адпраўлены ліст пра скід пароля.",
        "passwordreset-emailsentusername": "Калі ёсць адрас электроннай пошты, злучаны з гэтым імем удзельніка, то будзе дасланы ліст пра скід пароля.",
+       "passwordreset-emailsent-capture2": "{{PLURAL:$1|Электронны ліст|электронныя лісты}} скіду пароля адпраўлены. {{PLURAL:$1|Імя ўдзельніка і пароль|Спіс імён удзельнікаў і паролі}} паказаны ніжэй.",
        "passwordreset-invalideamil": "Няслушны адрас электроннай пошты",
        "passwordreset-nodata": "Не былі пададзены ні імя ўдзельніка, ні адрас электроннай пошты",
        "changeemail": "Змяніць або выдаліць адрас электроннай пошты",
index 8a8fe7b..5e989ef 100644 (file)
        "linkaccounts-submit": "Benutzerkonten verknüpfen",
        "unlinkaccounts": "Benutzerkonten trennen",
        "unlinkaccounts-success": "Das Benutzerkonto wurde getrennt.",
-       "authenticationdatachange-ignored": "Die Änderung der Authentifizierungsdaten wurde nicht bearbeitet. Vielleicht wurde kein Anbieter konfiguriert?"
+       "authenticationdatachange-ignored": "Die Änderung der Authentifizierungsdaten wurde nicht bearbeitet. Vielleicht wurde kein Anbieter konfiguriert?",
+       "userjsispublic": "Bitte beachten: JavaScript-Unterseiten sollten keine vertraulichen Daten enthalten, da sie von anderen Benutzern eingesehen werden können.",
+       "usercssispublic": "Bitte beachten: CSS-Unterseiten sollten keine vertraulichen Daten enthalten, da sie von anderen Benutzern eingesehen werden können."
 }
index 8a60608..a99ff64 100644 (file)
        "undo-summary": "Vırnayışê $1'i [[Special:Contributions/$2|$2i]] ([[User talk:$2|Werênayış]]) peyser gırot",
        "undo-summary-username-hidden": "Rewizyona veri $1'i hewada",
        "cantcreateaccount-text": "Hesabvıraştışê na IP adrese ('''$1''') terefê [[User:$3|$3]] kılit biyo.\n\nSebebo ke terefê $3 ra diyao ''$2''",
-       "viewpagelogs": "Qeydanê ena perer bıvin",
+       "viewpagelogs": "Qeydanê na pele bımocne",
        "nohistory": "Verê vurnayışanê na pele çıniyo.",
        "currentrev": "Çımraviyarnayışo rocane",
        "currentrev-asof": "$1 ra tepya mewcud weziyeta pela",
        "last": "peyên",
        "page_first": "verên",
        "page_last": "peyên",
-       "histlegend": "Ferqê weçinıtışi: Qutiya versiyonan qandé pêver sanayış işaret ke u dest be ''enter''i ya zi gocega cêrêne ro ne.<br />\nCedwel: <strong>({{int:ferq}})</strong> = ferqê versiyonê peyêni, <strong>({{int:peyên}})</strong> = ferqê versiyonê verêni, <strong>{{int:q}}</strong> = vurnayışo werdi.",
+       "histlegend": "Ferqê weçinıtışi: Qutiya versiyonan seba têversanayış işaret ke û dest be ''enter''i ya zi gocega cêrêne ro ne.<br />\nCedwel: <strong>({{int:ferq}})</strong> = ferqê verziyonê peyêni, <strong>({{int:peyên}})</strong> = ferqê versiyonê verêni, <strong>{{int:q}}</strong> = vurnayışo werdi.",
        "history-fieldset-title": "Tarixi bıvêne",
        "history-show-deleted": "Tenya esterıtey",
        "histfirst": "Verênêr",
        "lineno": "Xeta $1:",
        "compareselectedversions": "Rewizyonanê weçineyan pêver ke",
        "showhideselectedversions": "Revizyonanê weçinıtan bımocne/bınımne",
-       "editundo": "peyser bıgê",
+       "editundo": "peyser biya",
        "diff-empty": "(Babetna niyo)",
        "diff-multi-sameuser": "(Terefê eyni karberi ra {{PLURAL:$1|yew revizyono miyanên nêmocno|$1 revizyonê miyanêni nêmocnê}})",
        "diff-multi-otherusers": "(Terefê {{PLURAL:$2|yew karberi|$2 karberan}} ra {{PLURAL:$1|yew revizyono miyanên nêmocno|$1 revizyonê miyanêni nêmocnê}})",
        "recentchanges-summary": "Wiki sero vurriyayışê peyêni asenê.",
        "recentchanges-noresult": "Goreyê kriteranê kıfşkerdeyan ra qet yew vurnayış nêvêniya.",
        "recentchanges-feed-description": "Ena feed dı vurnayişanê tewr peniyan teqip bık.",
-       "recentchanges-label-newpage": "Pera newiy vıraziya ya",
+       "recentchanges-label-newpage": "Enê vurnayışi ra yew pela newiye vıraziye",
        "recentchanges-label-minor": "Vurriyayışo werdiyo",
-       "recentchanges-label-bot": "Ena vırnayışa boti ya",
+       "recentchanges-label-bot": "Eno vurnayış terefê yew boti ra vıraziyo",
        "recentchanges-label-unpatrolled": "Eno vurnayış hewna dewriya nêbiyo",
-       "recentchanges-label-plusminus": "No nımre erca ebata perer asıneno (maypuşt)",
+       "recentchanges-label-plusminus": "Ebadê pele de bazê bayti de vayeyê cı",
        "recentchanges-legend-heading": "<strong>Kıtabekê Vurriyayışê peyêni:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|Lista pelanê neweyan]] zi bıvêne)",
        "recentchanges-legend-plusminus": "''(±123)''",
        "recentchangeslinked-summary": "Lista cêrêne, pela bêlikerdiye rê (ya zi karberanê kategoriya bêlikerdiye rê) pelanê gırêdayoğan de lista de vurnayışê peyênana.\n[[Special:Watchlist|Lista şımaya seyrkedışi de]] peli be nuşteyo '''qolınd''' bêli kerdê.",
        "recentchangeslinked-page": "Nameyê pele:",
        "recentchangeslinked-to": "Heruna pela ke yena dayene, vurnayışanê pelanê ke daye ra gırêdayiyê inan bımocne",
-       "recentchanges-page-added-to-category": "[[:$1]] de kerd kategori miyan",
+       "recentchanges-page-added-to-category": "[[:$1]] kerd kategoriye miyan",
        "recentchanges-page-removed-from-category": "[[:$1]] kategoriye ra vet",
        "autochange-username": "MediaWiki vurnayışo otomatik",
        "upload": "Dosya bar ke",
index fd75693..61e06c0 100644 (file)
        "versionrequiredtext": "ये पाना प्रयोग गर्नका लागि MediaWiki $1 संस्करण चाहिन्छ ।\nहेर  [[Special:Version|version page]]",
        "ok": "भयो",
        "retrievedfrom": " \"$1\" बठे निकालिया",
-       "youhavenewmessages": "तमखी लेखा($3)मी $1 ($2) छ ।",
+       "youhavenewmessages": "तमखी लेखा($3)मी $1($2) छ ।",
        "youhavenewmessagesfromusers": "तमखी लेखा {{PLURAL:$3|प्रयोगकर्ता|$3 प्रयोगकर्तान}}($2)बठे$1",
        "youhavenewmessagesmanyusers": "तमलाई धेरै प्रयोगकर्ताहरू($2) बठे $1 छ ।",
        "newmessageslinkplural": "{{PLURAL:$1|एक नौलो रैबार|999=नौला रैबारहरू}}",
        "title-invalid-interwiki": "अनुरोध गरियाको शिर्षकमी अन्तर विकि लिङ्क छ जइलाई शिर्षकमी प्रयोग गद्द नाइपाइनो ।",
        "title-invalid-talk-namespace": "निवेदन गरियाको पानाको शिर्षकले उपलब्ध नभएका कुरडी पानालाई सन्दर्भको रूपमी राख्याको छ ।",
        "title-invalid-characters": "निवेदन गरियाको यै पानाको शिर्षकमी अवैध अक्षर रयाको छः \"$1\" ।",
+       "title-invalid-leading-colon": "निवेदन गरिया पृष्ठको शिर्षकको शुरूमी अवैध कोलोन रया छ ।",
+       "perfcached": "तलका डाटाहरू क्याचमी रया कुराहरू हुन्। अपटुडेट नहुन लाई सक्दान। बर्ति {{PLURAL:$1|नतिजा|$1 नतिजाहरू}} क्याचमी उपलब्ध छ।",
+       "perfcachedts": "तलतिरको आँकडा क्याच हो र $1 पहिला अद्यतन गरिया थ्यो। येई क्याचमी उपलब्ध {{PLURAL:$4|एउटा कारण हो|$4 कारणहरू हुन्}}।",
        "viewsource": "स्रोत हेर",
        "viewsource-title": " $1 को स्रोत हेर",
        "actionthrottled": "कार्य रोकिईयो",
        "prefs-rc": "नौला परिवर्तनहरू",
        "prefs-watchlist": "मेरो ध्यान सूची",
        "prefs-editwatchlist": "अवलोकनसूची सम्पादन",
+       "prefs-editwatchlist-label": "आफना अवलोकनसूचीमी रया इन्ट्रीलाई सम्पादन गर:",
+       "prefs-editwatchlist-edit": "आफना अवलोकनसूचीमी रया शीर्षकलाई धेकाउन्या तथा हटाउन्या",
        "prefs-editwatchlist-raw": "कच्चा अवलोकनसूची सम्पादन गद्दा",
        "prefs-editwatchlist-clear": "तमरो अवलोकनसूची मेटा",
        "prefs-watchlist-days": "ध्यान सूचीमी धेकाउने दिनहरू:",
+       "prefs-watchlist-days-max": "भौत $1 {{PLURAL:$1|दिन|दिन}}",
+       "prefs-watchlist-edits": "उच्चतम परिवर्तन संख्या बढाइएको निगरानी सूचीमी  धकाउनका लागि :",
        "prefs-watchlist-edits-max": "सबै है ज्यादा संख्या : १०००",
        "prefs-watchlist-token": "अवलोकन सूची टोकन:",
        "prefs-misc": "साधारण",
        "prefs-resetpass": "पासवर्ड परिवर्तन गर",
-       "prefs-changeemail": "à¤\87मà¥\87ल à¤ªà¤°à¤¿à¤µà¤°à¥\8dतन à¤\97रà¥\8dनà¥\8dया",
+       "prefs-changeemail": "à¤\87मà¥\87ल à¤ à¥\87à¤\97ाना à¤¬à¤¦à¥\87ल à¤µà¤¾ à¤¹à¤\9fा",
        "prefs-setemail": "इमेल ठेगाना प्रविष्ट गर्न्या",
        "prefs-email": "इमेल  विकल्पहरू",
        "prefs-rendering": "स्वरुप",
        "saveprefs": "संग्रह",
+       "restoreprefs": "सबै पूर्वनिर्धारित स्थिती कायम गर्ने(सबै खण्डहरूमी)",
        "prefs-editing": "सम्पादन",
        "rows": "हरफहरू :",
        "columns": "स्तम्भहरू :",
        "right-sendemail": "अन्य प्रयोगकर्तानलाई इमेल पठाउन्या",
        "grant-editmycssjs": "तमरो प्रयोगकर्ता CSS/JavaScript सम्पादन गर",
        "grant-editmyoptions": "तमरा प्रयोगकर्ता अभिरूचीहरूलाई सम्पादन गर",
+       "grant-editmywatchlist": "तमरो अवलोकनसूची सम्पादन गर",
+       "grant-editpage": "भैरया पृष्ठहरू सम्पादन गर",
+       "grant-editprotected": "सुरक्षित पृष्ठ सम्पादन",
+       "grant-highvolume": "उच्च मात्रा सम्पादन",
+       "grant-basic": "आधारभूत अधिकार",
+       "grant-viewdeleted": "नयाँ फाइलहरू अपलोड\nसम्पादन गर",
+       "grant-viewmywatchlist": "आफनो अबलोकन सुची हेर",
        "newuserlogpage": "प्रयोगकर्ता श्रृजना लग",
+       "action-move": "ये पानालाई अर्खिठौर सार",
        "action-move-subpages": "यै पानाको रे यैका उपपानाको नाम बदल्न्या",
+       "action-move-rootuserpages": "मूल प्रयोगकर्ता पृष्ठहरू सार्ने",
+       "action-move-categorypages": "श्रेणी पृष्ठ सार",
+       "action-movefile": "ये फाईललाइ सार",
+       "action-upload": "ये फाइल अपलोड गर",
        "action-unwatchedpages": "कसैले ध्यान नराख्याका पाननको सूची हेद्या",
        "action-userrights-interwiki": "अन्य विकिका प्रयोगकर्तानको प्रयोगकर्ता अधिकार सम्पादन गद्या",
        "action-applychangetags": "तमरो परिवर्तनसँगै ट्यागहरू लागु गर्न्या",
index e1c37c8..892ac2c 100644 (file)
        "linkaccounts-submit": "Link accounts",
        "unlinkaccounts": "Unlink accounts",
        "unlinkaccounts-success": "The account was unlinked.",
-       "authenticationdatachange-ignored": "The authentication data change was not handled. Maybe no provider was configured?"
+       "authenticationdatachange-ignored": "The authentication data change was not handled. Maybe no provider was configured?",
+       "userjsispublic": "Please note: JavaScript subpages should not contain confidential data as they are viewable by other users.",
+       "usercssispublic": "Please note: CSS subpages should not contain confidential data as they are viewable by other users."
 }
index 10e56f2..13eb863 100644 (file)
        "actionfailed": "Ago malsukcesis",
        "deletedtext": "\"$1\" estas forigita.\nVidu la paĝon $2 por registro de lastatempaj forigoj.",
        "dellogpage": "Protokolo pri forigoj",
-       "dellogpagetext": "Jen listo de la plej lastaj forigoj el la datumaro.\nĈiuj tempoj sekvas la horzonon UTC.",
+       "dellogpagetext": "Jen listo de la plej lastaj forigoj.",
        "deletionlog": "protokolo pri forigoj",
        "reverted": "Malfaris al antaŭa revisio",
        "deletecomment": "Kialo:",
index 3d1d039..7099422 100644 (file)
        "permissionserrors": "Error de permisos",
        "permissionserrorstext": "No tienes permiso para hacer eso, por {{PLURAL:$1|el siguiente motivo|los siguientes motivos}}:",
        "permissionserrorstext-withaction": "No tienes permiso para $2, por {{PLURAL:$1|el siguiente motivo|los siguientes motivos}}:",
-       "contentmodelediterror": "No puedes editar esta revisión porque su modelo de contenido es <code>$1</code>, la cual difiere del modelo actual de la página <code>$2</code>.",
+       "contentmodelediterror": "No puedes editar esta revisión porque su modelo de contenido es <code>$1</code>, que difiere del modelo actual de contenido de la página <code>$2</code>.",
        "recreate-moveddeleted-warn": "<strong>Atención: estás volviendo a crear una página que ha sido borrada anteriormente.</strong>\n\nPiensa si es adecuado continuar editando la página.\nA continuación, se proporciona el registro de borrado y traslados de esta página para más información:",
        "moveddeleted-notice": "Esta página ha sido borrada.\nA continuación, se proporciona el registro de borrados y traslados de la página para más información.",
-       "moveddeleted-notice-recent": "Esta página se ha eliminado recientemente (dentro de las últimas 24 horas).\nEl registro de eliminación y traslado de la página se muestran a continuación como referencia.",
+       "moveddeleted-notice-recent": "Esta página se ha eliminado recientemente (durante las últimas 24 horas).\nEl registro de eliminación y traslado de la página se muestran a continuación como referencia.",
        "log-fulllog": "Ver el registro completo",
        "edit-hook-aborted": "Una extensión ha evitado la edición.\nNo hay explicación disponible.",
        "edit-gone-missing": "No se ha podido actualizar la página.\nParece haber sido borrada.",
        "content-json-empty-object": "Objeto vacío",
        "content-json-empty-array": "Matriz vacía",
        "deprecated-self-close-category": "Páginas que utilizan etiquetas HTML autocerradas no válidas",
-       "deprecated-self-close-category-desc": "Esta página contiene etiquetas HTML de auto-cierre invalidas, tales como <code>&lt;b/></code> o <code>&lt;span/></code>. El comportamiento de estas en  cambiará pronto para ser coherente con la especificación de HTML5, por lo que su utilización en wikitext está en desuso.",
+       "deprecated-self-close-category-desc": "Esta página contiene etiquetas HTML de autocierre inválidas, tales como <code>&lt;b/></code> o <code>&lt;span/></code>. El comportamiento de estas cambiará pronto para ser coherente con la especificación de HTML5, por lo que su utilización en el wikitexto está en desuso.",
        "duplicate-args-warning": "<strong>Aviso:</strong> [[:$1]] llama a [[:$2]] con más de un valor para el parámetro «$3». Se usará solo el último valor proporcionado.",
        "duplicate-args-category": "Páginas que usan argumentos duplicados en invocaciones de plantillas",
        "duplicate-args-category-desc": "La página contiene invocaciones de plantillas que utilizan argumentos duplicados, como <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> o <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "expensive-parserfunction-warning": "<strong>Advertencia:</strong> esta página contiene demasiadas llamadas a funciones sintácticas costosas.\n\nTiene {{PLURAL:$1|una llamada|$1 llamadas}}, pero debería tener menos de {{PLURAL:$2|una|$2}}.",
-       "expensive-parserfunction-category": "Páginas con llamadas a funciones sintácticas demasiado costosas",
+       "expensive-parserfunction-category": "Páginas con demasiadas llamadas a funciones sintácticas costosas",
        "post-expand-template-inclusion-warning": "<strong>Aviso:</strong> El tamaño de las plantillas incluidas es muy grande.\nAlgunas de ellas no se incluirán.",
        "post-expand-template-inclusion-category": "Páginas con sobrecarga de plantillas",
        "post-expand-template-argument-warning": "Aviso: Esta página contiene al menos un parámetro de plantilla con un tamaño de expansión demasiado grande.\nSe han descartado esos parámetros.",
        "grant-group-high-volume": "Realizar actividad de volumen alto",
        "grant-group-customization": "Personalización y preferencias",
        "grant-group-administration": "Realizar acciones administrativas",
+       "grant-group-private-information": "Acceder a información privada sobre ti",
        "grant-group-other": "Actividades diversas",
        "grant-blockusers": "Bloquear y desbloquear usuarios",
        "grant-createaccount": "Crear cuentas",
        "grant-highvolume": "Gran cantidad de ediciones",
        "grant-oversight": "Ocultar a los usuarios y suprimir las revisiones",
        "grant-patrol": "Verificar cambios a páginas",
+       "grant-privateinfo": "Acceder a información privada",
        "grant-protect": "Proteger y desproteger páginas",
        "grant-rollback": "Revertir cambios a páginas",
        "grant-sendemail": "Enviar un correo electrónico a otros usuarios",
        "linkaccounts-submit": "Vincular cuentas",
        "unlinkaccounts": "Desvincular cuentas",
        "unlinkaccounts-success": "Se ha desvinculado la cuenta.",
-       "authenticationdatachange-ignored": "El cambio den los datos de autentificacion no fue realizado. ¿Tal vez, no se configuró un proveedor?"
+       "authenticationdatachange-ignored": "El cambio den los datos de autentificacion no fue realizado. ¿Tal vez, no se configuró un proveedor?",
+       "userjsispublic": "Recuerda: Las subpáginas JavaScript no deberían contener datos confidenciales, pues otros usuarios los pueden ver.",
+       "usercssispublic": "Recuerda: Las subpáginas CSS no deberían contener datos confidenciales, pues otros usuarios los pueden ver."
 }
index ac4112f..cfc4e4d 100644 (file)
        "undo-success": "این ویرایش را می‌توان خنثی کرد.\nلطفاً تفاوت زیر را بررسی کنید تا تأیید کنید که این چیزی است که می‌خواهید انجام دهید، سپس تغییرات زیر را ذخیره کنید تا خنثی‌سازی ویرایش را به پایان ببرید.",
        "undo-failure": "به علت تعارض با ویرایش‌های میانی، این ویرایش را نمی‌توان خنثی کرد.",
        "undo-norev": "این ویرایش را نمی‌توان خنثی کرد چون وجود ندارد یا حذف شده‌است.",
-       "undo-nochange": "به نظر می‌رسد ویرایش از پیش واگردانی شده است.",
+       "undo-nochange": "به نظر می‌رسد ویرایش از پیش خنثی‌سازی شده است.",
        "undo-summary": "خنثی‌سازی ویرایش $1 توسط [[Special:Contributions/$2|$2]] ([[User talk:$2|بحث]])",
        "undo-summary-username-hidden": "خنثی‌سازی نسخهٔ $1 به دست یک کاربر پنهان‌شده",
        "cantcreateaccount-text": "امكان ساختن حساب کاربری از این این نشانی آی‌پی ('''$1''') توسط [[User:$3|$3]] سلب شده است.\n\nدلیل ارائه شده توسط $3 چنین است: $2",
index 55d067f..c851a85 100644 (file)
        "shortpages": "Pages courtes",
        "longpages": "Pages longues",
        "deadendpages": "Pages en impasse",
-       "deadendpagestext": "Les pages suivantes ne contiennent aucun lien vers d'autres pages du wiki.",
+       "deadendpagestext": "Les pages suivantes ne contiennent aucun lien vers d'autres pages dans le wiki {{SITENAME}}.",
        "protectedpages": "Pages protégées",
        "protectedpages-indef": "Uniquement les protections indéfinies",
        "protectedpages-summary": "Cette page liste les pages existantes actuellement protégées. Pour une liste des titres protégés contre la création, voir [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]].",
        "move": "Renommer",
        "movethispage": "Renommer cette page",
        "unusedimagestext": "Les fichiers suivants existent, mais ne sont inclus dans aucune page.\nVeuillez noter que d’autres sites peuvent accéder à ces fichiers à l’aide de liens directs (URLs), et donc qu’un fichier peut être listé ici alors qu’il est utilisé par ces sites.",
-       "unusedcategoriestext": "Les catégories suivantes existent mais aucune page ou catégorie ne les utilise.",
+       "unusedcategoriestext": "Les pages de catégories suivantes existent, mais aucune page ou catégorie ne les utilise.",
        "notargettitle": "Pas de cible",
        "notargettext": "Vous n'avez pas indiqué une page ou un utilisateur sur lequel vous souhaitez effectuer cette action.",
        "nopagetitle": "Page cible inexistante",
        "querypage-disabled": "Cette page spéciale est désactivée pour des raisons de performances.",
        "apihelp": "Aide de l’API",
        "apihelp-no-such-module": "Le module « $1 » est introuvable.",
-       "apisandbox": "Bac à sable API",
+       "apisandbox": "Bac à sable de l'API",
        "apisandbox-jsonly": "Le bac à sable de l'API nécessite JavaScript",
        "apisandbox-api-disabled": "L'API est désactivé sur ce site.",
        "apisandbox-intro": "Utilisez cette page pour expérimenter l’<strong>API webservice de MediaWiki</strong>.\nReportez-vous à [[mw:API:Main page|la documentation de l’API]] pour plus de détails sur l’utilisation de l’API. Exemple: [https://www.mediawiki.org/wiki/API#A_simple_example obtenir le contenu d'une page principale]. Choisissez une option pour voir d'autres exemples.",
        "emailccsubject": "Copie de votre message à $1 : $2",
        "emailsent": "Courriel envoyé",
        "emailsenttext": "Votre message a été envoyé par courriel.",
-       "emailuserfooter": "Ce courriel a été envoyé par « $1 » à « $2 » par la fonction « {{int:emailuser}} » de {{SITENAME}}.",
-       "usermessage-summary": "A laissé un message système.",
+       "emailuserfooter": "Ce courriel a été {{GENDER:$1|envoyé}} par « $1 » à « {{GENDER:$2|$2}} » par la fonction « {{int:emailuser}} » de {{SITENAME}}.",
+       "usermessage-summary": "Laisser un message système.",
        "usermessage-editor": "Messager du système",
        "watchlist": "Liste de suivi",
        "mywatchlist": "Liste de suivi",
        "unwatch": "Ne plus suivre",
        "unwatchthispage": "Ne plus suivre",
        "notanarticle": "Ce n'est pas une page de contenu",
-       "notvisiblerev": "La version a été supprimée",
+       "notvisiblerev": "La dernière version relue par un utilisateur différent, a été supprimée",
        "watchlist-details": "{{PLURAL:$1|$1 page|$1 pages}} dans votre liste de suivi, sans compter les pages de discussion.",
        "wlheader-enotif": "La notification par courriel est activée.",
-       "wlheader-showupdated": "Les pages qui ont été modifiées depuis votre dernière visite sont affichées en '''gras'''.",
+       "wlheader-showupdated": "Les pages qui ont été modifiées depuis votre dernière visite sont affichées en <strong>gras</strong>.",
        "wlnote": "Ci-dessous {{PLURAL:$1|figure la dernière modification effectuée|figurent les <strong>$1</strong> dernières modifications effectuées}} durant {{PLURAL:$2|la dernière heure|les <strong>$2</strong> dernières heures}}, jusqu'au $3, $4.",
        "wlshowlast": "Montrer les dernières $1 heures, les derniers $2 jours",
        "watchlist-hide": "Masquer",
        "linkaccounts-submit": "Lier les comptes",
        "unlinkaccounts": "Dissocier les comptes",
        "unlinkaccounts-success": "Le compte a été dissocié.",
-       "authenticationdatachange-ignored": "Les modifications de données d’authentification n’ont pas été gérées. Peut-être aucun fournisseur n’a-t-il été configuré ?"
+       "authenticationdatachange-ignored": "Les modifications de données d’authentification n’ont pas été gérées. Peut-être aucun fournisseur n’a-t-il été configuré ?",
+       "userjsispublic": "Veuillez noter: les sous-pages JavaScript ne doivent pas contenir de données confidentielles parce qu'elles sont visibles des autres utilisateurs.",
+       "usercssispublic": "Veuillez noter: les sous-pages CSS ne doivent pas contenir de données confidentielles parce qu'elles sont visibles des autres utilisateurs."
 }
index 28f11c0..f70f581 100644 (file)
        "listingcontinuesabbrev": "samb.",
        "index-category": "Kaca kaindhèksan",
        "noindex-category": "Kaca ora kaindhèksan",
-       "broken-file-category": "Kaca mawa pranala berkas rusak",
+       "broken-file-category": "Kaca mawa pranala barkas rusak",
        "about": "Bab",
        "article": "Kaca isi",
        "newwindow": "(buka mawa jendhéla anyar)",
        "no-null-revision": "Ora isa nggawe revisi 'null' anyar kanggo kaca \"$1\"",
        "badtitle": "Sesirah ala",
        "badtitletext": "Sesirahing kaca sing dikarepaké ora sah, suwung, utawa salah nggayut nyang sesirah antarabasa utawa antarawiki.\nIku mungkin ngandhut pralambang siji utawa luwih sing ora kena dianggo tumrap sesirah iki.",
-       "perfcached": "Data iki mung dijupuk saka papan singgahan lan mungkin ora kaanyaran. Maksimum {{PLURAL:$1|sak asil|$1 asil}} sumadhiya nèng papan singgahan.",
-       "perfcachedts": "Data iki mung dijupuk saka papan singgahan lan mungkin dianyari pungkasan $1. Maksimum {{PLURAL:$4|sak asil|$4 asil}} sumadhiya nèng papan singgahan.",
+       "perfcached": "Data ing ngisor iki kasimpen ing telih lan mungkin durung dianyari. Paling akèh ana {{PLURAL:$1|sakasil|$1 kasil}} sumadhiya ing telih iku.",
+       "perfcachedts": "Data ing ngisor iki kasimpen ing telih, lan pungkasan dianyari $1. Paling akèh ana {{PLURAL:$4|sakasil|$4 kasil}} sumadhiya ing telih iku.",
        "querypage-no-updates": "Update saka kaca iki lagi dipatèni. Data sing ana ing kéné saiki ora bisa bakal dibalèni unggah manèh.",
        "viewsource": "Deleng sumber",
        "viewsource-title": "Delok sumberé $1",
        "anoneditwarning": "<strong>Penget:</strong> Panjenengan boten mlebet log. Alamat IP Panjenengan badhe katingal dening publik manawi Panjenengan ngayahi ewah-ewahan. Manawi Panjenengan  <strong>[$1 mlebet log]</strong> utawai <strong>[$2 damel akun]</strong>, suntingan Panjenengan badhe kaatribusekaken dhumateng  nama pangangge Panjenengan, lan rupi-rupi  kauntungan sanesipun.",
        "anonpreviewwarning": "''Sampéyan durung mlebu log. Nyimpen bakal nyathet alamat IP Sampéyan nèng riwayat sunting kaca iki.''",
        "missingsummary": "'''Pènget:''' Panjenengan ora nglebokaké ringkesan panyuntingan. Menawa panjenengan mencèt tombol Simpen manèh, suntingan panjenengan bakal kasimpen tanpa ringkesan panyuntingan.",
+       "selfredirect": "<strong>Pélik:</strong> Sampéyan ngalih kaca iki iya nyang kaca iki dhéwé.\nSampéyan mungkin salah wènèh tujuan kanggo alihan utawa salah mbesut kaca.\nYèn sampéyan ngeklik \"{{int:savearticle}}\" manèh, kaca alihan bakal digawé.",
        "missingcommenttext": "Mangga isi tanggapan ing ngisor iki.",
        "missingcommentheader": "'''Pangéling:''' Sampéyan durung nyadhiyakaké judhul/jejer kanggo tanggepan iki.\nYèn Sampéyan klik \"{{int:savearticle}}\" manèh, suntingan Sampéyan bakal kasimpen tanpa kuwi.",
        "summary-preview": "Pratuduh tingkesan:",
        "searchrelated": "magepokan",
        "searchall": "kabèh",
        "showingresults": "Ing ngisor iki dituduhaké {{PLURAL:$1|'''1''' kasil|'''$1''' kasil}}, wiwitané saking #<strong>$2</strong>.",
+       "showingresultsinrange": "Nuduhaké nganti {{PLURAL:$1|<strong>1</strong> kasil|<strong>$1</strong> kasil}} sajeroning penthangan #<strong>$2</strong> tekan #<strong>$3</strong>.",
        "search-showingresults": "{{PLURAL:$4|Asil <strong>$1</strong> dari <strong>$3</strong>|Asil <strong>$1 - $2</strong> saking <strong>$3</strong>}}",
        "search-nonefound": "Ora ana kasil sing cocog karo pitakonan (''query'').",
        "powersearch-legend": "Panggolèkan sabanjuré (''advance search'')",
        "prefs-searchoptions": "Golèk",
        "prefs-namespaces": "Ruang jeneng / Bilik jeneng",
        "default": "baku",
-       "prefs-files": "Berkas",
+       "prefs-files": "Barkas",
        "prefs-custom-css": "CSS priangga",
        "prefs-custom-js": "JavaScript priangga",
        "prefs-common-css-js": "CSS/JS didumaké kanggo kabèh kulit:",
        "right-move-rootuserpages": "Ngalih kaca panganggo oyod",
        "right-movefile": "Mindhah berkas",
        "right-suppressredirect": "Aja nggawé pangalihan saka kaca sing lawas yèn mindhah sawijining kaca",
-       "right-upload": "Ngunggahaké berkas-berkas",
+       "right-upload": "Unggah barkas",
        "right-reupload": "Tindhihana sawijining berkas sing wis ana",
        "right-reupload-own": "Nimpa sawijining berkas sing wis ana lan diunggahaké déning panganggo sing padha",
        "right-reupload-shared": "Timpanana berkas-berkas ing khazanah binagi sacara lokal",
        "upload-prohibited": "Jenis berkas sing dilarang: $1.",
        "uploadlogpage": "Log pangunggahan",
        "uploadlogpagetext": "Ing ngisor iki kapacak log pangunggahan berkas sing anyar dhéwé.\nMangga mirsani [[Special:NewFiles|galeri berkas-berkas anyar]] kanggo pratélan visual.",
-       "filename": "Jeneng berkas",
+       "filename": "Jeneng barkas",
        "filedesc": "Tingkesan",
        "fileuploadsummary": "Ringkesan:",
        "filereuploadsummary": "Owah-owahan berkas:",
        "file-deleted-duplicate": "Sawijining berkas persis berkas iki ([[:$1]]) wis tau dibusak. Mangga panjenengan priksani sajarah pambusakan berkas kasebut sadurungé nerusaké ngunggahaké berkas kuwi manèh.",
        "uploadwarning": "Pèngetan pangunggahan berkas",
        "uploadwarning-text": "Mangga owah katrangan berkas nèng ngisor lan coba manèh.",
-       "savefile": "Simpen berkas",
+       "savefile": "Simpen barkas",
        "uploaddisabled": "Nuwun sèwu, fasilitas pangunggahan dipatèni.",
        "copyuploaddisabled": "Ngunggah mawa URL dipatèni.",
        "uploaddisabledtext": "Pangunggahan berkas ora diidinaké.",
        "uploadscripted": "Berkas iki ngandhut HTML utawa kode sing bisa diinterpretasi salah déning panjlajah wèb.",
        "uploadvirus": "Berkas iki ngamot virus! Détil: $1",
        "uploadjava": "Berkas kuwi berkas ZIP sing kaisi berkas .class Java.\nNgungga berkas Java ora dililakaké amarga bisa nyebabaké ngluwèhaké wates kamanan.",
-       "upload-source": "Berkas sumber",
+       "upload-source": "Barkas sumber",
        "sourcefilename": "Jeneng berkas sumber:",
        "sourceurl": "URL sumber:",
        "destfilename": "Jeneng berkas sing dituju",
        "brokenredirectstext": "Pengalihan ing ngisor iki tumuju menyang kaca sing ora ana:",
        "brokenredirects-edit": "besut",
        "brokenredirects-delete": "busak",
-       "withoutinterwiki": "Kaca tanpa pranala antarbasa",
-       "withoutinterwiki-summary": "Kaca-kaca iki ora nduwé pranala menyang vèrsi ing  basa liyané:",
+       "withoutinterwiki": "Kaca tanpa pranala basa",
+       "withoutinterwiki-summary": "Kaca-kaca ing ngisor iki ora nggayut nyang vèrsi basa liyané.",
        "withoutinterwiki-legend": "Préfiks",
        "withoutinterwiki-submit": "Tuduhna",
        "fewestrevisions": "Artikel mawa owah-owahan sithik dhéwé",
        "mostlinkedtemplates": "Kaca paling akèh transklusi",
        "mostcategories": "Kaca sing kategoriné akèh dhéwé",
        "mostimages": "Berkas sing kerep dhéwé dienggo",
-       "mostinterwikis": "Halaman dengan interwiki terbanyak",
+       "mostinterwikis": "Kaca mawa interwiki paling akèh",
        "mostrevisions": "Kaca mawa pangowahan sing akèh dhéwé",
        "prefixindex": "Kabèh kaca mawa ater-ater",
        "prefixindex-namespace": "Kabèh kaca mawa ater-ater (bilik jeneng $1)",
        "shortpages": "Kaca cendhak",
        "longpages": "Kaca dawa",
        "deadendpages": "Kaca-kaca buntu (tanpa pranala)",
-       "deadendpagestext": "kaca-kaca iki ora nduwé pranala tekan ngendi waé ing wiki iki..",
+       "deadendpagestext": "Kaca-kaca ing ngisor iki ora nggayut nyang kaca liya ing {{SITENAME}}.",
        "protectedpages": "Kaca sing direksa",
        "protectedpages-indef": "Namung pangreksan ora langgeng waé",
        "protectedpages-cascade": "Amung kaca rineksan kang runtut",
        "delete-legend": "Busak",
        "historywarning": "'''Pènget''': Kaca sing bakal panjenengan busak ana sajarahé kanthi $1 {{PLURAL:$1|révisi|révisi}}:",
        "confirmdeletetext": "Panjenengan bakal mbusak kaca utawa berkas iki minangka permanèn karo kabèh sajarahé saka basis data. Pastèkna dhisik menawa panjenengan pancèn nggayuh iki, ngerti kabèh akibat lan konsekwènsiné, lan apa sing bakal panjenengan tumindak iku cocog karo [[{{MediaWiki:Policy-url}}|kawicaksanan {{SITENAME}}]].",
-       "actioncomplete": "Proses tuntas",
+       "actioncomplete": "Kasil diayahi",
        "actionfailed": "Tindakan gagal",
-       "deletedtext": "\"$1\" sampun kabusak. Coba pirsani $2 kanggé log paling énggal kaca ingkang kabusak.",
+       "deletedtext": "\"$1\" wis dibusak. \nDelenga $2 minangka rekamaning busak-busakan pungkasan.",
        "dellogpage": "Log busak",
        "dellogpagetext": "Ing ngisor iki kapacak log pambusakan kaca sing anyar dhéwé.",
        "deletionlog": "Cathetan sing dibusak",
        "whatlinkshere": "Sing nggayut mréné",
        "whatlinkshere-title": "Kaca mawa pranala nggayut \"$1\"",
        "whatlinkshere-page": "Kaca:",
-       "linkshere": "Kaca-kaca iki nduwé pranala menyang '''[[:$1]]''':",
+       "linkshere": "Kaca-kaca ing ngisor iki nggayut nyang '''[[:$1]]''':",
        "nolinkshere": "Ora ana kaca sing nduwé pranala menyang '''[[:$1]]'''.",
        "nolinkshere-ns": " Ora ana kaca sing nduwé pranala menyang '''[[:$1]]''' ing bilik jeneng sing kapilih.",
        "isredirect": "kaca lih-lihan",
        "import-interwiki-history": "Tuladen kabèh vèrsi lawas saka kaca iki",
        "import-interwiki-templates": "Katutna kabèh cithakan",
        "import-interwiki-submit": "Impor",
-       "import-upload-filename": "Jeneng berkas:",
+       "import-upload-filename": "Jeneng barkas:",
        "import-comment": "Komentar:",
        "importtext": "Mangga èkspor berkas saka wiki sumber nganggo [[Special:Export|prangkat èkspor]].\nSimpen nèng komputer Sampéyan lan unggaha nèng kéné.",
        "importstart": "Ngimpor kaca...",
        "exif-subjectlocation": "Lokasi subjèk",
        "exif-exposureindex": "Indhèks pajanan",
        "exif-sensingmethod": "Métodhe pangindran",
-       "exif-filesource": "Sumber berkas",
+       "exif-filesource": "Sumber barkas",
        "exif-scenetype": "Tipe panyawangan",
        "exif-customrendered": "Prosès nggawé gambar",
        "exif-exposuremode": "Modhe pajanan",
        "redirect-user": "ID panganggo",
        "redirect-page": "ID kaca",
        "redirect-revision": "Revisi kaca",
-       "redirect-file": "Jeneng berkas",
+       "redirect-file": "Jeneng barkas",
        "redirect-not-exists": "Nilai ora ditemokaké",
        "fileduplicatesearch": "Golèk berkas duplikat",
        "fileduplicatesearch-summary": "Golèk duplikat berkas adhedhasar biji hash-é.",
index 6059e1a..282444d 100644 (file)
@@ -15,7 +15,8 @@
                        "តឹក ប៊ុនលី",
                        "វ័ណថារិទ្ធ",
                        "아라",
-                       "Macofe"
+                       "Macofe",
+                       "Dcljr"
                ]
        },
        "tog-underline": "គូសបន្ទាត់ក្រោម​តំណភ្ជាប់៖",
        "passwordreset-emailtext-user": "អ្នកប្រើប្រាស់ $1 នៅក្នុង {{SITENAME}} បានស្នើសុំស្ដារពាក្យសម្ងាត់របស់អ្នកនៅក្នុង {{SITENAME}} ($4)។\n {{PLURAL:$3|គណនី|គណនី}}អ្នកប្រើប្រាស់ដូចតទៅនេះមានជាប់ទាក់ទិននឹងអាសយដ្ឋានអ៊ីមែលនេះ៖\n\n$2\n\n{{PLURAL:$3|ពាក្យសម្ងាត់បណ្ដោះអាសន្ននេះ|ពាក្យសម្ងាត់បណ្ដោះអាសន្នទាំងនេះ}} និងហួសសុពលភាពក្នុងរយៈពេល {{PLURAL:$5|មួយថ្ងៃ|$5 ថ្ងៃ}}។\nយកល្អអ្នកគួរតែកត់ឈ្មោះចូលរួចជ្រើសរើសពាក្យសម្ងាត់ថ្មីមួយ។ ប្រសិនបើមាននរណាម្នាក់ផ្សេងធ្វើការស្នើសុំនេះ \nឬប្រសិនបើអ្នកនឹកឃើញពាក្យសម្ងាត់ដើមរបស់អ្នក ហើយអ្នកមិនប្រាថ្នាផ្លាស់ប្ដូរវាទៀតទេនោះ អ្នកគ្រាន់តែ\nបំភ្លេចអំពីសារមួយនេះ ហើយបន្តប្រើប្រាស់ពាក្យសម្ងាត់ចាស់របស់អ្នកទៅបានហើយ។",
        "passwordreset-emailelement": "អត្តនាម៖ \n$1\n\nពាក្យសម្ងាត់បណ្ដោះអាសន្ន៖ \n$2",
        "passwordreset-emailsentemail": "បើសិនជានេះអាសយដ្ឋានអ៊ីមែលដែលត្រូវបានចុះឈ្មោះសម្រាប់គណនីរបស់អ្នក នោះអ៊ីមែលសម្រាប់ស្ដារពាក្យសម្ងាត់មួយនឹងត្រូវបានផ្ញើទៅ។",
-       "passwordreset-emailsent-capture": "អ៊ីមែលស្ដារពាក្យសម្ងាត់មួយដូចបង្ហាញខាងក្រោមត្រូវបានផ្ញើទៅហើយ។",
-       "passwordreset-emailerror-capture": "អ៊ីមែលស្ដារពាក្យសម្ងាត់មួយដូចបង្ហាញខាងក្រោមត្រូវបានបង្កើតហើយ ប៉ុន្តែការផ្ញើទៅកាន់ {{GENDER:$2|អ្នកប្រើប្រាស់}}មិនបានសំរេចទេ៖ $1",
        "changeemail": "ផ្លាស់ប្ដូរឬលុបអាសយដ្ឋានអ៊ីមែល",
        "changeemail-header": "សូមបំពេញសំណុំបែបបទនេះដើម្បីផ្លាស់ប្ដូរអាសយដ្ឋានអ៊ីមែល។ បើសិនជាអ្នកចង់លុបការតភ្ជាប់អាសយដ្ឋានអ៊ីមែលពីគណនីរបស់អ្នក សូមដាក់ប្រឡោះអាសយដ្ឋានថ្មីអោយនៅទំនេរពេលសម្រេចដាក់សំណុំបែបបទ។",
        "changeemail-no-info": "អ្នក​ចាំបាច់​ត្រូវតែ​កត់ឈ្មោះចូល ដើម្បី​ចូលទៅកាន់​ទំព័រ​នេះ​ដោយផ្ទាល់​។",
        "undo-norev": "កំណែ​មិន​អាច​មិន​ធ្វើ​ឡើង​វិញ​បាន​ទេ​ ពីព្រោះ​វា​មិន​មាន​ឬ​ត្រូវ​បាន​លុប​បាត់​ទៅ​ហើយ​។",
        "undo-summary": "មិន​ធ្វើ​វិញ​នូវ​កំណែ​ប្រែ $1 ដោយ​ [[Special:Contributions/$2|$2]] ([[User talk:$2|ការពិភាក្សា​]])",
        "undo-summary-username-hidden": "មិន​ធ្វើ​វិញ​នូវ​កំណែ​ប្រែ $1 ដោយអ្នកប្រើប្រាស់លាក់ឈ្មោះ",
-       "cantcreateaccounttitle": "មិនអាចបង្កើតគណនីបានទេ",
        "cantcreateaccount-text": "ការបង្កើតគណនីពីអាសយដ្ឋាន IP ('''$1''') នេះ ត្រូវបានរារាំងដោយ [[User:$3|$3]]។\n\nហេតុផលដែលត្រូវលើកឡើងដោយ $3 គឺ ''$2''",
        "viewpagelogs": "មើលកំណត់ហេតុសម្រាប់ទំព័រនេះ",
        "nohistory": "មិនមានប្រវត្តិកំណែប្រែ​ចំពោះទំព័រនេះ។",
        "enotif_subject_moved": "ទំព័រ {{SITENAME}} មានចំណងជើងថា $1 ត្រូវបាន {{GENDER:$2|ប្ដូរទីតាំង}} ដោយ $2",
        "enotif_subject_restored": "ទំព័រ {{SITENAME}} មានចំណងជើងថា $1 ត្រូវបាន {{GENDER:$2|ស្ដារឡើងវិញ}} ដោយ $2",
        "enotif_subject_changed": "ទំព័រ {{SITENAME}} មានចំណងជើងថា $1 ត្រូវបាន {{GENDER:$2|ផ្លាស់ប្ដូរ}} ដោយ $2",
-       "enotif_body_intro_deleted": "ទំព័រ {{SITENAME}} មានចំណងជើងថា $1 ត្រូវបាន {{GENDER:$2|លុបចោល}} នៅ $PAGEEDITDATE ដោយ $2។ សូមអាន $3។",
+       "enotif_body_intro_deleted": "ទំព័រ {{SITENAME}} មានចំណងជើងថា $1 ត្រូវបាន {{GENDER:$2|លុបចោល}} នៅ $PAGEEDITDATE ដោយ $2 ។ សូមអាន $3 ។",
        "enotif_body_intro_created": "ទំព័រ {{SITENAME}} មានចំណងជើងថា $1 ត្រូវបាន {{GENDER:$2|បង្កើត}} នៅ $PAGEEDITDATE ដោយ $2។ សូមអាន $3 សម្រាប់កំណែបច្ចុប្បន្ន។",
        "enotif_body_intro_moved": "ទំព័រ {{SITENAME}} មានចំណងជើងថា $1 ត្រូវបាន {{GENDER:$2|ប្ដូរទីតាំង}} នៅ $PAGEEDITDATE ដោយ $2។ សូមអាន $3 សម្រាប់កំណែបច្ចុប្បន្ន។",
        "enotif_body_intro_restored": "ទំព័រ {{SITENAME}} មានចំណងជើងថា $1 ត្រូវបាន {{GENDER:$2|ស្ដារឡើងវិញ}} នៅ $PAGEEDITDATE ដោយ $2។ សូមអាន $3 សម្រាប់កំណែបច្ចុប្បន្ន។",
        "special-characters-title-minus": "សញ្ញាដក",
        "mw-widgets-dateinput-no-date": "គ្មានកាលបរិច្ឆេទត្រូវបានជ្រើសរើស",
        "mw-widgets-titleinput-description-new-page": "ទំព័រមិនទាន់មាននៅឡើយទេ",
-       "mw-widgets-titleinput-description-redirect": "បញ្ជូនបន្តទៅ $1",
-       "api-error-blacklisted": "សូមជ្រើសរើសឈ្មោះផ្សេងដែលក្បោះក្បាយជាង។"
+       "mw-widgets-titleinput-description-redirect": "បញ្ជូនបន្តទៅ $1"
 }
index fd27331..688ee15 100644 (file)
        "linkaccounts-submit": "계정 연결",
        "unlinkaccounts": "계정 연결 해제",
        "unlinkaccounts-success": "계정의 연결이 해제되었습니다.",
-       "authenticationdatachange-ignored": "인증 데이터 변경을 처리하지 못했습니다. 제공자를 설정하지 않으셨습니까?"
+       "authenticationdatachange-ignored": "인증 데이터 변경을 처리하지 못했습니다. 제공자를 설정하지 않으셨습니까?",
+       "userjsispublic": "주목해 주십시오: 자바스크립트의 하위 문서들은 다른 사용자들이 볼 수 있기 때문에 기밀 데이터를 포함해서는 안 됩니다.",
+       "usercssispublic": "주목해 주십시오: CSS의 하위 문서들은 다른 사용자들이 볼 수 있기 때문에 기밀 데이터를 포함해서는 안 됩니다."
 }
index f56536b..f9bb80c 100644 (file)
        "recentchanges-feed-description": "Verfollegt mat dësem Feed déi rezent Ännerungen op {{SITENAME}}.",
        "recentchanges-label-newpage": "Mat dëser Ännerung gouf eng nei Säit ugeluecht",
        "recentchanges-label-minor": "Dëst ass eng kleng Ännerung",
-       "recentchanges-label-bot": "Dës Ännerung gouf vun engem Bot gemaacht",
+       "recentchanges-label-bot": "Dës Ännerung gouf vun engem Bot gemaach",
        "recentchanges-label-unpatrolled": "Dës Ännerung gouf nach net nogekuckt",
        "recentchanges-label-plusminus": "D'Gréisst vun der Säit huet sech ëm déi Zuel vu Bytes geännert",
        "recentchanges-legend-heading": "<strong>Legend:</strong>",
index 1b78704..86a2ba4 100644 (file)
        "show": "Rodyti",
        "minoreditletter": "S",
        "newpageletter": "N",
-       "boteditletter": "R",
+       "boteditletter": "r",
        "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|stebintis naudotojas|stebintys naudotojai|stebinčių naudotojų}}]",
        "rc_categories": "Riboti kategorijoms (atskirkite su „|“)",
        "rc_categories_any": "Bet kuris iš pasirinktųjų",
        "log-action-filter-rights-autopromote": "Automatinis keitimas",
        "log-action-filter-upload-upload": "Naujas įkėlimas",
        "log-action-filter-upload-overwrite": "Kelti iš naujo",
+       "authmanager-create-disabled": "Paskyros kūrimas yra išjungtas.",
+       "authmanager-create-from-login": "Norėdami sukurti paskyrą užpildykite laukelius žemiau.",
        "authmanager-authplugin-setpass-failed-title": "Slaptažodžio keitimas nepavyko",
        "authmanager-authplugin-setpass-bad-domain": "Negalimas domenas.",
        "authmanager-autocreate-noperm": "Automatinis paskyros kūrimas neleidžiamas.",
index ecd1cf0..89742eb 100644 (file)
        "botpasswords-label-resetpassword": "Atiestatīt paroli",
        "botpasswords-label-restrictions": "Lietošanas ierobežojumi:",
        "botpasswords-label-grants-column": "Piešķirts",
+       "botpasswords-created-title": "Bota parole izveidota",
+       "botpasswords-updated-title": "Bota parole atjaunināta",
        "botpasswords-deleted-title": "Bota parole dzēsta",
        "resetpass_forbidden": "Paroles nav iespējams nomainīt",
        "resetpass-no-info": "Jums ir nepieciešams ieiet, lai tūlīt piekļūtu šai lapai.",
        "passwordreset-emailsentemail": "Paroles atiestatīšanas e-pasts ir nosūtīts.",
        "passwordreset-nosuchcaller": "Izsaucējs nepastāv: $1",
        "passwordreset-invalideamil": "Nederīga e-pasta adrese",
-       "changeemail": "Mainīt e-pasta adresi",
+       "changeemail": "Mainīt vai noņemt e-pasta adresi",
        "changeemail-header": "Mainīt konta e-pasta adresi",
        "changeemail-oldemail": "Pašreizējā e-pasta adrese:",
        "changeemail-newemail": "Jaunā e-pasta adrese:",
        "mergehistory-submit": "Apvienot versijas",
        "mergehistory-empty": "Neviena versija nevar tikt apvienota",
        "mergehistory-fail": "Nav iespējams apvienot hronoloģiju, lūdzu, pārbaudiet vēlreiz lapu un laika parametrus.",
+       "mergehistory-fail-bad-timestamp": "Laika zīmogs ir nederīgs.",
+       "mergehistory-fail-invalid-source": "Avota lapa ir nederīga.",
+       "mergehistory-fail-invalid-dest": "Mērķa lapa ir nederīga.",
        "mergehistory-no-source": "Avota lapa $1 nepastāv.",
        "mergehistory-no-destination": "Mērķa lapa $1 nepastāv.",
        "mergehistory-invalid-source": "Avota lapas nosaukumam jābūt derīgam.",
        "sp-contributions-newbies": "Rādīt jauno lietotāju devumu",
        "sp-contributions-newbies-sub": "Jaunie lietotāji",
        "sp-contributions-blocklog": "Bloķēšanas reģistrs",
-       "sp-contributions-deleted": "dzēstais dalībnieka devums",
+       "sp-contributions-deleted": "dzēstais {{GENDER:$1|dalībnieka|dalībnieces}} devums",
        "sp-contributions-uploads": "augšupielādes",
        "sp-contributions-logs": "reģistri",
        "sp-contributions-talk": "diskusija",
index 459c47b..33ea41a 100644 (file)
@@ -18,7 +18,8 @@
                        "Milicevic01",
                        "Macofe",
                        "Nemo bis",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Kaldari"
                ]
        },
        "tog-underline": "Потцртување на врски:",
        "hidden-category-category": "Скриени категории",
        "category-subcat-count": "{{PLURAL:$2|Оваа категорија ја содржи само следнава поткатегорија.|Оваа категорија {{PLURAL:$1|ја содржи следнава поткатегорија|ги содржи следниве $1 поткатегории}} од вкупно $2.}}",
        "category-subcat-count-limited": "Оваа категорија {{PLURAL:$1|ја содржи следнава поткатегорија|ги содржи следниве $1 поткатегории}}.",
-       "category-article-count": "{{#ifeq:$2|Оваа категорија содржи само една страница.|{{PLURAL:$1|Прикажана е една|Прикажани се $1}} од вкупно $2 страници во категоријата.}}",
+       "category-article-count": "{{PLURAL:$2|Оваа категорија содржи само една страница.|{{PLURAL:$1|Прикажана е една|Прикажани се $1}} од вкупно $2 страници во категоријата.}}",
        "category-article-count-limited": "{{PLURAL:$1|Следната страница е|Следните $1 страници се}} во оваа категорија.",
-       "category-file-count": "{{#ifeq:$2|Оваа категорија содржи само една податотека.|{{PLURAL:$1|Прикажана е една|Прикажани се $1}} од вкупно $2 податотеки во категоријата.}}",
+       "category-file-count": "{{PLURAL:$2|Оваа категорија содржи само една податотека.|{{PLURAL:$1|Прикажана е една|Прикажани се $1}} од вкупно $2 податотеки во категоријата.}}",
        "category-file-count-limited": "{{PLURAL:$1|Следнава податотека е|Следниве $1 податотеки се}} во оваа категорија.",
        "listingcontinuesabbrev": "продолжува",
        "index-category": "Индексирани страници",
        "linkaccounts-submit": "Поврзи сметки",
        "unlinkaccounts": "Одврзи сметки",
        "unlinkaccounts-success": "Сметката е одврзана.",
-       "authenticationdatachange-ignored": "Промената на податоците во заверката не е обработена. Можеби не е поставен услужник?"
+       "authenticationdatachange-ignored": "Промената на податоците во заверката не е обработена. Можеби не е поставен услужник?",
+       "userjsispublic": "Напомена: потстраниците со JavaScript не треба да содржат дсоверливи податоци бидејќи истите се видливи и за други корисници.",
+       "usercssispublic": "Напомена: потстраниците со CSS не треба да содржат дсоверливи податоци бидејќи истите се видливи и за други корисници."
 }
index 21bf1d8..482171a 100644 (file)
        "shown-title": "စာမျက်နှာတစ်ခုလျှင် ရလဒ် $1 {{PLURAL:$1|ခု|ခု}} ပြရန်",
        "viewprevnext": "($1 {{int:မှ}} $2) အထိကြား ရလဒ် ($3) ခုကို ကြည့်ရန်",
        "searchmenu-exists": "'''ဤဝီကီတွင် \"[[:$1]]\" အမည်နှင့် စာမျက်နှာတစ်ခုရှိသည်။'''",
-       "searchmenu-new": "<strong>á\80¤á\80\9dá\80®á\80\80á\80®á\80\90á\80½á\80\84á\80º \"[[:$1]]\" á\80\85á\80¬á\80\99á\80»á\80\80á\80ºá\80\94á\80¾á\80¬á\80\80á\80­á\80¯ á\80\96á\80\94á\80ºá\80\90á\80®á\80¸á\80\95á\80«!</strong> {{PLURAL:$2|0=|á\80\9eá\80\84á\80·á\80ºá\80\9bá\80¾á\80¬á\80\96á\80½á\80±á\80\99á\80¾á\80¯á\80\94á\80¾á\80\84á\80·á\80º á\80\85á\80¬á\80\99á\80»á\80\80á\80ºá\80\94á\80¾á\80¬á\80\80á\80­á\80¯á\80\9cá\80\8aá\80ºá\80¸ á\80\80á\80¼á\80\8aá\80·á\80ºá\80\95á\80«á\81\8b\80\9bá\80¾á\80¬á\80\96á\80½á\80±á\80\99á\80¾á\80¯ á\80\9bá\80\9cá\80\92á\80ºá\80\99á\80»á\80¬á\80¸á\80\80á\80­á\80¯á\80\9cá\80\8aá\80ºá\80¸ á\80\80á\80¼á\80\8aá\80ºá\80«ပါ။}}",
+       "searchmenu-new": "<strong>á\80¤á\80\9dá\80®á\80\80á\80®á\80\90á\80½á\80\84á\80º \"[[:$1]]\" á\80\85á\80¬á\80\99á\80»á\80\80á\80ºá\80\94á\80¾á\80¬á\80\80á\80­á\80¯ á\80\96á\80\94á\80ºá\80\90á\80®á\80¸á\80\95á\80«!</strong> {{PLURAL:$2|0=|á\80\9eá\80\84á\80·á\80ºá\80\9bá\80¾á\80¬á\80\96á\80½á\80±á\80\99á\80¾á\80¯á\80\94á\80¾á\80\84á\80·á\80º á\80\85á\80¬á\80\99á\80»á\80\80á\80ºá\80\94á\80¾á\80¬á\80\80á\80­á\80¯á\80\9cá\80\8aá\80ºá\80¸ á\80\80á\80¼á\80\8aá\80·á\80ºá\80\95á\80«á\81\8b\80\9bá\80¾á\80¬á\80\96á\80½á\80±á\80\99á\80¾á\80¯ á\80\9bá\80\9cá\80\92á\80ºá\80\99á\80»á\80¬á\80¸á\80\80á\80­á\80¯á\80\9cá\80\8aá\80ºá\80¸ á\80\80á\80¼á\80\8aá\80·á\80ºပါ။}}",
        "searchprofile-articles": "မာတိကာစာမျက်နှာများ",
        "searchprofile-images": "မာလတီမီဒီယာ",
        "searchprofile-everything": "အားလုံး",
index 6cd436a..3fc66f5 100644 (file)
        "expand_templates_remove_comments": "Kommentaren rutnehmen",
        "expand_templates_generate_xml": "XML-Parser-Boom wiesen",
        "expand_templates_preview": "Vörschau",
-       "pagelang-language": "Spraak"
+       "pagelang-language": "Spraak",
+       "special-characters-group-latin": "Latiensch",
+       "special-characters-group-latinextended": "Latiensch verwiedert",
+       "special-characters-group-ipa": "Internatschonal Phoneetsch Alphabet",
+       "special-characters-group-symbols": "Symbolen",
+       "special-characters-group-greek": "Greeksch",
+       "special-characters-group-greekextended": "Greeksch verwiedert",
+       "special-characters-group-cyrillic": "Kyrillisch",
+       "special-characters-group-arabic": "Araabsch",
+       "special-characters-group-arabicextended": "Araabsch verwiedert",
+       "special-characters-group-persian": "Persisch",
+       "special-characters-group-hebrew": "Hebrääsch",
+       "special-characters-group-bangla": "Bengaalsch",
+       "special-characters-group-tamil": "Tamilsch",
+       "special-characters-group-telugu": "Telugu",
+       "special-characters-group-sinhala": "Singaleesch",
+       "special-characters-group-gujarati": "Gujarati",
+       "special-characters-group-devanagari": "Devanagari",
+       "special-characters-group-thai": "Thailändsch",
+       "special-characters-group-lao": "Laotisch",
+       "special-characters-group-khmer": "Khmer"
 }
index 2a1628f..10d005d 100644 (file)
        "recreate": "Attopprett",
        "confirm_purge_button": "OK",
        "confirm-purge-top": "Vil du slette tenarane sin mellomlagra versjon av denne sida?",
-       "confirm-purge-bottom": "Reinsing av ei side slettar mellomlageret og tvinger fram den nyaste versjonen.",
+       "confirm-purge-bottom": "Reinsing av ei side slettar mellomlageret og tvingar fram den nyaste versjonen.",
        "confirm-watch-button": "OK",
        "confirm-watch-top": "Legg denne sida til i overvakingslista di?",
        "confirm-unwatch-button": "OK",
index 0a13f29..e329be0 100644 (file)
        "passwordreset-emailtext-user": "L'utilizaire $1 sus {{SITENAME}} a demandat una reïnicializacion de vòstre senhal per {{SITENAME}} ($4). {{PLURAL:$3|Lo compte d'utilizaire seguent es associat|Los comptes d'utilizaires seguents son associats}} a aquesta adreça de corrièr electronic :\n\n$2\n\n{{PLURAL:$3|Aqueste senhal temporari expirarà|Aquestes senhals temporaris expiraràn}} dins {{PLURAL:$5|un jorn|$5 jorns}}. Ara, vos cal vos connectar e causir un senhal novèl. Se aquesta demanda proven pas de vos, o que vos sètz remembrat de vòstre senhal inicial, e que lo volètz pas mai modificar, podètz ignorar aqueste messatge e contunhar d'utilizar vòstre ancian senhal.",
        "passwordreset-emailelement": "Utilizaire: \n$1\n\nSenhal temporari: \n$2",
        "passwordreset-emailsentemail": "Un corrièr electronic de reïnicializacion de senhal es estat mandat.",
-       "passwordreset-emailsent-capture": "Un corrièr electronic de reïnicializacion senhal es estat mandat, qu'es afichat çaijós.",
-       "passwordreset-emailerror-capture": "Un corrièr electronic de reïnicializacion de senhal es estat generat, qu'es afichat çaijós, mas lo mandadís a l'{{GENDER:$2|utilizaire}} a fracassat : $1",
        "changeemail": "Cambiar o suprimir l'adreça electronica",
        "changeemail-header": "Cambiar l'adreça electronica del compte",
        "changeemail-no-info": "Vos cal èsser connectat per aver accès a aquesta pagina.",
        "minoredit": "Aquò es un cambiament menor",
        "watchthis": "Seguir aquesta pagina",
        "savearticle": "Salvar",
+       "publishpage": "Publicar la pagina",
+       "publishchanges": "Publicar las modificacions",
        "preview": "Previsualizar",
-       "showpreview": "Previsualizacion",
+       "showpreview": "Previsualizar",
        "showdiff": "Veire los cambiaments",
        "blankarticle": "<strong>Atencion :</strong> La pagina que creatz es voida.\nSe clicatz tornarmai sus « {{int:savearticle}} », la pagina serà creada sens cap de contengut.",
        "anoneditwarning": "<strong>Atencion :<strong> sètz pas connectat.\nVòstra adreça IP serà visibla per tot lo monde se fasètz de modificacions. Se <strong>[$1 vos connectatz]</strong> o <strong>[$2 creatz un compte]</strong>, vòstras modificacions seràn atribuidas a vòstre nom d’utilizaire, entre autres avantatges.",
        "undo-nochange": "Sembla que la modificacion es ja estada anullada.",
        "undo-summary": "Anullacion de las modificacions $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|discutir]] | [[Special:Contributions/$2|{{MediaWiki:Contribslink}}]])",
        "undo-summary-username-hidden": "Anullar la revision $1 per un utilizaire amagat",
-       "cantcreateaccounttitle": "Podètz pas crear de compte.",
        "cantcreateaccount-text": "La creacion de compte dempuèi aquesta adreça IP ('''$1''') es estada blocada per [[User:$3|$3]].\n\nLa rason balhada per $3 èra ''$2''.",
        "cantcreateaccount-range-text": "La creacion de compte dempuèi las adreças IP dins la plaja <strong>$1</strong>, que compren vòstra agreça IP (<strong>$4</strong>) son estadas blocadas per [[User:$3|$3]].\n\nLo motiu provesit per $3 es <em>$2</em>",
        "viewpagelogs": "Vejatz las operacions per aquesta pagina",
        "tooltip-ca-nstab-category": "Vejatz la pagina de la categoria",
        "tooltip-minoredit": "Marcar mas modificacions coma un cambiament menor",
        "tooltip-save": "Salvar vòstras modificacions",
+       "tooltip-publish": "Publicar vòstras modificacions",
        "tooltip-preview": "Mercé de previsualizar vòstras modificacions abans de salvar!",
        "tooltip-diff": "Aficha los cambiaments qu'avètz aportats al tèxte",
        "tooltip-compareselectedversions": "Afichar las diferéncias entre doas versions d'aquesta pagina",
index 8108c7a..2989d3b 100644 (file)
        "botpasswords-insert-failed": "Falhou ao adicionar o nome do robô \"$1\". Já foi adicionado?",
        "botpasswords-update-failed": "Falha ao atualizar o nome do robô \"$1\". Será que foi eliminado?",
        "botpasswords-created-title": "Criada palavra-passe para o robô",
-       "botpasswords-created-body": "O robô palavra-passe para o nome do robô \"$1\" do utilizador \"$2\" foi criado.",
+       "botpasswords-created-body": "A palavra-passe de robô para o robô \"$1\" do utilizador \"$2\" foi criada.",
        "botpasswords-updated-title": "A palavra-passe de robô foi actualizada.",
        "botpasswords-updated-body": "O robô palavra-passe para o nome do robô \"$1\" do utilizador \"$2\" foi atualizado.",
        "botpasswords-deleted-title": "Palavra-passe de robô eliminada",
index 6a3d604..2c5041c 100644 (file)
        "linkaccounts-submit": "Text of the main submit button on [[Special:LinkAccounts]] (when there is one)",
        "unlinkaccounts": "Title of the special page [[Special:UnlinkAccounts]] which allows the user to remove linked remote accounts.",
        "unlinkaccounts-success": "Account unlinking form success message",
-       "authenticationdatachange-ignored": "Shown when authentication data change was unsuccessful due to configuration problems.\n\nCf. e.g. {{msg-mw|Passwordreset-ignored}}."
+       "authenticationdatachange-ignored": "Shown when authentication data change was unsuccessful due to configuration problems.\n\nCf. e.g. {{msg-mw|Passwordreset-ignored}}.",
+       "userjsispublic": "A reminder to users that Javascript subpages are not preferences but normal pages, and thus can be viewed by other users and the general public. This message is shown to a user whenever they are editing a subpage in their own user-space that ends in .js. See also {{msg-mw|usercssispublic}}.",
+       "usercssispublic": "A reminder to users that CSS subpages are not preferences but normal pages, and thus can be viewed by other users and the general public. This message is shown to a user whenever they are editing a subpage in their own user-space that ends in .css. See also {{msg-mw|userjsispublic}}"
 }
index 7ef457b..f1fad3c 100644 (file)
        "linkaccounts-submit": "Poveži račune",
        "unlinkaccounts": "Razveži račune",
        "unlinkaccounts-success": "Račun smo razvezali.",
-       "authenticationdatachange-ignored": "Sprememba overitvenih podatkov ni bila obdelana. Morda ni bil konfiguriran noben ponudnik?"
+       "authenticationdatachange-ignored": "Sprememba overitvenih podatkov ni bila obdelana. Morda ni bil konfiguriran noben ponudnik?",
+       "userjsispublic": "Pomnite: Podstrani JavaScript naj ne vsebujejo zaupnih podatkov, saj so vidne tudi drugim uporabnikom.",
+       "usercssispublic": "Pomnite: Podstrani CSS naj ne vsebujejo zaupnih podatkov, saj so vidne tudi drugim uporabnikom."
 }
index 3cea9f2..33c3522 100644 (file)
        "linkaccounts-submit": "Länka konton",
        "unlinkaccounts": "Avlänka konton",
        "unlinkaccounts-success": "Kontot avlänkades.",
-       "authenticationdatachange-ignored": "Ändringen av autentiseringsdata hanterades inte. Kanske ingen tillhandahållare har konfigurerats?"
+       "authenticationdatachange-ignored": "Ändringen av autentiseringsdata hanterades inte. Kanske ingen tillhandahållare har konfigurerats?",
+       "userjsispublic": "Observera: JavaScript-undersidor bör inte innehålla konfidentiella uppgifter eftersom de kan ses av andra användare.",
+       "usercssispublic": "Observera: CSS-undersidor bör inte innehålla konfidentiella uppgifter eftersom de kan ses av andra användare."
 }
index 4f78206..d9a5592 100644 (file)
        "filesource": "ಮೂಲ",
        "savefile": "ಕಡತನ್ ಒರಿಪಾಲೆ",
        "upload-source": "ಮೂಲ ಕಡತ",
+       "upload-options": "ಅಪ್ಲೋಡ್ ಆಯ್ಕೆಲು",
+       "watchthisupload": "ಈ ಪುಟೊನು ತೂಲೆ",
        "upload-file-error": "ಆ೦ತರಿಕ ದೋಷ",
+       "upload-dialog-title": "ಫೈಲ್ ಅಪ್ಲೋಡ್",
        "upload-dialog-button-cancel": "ವಜಾ ಮಲ್ಪುಲೆ",
        "upload-dialog-button-done": "ಆಂಡ್",
        "upload-dialog-button-save": "ಒರಿಪಾಲೆ",
        "listfiles_size": "ಗಾತ್ರೊ",
        "listfiles_description": "ವಿವರಣೆ",
        "listfiles_count": "ಆವೃತ್ತಿಲು",
+       "listfiles-latestversion": "ಪ್ರಸಕ್ತ ಆವೃತ್ತಿ",
        "listfiles-latestversion-yes": "ಅಂದ್",
        "listfiles-latestversion-no": "ಅತ್ತ್",
        "file-anchor-link": "ಫೈಲ್",
        "filehist-datetime": "ದಿನೊ/ಪೊರ್ತು",
        "filehist-thumb": "ಎಲ್ಯಚಿತ್ರೊ",
        "filehist-thumbtext": "$1ತ ಆವೃತ್ತಿದ ಎಲ್ಯಚಿತ್ರೊ",
+       "filehist-nothumb": "ಎಲ್ಯಚಿತ್ರೊ ಇಜ್ಜಿ",
        "filehist-user": "ಬಳಕೆದಾರೆರ್",
        "filehist-dimensions": "ಆಯಾಮೊಲು",
        "filehist-filesize": "ಫೈಲ್’ದ ಗಾತ್ರ",
        "upload-disallowed-here": "ಈರ್ ಈ ಫೈಲ್‍ನ್ ಕುಡೊರೊ ಬರೆವರೆ ಸಾದ್ಯೊ ಇದ್ದಿ.",
        "filerevert-comment": "ಕಾರಣ:",
        "filerevert-submit": "ದುಂಬುದ ಲೆಕ ಮಲ್ಪುಲೆ",
+       "filedelete-legend": "ಕಡತನ್ ಮಾಜಾಲೆ",
        "filedelete-comment": "ಕಾರಣ",
        "filedelete-submit": "ಮಾಜಾಲೆ",
        "filedelete-reason-otherlist": "ಬೇತೆ ಕಾರಣ",
        "download": "ಡೌನ್‍ಲೋಡ್",
        "randompage": "ಯಾದೃಚ್ಛಿಕ ಪುಟೊ",
+       "randomincategory-category": "ವರ್ಗೊ:",
        "randomincategory-submit": "ಪೋಲೆ",
        "statistics": "ಅಂಕಿ ಅಂಶೊಲು",
        "statistics-header-pages": "ಪುಟೊತ ಅಂಕಿ ಅಂಶಲು",
        "statistics-pages": "ಪುಟಕುಲು",
+       "statistics-users-active": "ಸಕ್ರಿಯ ಬಳಕೆದಾರೆರ್",
        "pageswithprop-submit": "ಪೋಲೆ",
        "brokenredirects-edit": "ಸಂಪೊಲಿಪುಲೆ",
        "brokenredirects-delete": "ಮಾಜಾಲೆ",
        "wantedfiles": "ಬೋಡಾಯಿನ ಕಡತೊಲು",
        "prefixindex": "ಪೂರ್ವನಾಮೊಲ್ದ ಸೂಚಿಕೆ",
        "prefixindex-submit": "ತೋಜಾಲೆ",
+       "shortpages": "ಎಲ್ಯ ಪುಟೊಕುಲು",
+       "longpages": "ಉದ್ದ ಪುಟೊಕುಲು",
+       "protectedpages": "ಸಂರಕ್ಷಿತ ಪುಟೊ",
        "protectedpages-page": "ಪುಟೊ",
        "protectedpages-reason": "ಕಾರಣೊ",
        "protectedpages-unknown-timestamp": "ಗೊತ್ತಿಜ್ಜಾಂದಿನ",
+       "protectedpages-unknown-performer": "ಅಜ್ಞಾತ ಬಳಕೆದಾರೆ",
+       "protectedtitles": "ಸಂರಕ್ಷಿತ ಶೀರ್ಷಿಕೆಲು",
        "listusers": "ಬಳಕೆದಾರರೆನ ತಖ್ತೆ",
        "newpages": "ಪೊಸ ಪುಟೊಲು",
        "newpages-submit": "ತೋಜಾಲೆ",
        "emailsend": "ಕಡಪುಡುಲೆ",
        "watchlist": "ವೀಕ್ಷಣಾ ಪಟ್ಟಿ",
        "mywatchlist": "ಎನ್ನ ವೀಕ್ಷಣಾಪಟ್ಟಿ",
+       "watchnologin": "ಲಾಗಿನ್ ಆತ್‍ಜರ್",
        "watch": "ತೂಲೆ",
        "watchthispage": "ಈ ಪುಟೊನು ತೂಲೆ",
        "unwatch": "ವೀಕ್ಷಣಾಪಟ್ಟಿರ್ದ್ ದೆಪ್ಪು",
        "watchlist-hide": "ಅಡೆಂಗಾವು",
        "watchlist-submit": "ತೋಜಾವು",
        "wlshowhideminor": "ಎಲ್ಯೆಲ್ಯ ಬದಲಾವಣೆಲು",
+       "wlshowhideliu": "ನೋಂದವಣೆ ಆತಿನಂಚಿನ ಸದಸ್ಯೆರ್",
+       "wlshowhideanons": "ಪುದರ್ ಇದ್ಯಾಂದಿನ ಸದಸ್ಯೆರ್",
        "watchlist-options": "ವೀಕ್ಷಣಾಪಟ್ಟಿ ಆಯ್ಕೆಲು",
        "watching": "ವೀಕ್ಷಣಾಪಟ್ಟಿಗ್ ಸೇರ್ಪಾವೊಂದುಂಡು...",
        "unwatching": "ವೀಕ್ಷಣಾಪಟ್ಟಿರ್ದ್ ದೆತ್ತೊಂದುಂಡು...",
+       "deletepage": "ಪುಟೊಕುಲೆನ್ ಮಾಜಾಲೆ",
        "confirm": "ಗಟ್ಟಿಮಲ್ಪುಲೆ",
        "delete-legend": "ಮಾಜಾಲೆ",
        "historyaction-submit": "ತೋಜಾಲೆ",
        "actioncomplete": "ಕಾರ್ಯ ಸಂಪೂರ್ಣ",
        "dellogpage": "ಡಿಲೀಟ್ ಮಲ್ತಿನ ಫೈಲ್‍ದ ದಾಕಲೆ",
+       "deletionlog": "ಡಿಲೀಟ್ ಮಲ್ತಿನ ಫೈಲ್‍ದ ದಾಕಲೆ",
        "deletecomment": "ಕಾರಣ:",
        "deletereasonotherlist": "ಬೇತೆ ಕಾರಣ",
+       "delete-edit-reasonlist": "ಮಾಜಾಯಿನ ಕಾರಣೊಲೆನ್ ಸಂಪಾದನೆ ಮಲ್ಪುಲೆ",
        "rollbacklink": "ಪುಡತ್ತ್ ಪಾಡ್",
        "rollbacklinkcount": "ಪಿರ ದೆತೊನ್ಲೆ $1 {{PLURAL:$1|edit|ಸಂಪದನೆಲು}}",
+       "changecontentmodel-title-label": "ಪುಟೊದ ಪುದರ್",
        "changecontentmodel-reason-label": "ಕಾರಣ:",
        "changecontentmodel-submit": "ಬದಲಾವಣೆ",
        "logentry-contentmodel-change-revertlink": "ದುಂಬುದ ಲೆಕ ಮಲ್ಪುಲೆ",
        "ipbreason": "ಕಾರಣೊ:",
        "ipboptions": "2 ಗಂಟೆಲು:2 hours,1 ದಿನ:1 day,3 ದಿನೊಲು:3 days,1 ವಾರ:1 week,2 ವಾರೊಲು:2 weeks,1 ತಿಂಗೊಲು:1 month,3 ತಿಂಗೊಲು:3 months,6 ತಿಂಗೊಲು:6 months,1 ವರ್ಷ:1 year,ಅನಿರ್ಧಿಷ್ಟ:infinite",
        "ipblocklist": "ತಡೆಪತ್ತ್’ದಿನ ಐ.ಪಿ ವಿಳಾಸೊಲು ಅಂಚೆನೆ ಬಳಕೆದ ಪುದರ್’ಲು",
+       "blocklist-target": "ಗುರಿ",
+       "blocklist-reason": "ಕಾರಣೊ",
+       "ipblocklist-submit": "ನಾಡ್‍ಲೆ",
        "blocklink": "ಅಡ್ಡ ಪತ್ತ್‌ಲೆ",
        "unblocklink": "ಅಡ್ಡನ್ ದೆಪ್ಪುಲೆ",
        "change-blocklink": "ಬ್ಲಾಕ್’ನ್ ಬದಲಾಲೆ",
        "contribslink": "ಕಾಣಿಕೆಲು",
+       "emaillink": "ಇ-ಅಂಚೆ ಕಡಪುಡುಲೆ",
        "blocklogpage": "ತಡೆಪತ್ತ್’ದ್’ನ ಸದಸ್ಯೆರ್ನ ದಿನಚರಿ",
        "blocklogentry": "[[$1]] ಖಾತೆನ್ $2 $3 ಮುಟ್ಟ ತಡೆಪತ್ತ್’ದ್’ನ್ಡ್",
        "unblocklogentry": "$1 ಖಾತೆನ್ ಅನ್-ಬ್ಲಾಕ್ ಮಲ್ತ್’ನ್ಡ್",
        "block-log-flags-nocreate": "ಖಾತೆ ಸೃಷ್ಟಿನ್ ತಡೆಪತ್ತ್’ದ್’ನ್ಡ್",
        "movelogpage": "ಸ್ತಲಾಂತರೊದ ದಾಕಲೆ",
+       "movereason": "ಕಾರಣೊ:",
        "revertmove": "ದುಂಬುದ ಲೆಕೆ ಮಲ್ಪುಲೆ",
        "export": "ಪುಟೊಲೆನ್ ಕಡಪುಡ್ಲೆ",
+       "export-submit": "ರಫ್ತು ಮಲ್ಪುಲೆ",
+       "export-addcat": "ಸೇರಾಲೆ",
+       "export-addns": "ಸೇರಾಲೆ",
+       "export-download": "ಕಡತನ್ ಒರಿಪಾಲೆ",
        "allmessagesname": "ಪುದರ್",
+       "allmessages-filter-legend": "ಅರಿಪೆ",
+       "allmessages-filter-all": "ಮಾತಾ",
+       "allmessages-filter-modified": "ಬದಲಾಯಿನ",
+       "allmessages-language": "ಬಾಸೆ:",
+       "allmessages-filter-submit": "ಪೋ",
+       "allmessages-filter-translate": "ಭಾಷಾಂತರ ಮಲ್ಪುಲೆ",
        "thumbnail-more": "ಮಲ್ಲೆ ಮಲ್ಪುಲೆ",
        "thumbnail_error": "ಮುನ್ನೋಟ ಚಿತ್ರೊನು ಸೃಷ್ಟಿ ಮನ್ಪುನಗ ದೋಷ: $1",
+       "import": "ಪುಟೊಲೆನ್ ಕಡಪುಡ್ಲೆ",
+       "import-interwiki-sourcepage": "ಮೂಲ ಪುಟ",
+       "import-interwiki-submit": "ಆಮದು",
+       "import-upload-filename": "ಕಡತದ ಪುದರ್:",
+       "import-comment": "ಅಭಿಪ್ರಾಯೊ:",
        "tooltip-pt-userpage": "{{GENDER:|ಎನ್ನ ಸದಸ್ಯ}} ಪುಟೊ",
        "tooltip-pt-mytalk": "{{GENDER:|ಎನ್ನ}} ಚರ್ಚೆ ಪುಟೊ",
        "tooltip-pt-preferences": "{{GENDER:|ಎನ್ನ}} ಇಸ್ಟೊಲು",
        "tooltip-undo": "\"ವಜಾ ಮಲ್ಪುಲೆ\" ಈ ಬದಲಾವಣೆನ್ ದೆತೊನುಜಿ ಬುಕ್ಕೊ ಪ್ರಿವ್ಯೂ ಮೋಡ್‍ಡ್ ಬದಲಾವಣೆ ಮಲ್ಪೆರ್ ಕೊನೊಪು೦ಡು. ಅ೦ಚೆನೆ ಸಾರಾಂಸೊಡು ಬದಲಾವಣೆಗ್ ಕಾರಣ ಸೇರಾಯರ ಆಪು೦ಡು.",
        "tooltip-summary": "ಒಂಜಿ ಎಲ್ಯ ಸಾರಾಂಸೊ ಕೊರ್ಲೆ",
        "simpleantispam-label": "ಯಾಂಟಿ-ಸ್ಪಾಮ್ ಚೆಕ್.\nಮುಲ್ಪ <strong>ದಿಂಜಾವೊಡ್ಚಿ</strong>",
+       "pageinfo-article-id": "ಪುಟೊದ ಐಡಿ",
        "pageinfo-toolboxlink": "ಪುಟೊದ ಮಾಹಿತಿ",
+       "pageinfo-contentpage-yes": "ಅಂದ್",
+       "pageinfo-protect-cascading-yes": "ಅಂದ್",
+       "pageinfo-category-pages": "ಪುಟೊಕುಲೆ ಸಂಕ್ಯೆ",
        "previousdiff": "← ದುಂಬುದ ಸಂಪದನೆ",
        "nextdiff": "ಬುಕ್ಕೊದ ಸಂಪದನೆ →",
+       "thumbsize": "ಕಿರುನೋಟದ ಗಾತ್ರೊ:",
        "file-info-size": "$1 × $2 ಚಿತ್ರಬಿಂದುಲು, ಫೈಲ್‍ದ ಗಾತ್ರೊ: $3, MIME ಪ್ರಕಾರೊ: $4",
        "file-nohires": "ಇಂದೆರ್ದ್ ಜಾಸ್ತಿ ರೆಸಲ್ಯೂಶನ್ ಇದ್ದಿ,",
        "svg-long-desc": "ಎಸ್.ವಿ.ಜಿ ಫೈಲ್, ಸುಮಾರಾದ್ $1 × $2 ಚಿತ್ರೊಬಿಂದು, ಫೈಲ್‍ದ ಗಾತ್ರ: $3",
        "show-big-image-preview": "ಪಿರವುದ ಪುಟೊದ ಗಾತ್ರೊ: $1.",
        "show-big-image-other": "ಬೇತೆ{{PLURAL:$2|resolution|ನಿರ್ನಯೊಲು}}: $1.",
        "show-big-image-size": "$1 × $2 ಚಿತ್ರೊಬಿಂದುಲು",
+       "newimages-legend": "ಅರಿಪೆ",
+       "ilsubmit": "ನಾಡ್‍ಲೆ",
        "bad_image_list": "ವ್ಯವಸ್ಥೆದ ಆಕಾರ ಈ ರೀತಿ ಉಂಡು:\n\nಪಟ್ಟಿಡುಪ್ಪುನಂಚಿನ ದಾಖಲೆಲೆನ್ (* ರ್ದ್ ಶುರು ಆಪುನ ಸಾಲ್’ಲು) ಮಾತ್ರ ಪರಿಗಣನೆಗ್ ದೆತೊನೆರಾಪುಂಡು.\nಪ್ರತಿ ಸಾಲ್’ದ ಶುರುತ ಲಿಂಕ್ ಒಂಜಿ ದೋಷ ಉಪ್ಪುನಂಚಿನ ಫೈಲ್’ಗ್ ಲಿಂಕಾದುಪ್ಪೊಡು.\nಅವ್ವೇ ಸಾಲ್’ದ ಶುರುತ ಪೂರಾ ಲಿಂಕ್’ಲೆನ್ ಪರಿಗನೆರ್ದ್ ದೆಪ್ಪೆರಾಪುಂಡು, ಪಂಡ ಓವು ಪುಟೊಲೆಡ್ ಫೈಲ್’ದ ಬಗ್ಗೆ ಬರ್ಪುಂಡೋ ಔಲು.",
        "metadata": "ಮೆಟಾಡೇಟಾ",
        "metadata-help": "ಈ ಪೈಲ್‍ಡ್ ಜಾಸ್ತಿ ಮಾಹಿತಿ ಉಂಡು. ಹೆಚ್ಚಿನಂಸೊ ಪೈಲ್‍ನ್ ಉಂಡು ಮಲ್ಪೆರೆ ಉಪಯೋಗ ಮಲ್ತಿನ ಡಿಜಿಟಲ್ ಕ್ಯಾಮೆರರ್ದ್ ಅತ್ತ್ಂಡ ಸ್ಕ್ಯಾನರ್‌ರ್ದ್ ಈ ಮಾಹಿತಿ ಬತ್ತ್ಂಡ್.\nಮೂಲಪ್ರತಿರ್ದ್ ಈ ಪೈಲ್ ಬದಲಾದಿತ್ತ್ಂಡ್, ಈ ಮಾಹಿತಿ ಬದಲಾತಿನ ಪೈಲ್‍ದ ವಿವರೊಲೆಗ್ ಸರಿಯಾದ್ ಹೊಂದಂದೆ ಉಪ್ಪು.",
        "metadata-expand": "ವಿಸ್ತಾರವಾಯಿನ ವಿವರೊಲೆನ್ ತೊಜ್ಪಾವು",
        "metadata-collapse": "ವಿಸ್ತಾರವಾಯಿನ ವಿವರೊಲೆನ್ ದೆಂಗಾವು",
        "metadata-fields": "ಈ ಸಂದೇಸೊಡು ಪಟ್ಟಿ ಮಲ್ತಿನಂಚಿನ EXIF ಮಿತ್ತ ದರ್ಜೆದ ಮಾಹಿತಿನ್ ಚಿತ್ರೊ ಪುಟೊಕು ಸೇರ್ಪಾಯೆರೆ ಆವೊಂದುಂಡು. ಪುಟೊಟು ಮಿತ್ತ ದರ್ಜೆ ಮಾಹಿತಿದ ಪಟ್ಟಿನ್ ದೆಪ್ಪುನಗ ಉಂದು ತೋಜುಂಡು.\nಒರಿದನವು ಮೂಲೊ ಸ್ಥಿತಿಟ್ ಅಡೆಂಗ್‍ದುಂಡು.\n*ಮಲ್ಪುಲೆ\n*ಮಾದರಿ\n*ದಿನೊ ಪೊರ್ತು ಮೂಲೊ\n*ಮಾನಾದಿಗೆದ ಸಮಯೊ\n*ಫ್‍ಸಂಖ್ಯೆ\n*ಐಎಸ್ಒ ವೇಗೊದ ರೇಟಿಂಗ್\n*ತೂಪಿನ ಜಾಗೆದ ದೂರ\n*ಕಲಾವಿದೆ\n*ಕೃತಿಸ್ವಾಮ್ಯೊ\n*ಚಿತ್ರೊ ವಿವರಣೆ\n*ಜಿಪಿಎಸ್ ಅಕ್ಷಾಂಸೊ\n*ಜಿಪಿಎಸ್ ರೇಖಾಂಸೊ\n*ಜಿಪಿಎಸ್ ಎತ್ತರೊ",
+       "exif-imagewidth": "ಅಗೆಲ",
+       "exif-imagelength": "ಎತ್ತರೊ",
        "exif-orientation": "ದಿಕ್ಕ್ ದಿಸೆ",
        "exif-xresolution": "ಅಡ್ಡಗಲೊದ ರೆಜ಼ಲ್ಯೂಶನ್",
        "exif-yresolution": "ಉದ್ದೊದ ರೆಜ಼ಲ್ಯೂಶನ್",
        "exif-make": "ಕ್ಯಾಮರೊದ ತಯಾರೆಕೆರ್",
        "exif-model": "ಕ್ಯಾಮರೊದ ಮಾದರಿ",
        "exif-software": "ಉಪಯೋಗೊ ಮಲ್ತಿನ ತಂತ್ರಾಂಸೊ",
+       "exif-artist": "ಬರೆತಿನಾರ್",
+       "exif-copyright": "ಹಕ್ಕುದಾರೆ",
        "exif-exifversion": "Exif ಆವೃತ್ತಿ",
        "exif-colorspace": "ಬಣ್ಣೊದ ಜಾಗೆ",
        "exif-datetimeoriginal": "ಮಾಹಿತಿ ಸ್ರಿಸ್ಟಿಸಯಿನ ದಿನೊ ಬೊಕ್ಕ ಪೊರ್ತು",
        "exif-datetimedigitized": "ಗಣಕೀಕರಣೊದ ದಿನೊ ಬೊಕ್ಕ ಪೊರ್ತು",
+       "exif-flash": "ಫ್ಲ್ಯಾಶ್",
+       "exif-source": "ಮೂಲೊ",
+       "exif-languagecode": "ಭಾಸೆ",
+       "exif-iimcategory": "ವರ್ಗೊ",
+       "exif-label": "ಗುರುತು ಪಟ್ಟಿ",
        "exif-orientation-1": "ಸಾದಾರನೊ",
+       "exif-meteringmode-1": "ಸರಾಸರಿ",
+       "exif-meteringmode-255": "ಇತರೊ",
+       "exif-lightsource-0": "ಗೊತ್ತಿಜ್ಜಾಂದಿನ",
+       "exif-lightsource-4": "ಫ್ಲ್ಯಾಶ್",
+       "exif-contrast-0": "ಸಾದಾರನೊ",
+       "exif-saturation-0": "ಸಾದಾರನೊ",
+       "exif-subjectdistancerange-0": "ಗೊತ್ತಿಜ್ಜಾಂದಿನ",
+       "exif-iimcategory-hth": "ಆರೋಗ್ಯ",
        "namespacesall": "ಮಾತ",
        "monthsall": "ಮಾತ",
+       "confirm_purge_button": "ಸರಿ",
+       "confirm-watch-button": "ಸರಿ",
+       "confirm-unwatch-button": "ಸರಿ",
+       "confirm-rollback-button": "ಸರಿ",
+       "quotation-marks": "\"$1\"",
+       "imgmultipageprev": "← ದುಂಬುತ ಪುಟೊ",
+       "imgmultipagenext": "ನನತಾ ಪುಟ →",
+       "img-lang-go": "ಪೋಲೆ",
+       "table_pager_next": "ನನತಾ ಪುಟ",
+       "table_pager_prev": "ದುಂಬುತ ಪುಟೊ",
+       "table_pager_first": "ಸುರುತ ಪುಟೊ",
+       "table_pager_last": "ಕಡೆತ ಪುಟೊ",
+       "table_pager_limit_submit": "ಪೋಲೆ",
+       "watchlistedit-raw-titles": "ತರೆಬರವು:",
        "watchlistedit-clear-title": "ತುಯಿನೇನ್ ಮಾಜಾಲೇ",
+       "watchlistedit-clear-legend": "ತುಯಿನೇನ್ ಮಾಜಾಲೇ",
+       "watchlistedit-clear-titles": "ತರೆಬರವು:",
        "watchlisttools-view": "ಪ್ರಸ್ತುತ ಬದಲಾವಣೆಲ್ ತೋಜಾಲೆ",
        "watchlisttools-edit": "ವೀಕ್ಷಣಾಪಟ್ಟಿನ್ ತೂಲೆ ಬೊಕ್ಕ ಎಡಿಟ್ ಮಲ್ಪುಲೆ",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|ಪಾತೆರ್ಲೆ]])",
+       "version": "ಆವೃತ್ತಿ",
+       "version-specialpages": "ವಿಸೇಸೊ ಪುಟೊಲು",
+       "version-other": "ಇತರೊ",
+       "version-ext-license": "ಪರವಾನಗಿ",
+       "version-ext-colheader-name": "ವಿಸ್ತರಣೆ",
+       "version-skin-colheader-name": "ಸ್ಕಿನ್",
+       "version-ext-colheader-version": "ಆವೃತ್ತಿ",
+       "version-ext-colheader-license": "ಪರವಾನಗಿ",
+       "version-ext-colheader-description": "ವಿವರಣೆ",
+       "version-ext-colheader-credits": "ಲೇಖಕೆರ್",
+       "version-poweredby-others": "ಇತರೊ",
+       "version-software-product": "ಉತ್ಪನ್ನ",
+       "version-software-version": "ಆವೃತ್ತಿ",
+       "version-libraries-library": "ಗ್ರಂಥಾಲಯೊ",
+       "version-libraries-version": "ಆವೃತ್ತಿ",
+       "version-libraries-license": "ಪರವಾನಗಿ",
+       "version-libraries-description": "ವಿವರಣೆ",
+       "version-libraries-authors": "ಲೇಖಕೆರ್",
+       "redirect-submit": "ಪೋಲೆ",
+       "redirect-value": "ಮೌಲ್ಯ:",
+       "redirect-user": "ಬಳಕೆದಾರೆರ ID",
+       "redirect-page": "ಪುಟೊದ ಐಡಿ",
+       "redirect-file": "ಕಡತದ ಪುದರ್",
+       "fileduplicatesearch-filename": "ಕಡತದ ಪುದರ್:",
+       "fileduplicatesearch-submit": "ನಾಡ್‍ಲೆ",
        "specialpages": "ವಿಸೇಸೊ ಪುಟೊಲು",
+       "blankpage": "ಖಾಲಿ ಪುಟ",
        "tag-filter": "[[Special:Tags|ಟ್ಯಾಗ್]]ಅರಿಪೆ:",
+       "tag-filter-submit": "ಅರಿಪೆ",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag|ಟ್ಯಾಗುಲು}}]]:$2)",
+       "tags-title": "ತೂಗು ಪಟ್ಟಿಲು",
+       "tags-source-header": "ಮೂಲೊ",
+       "tags-active-header": "ಸಕ್ರಿಯ?",
+       "tags-actions-header": "ಕ್ರಿಯೆಕ್ಕುಲು",
+       "tags-active-yes": "ಅಂದ್",
+       "tags-active-no": "ಅತ್ತ್",
+       "tags-edit": "ಸಂಪೊಲಿಪುಲೆ",
+       "tags-delete": "ಮಾಜಾಲೆ",
+       "tags-create-reason": "ಕಾರಣ:",
+       "tags-create-submit": "ಸೃಷ್ಟಿಸಾಲೆ",
+       "tags-delete-reason": "ಕಾರಣ:",
+       "tags-deactivate-reason": "ಕಾರಣ:",
        "logentry-delete-delete": "$1{{GENDER:$2|ಮಾಜಾದ್‍ಂಡ್}}ಪುಟೊ $3",
        "logentry-move-move": "$1 {{GENDER:$2|ಜಾರಲೆ}} ಪುಟೊ $3 ಡ್ದ್ $4",
        "logentry-newusers-create": "ಬಳಕೆದಾರೆರೆ ಕಾತೆ $1 ನ್ನು {{GENDER:$2|ಸ್ರಿಸ್ಟಿ ಮಲ್ತಾಂಡ್}}",
index 8368ac5..4377326 100644 (file)
        "prefs-watchlist-token": "వీక్షణాజాబితా టోకెను:",
        "prefs-misc": "ఇతరత్రా",
        "prefs-resetpass": "సంకేతపదాన్ని మార్చుకోండి",
-       "prefs-changeemail": "ఈ-మెయిలు చిరునామా మార్పు",
+       "prefs-changeemail": "ఈ-మెయిలు చిరునామా మార్పు లేదా తొలగింపు",
        "prefs-setemail": "ఓ ఈమెయిల్ చిరునామా ఇవ్వండి",
        "prefs-email": "ఈ-మెయిల్ ఎంపికలు",
        "prefs-rendering": "రూపురేఖలు",
        "saveprefs": "భద్రపరచు",
        "restoreprefs": "అప్రమేయ అమరికలను పునఃస్థాపించు (అన్ని విభాగాల్లోనూ)",
-       "prefs-editing": "సవరిసà±\8dà°¤à±\81à°¨à±\8dనారు",
+       "prefs-editing": "దిదà±\8dà°¦à±\81బాà°\9fà±\8dà°²ు",
        "rows": "అడ్డు వరుసలు:",
        "columns": "నిలువు వరుసలు:",
        "searchresultshead": "వెతుకు",
-       "stub-threshold": "<a href=\"#\" class=\"stub\">మొలక లింకు</a> ఫార్మాటింగు కొరకు హద్దు (బైట్లు):",
+       "stub-threshold": "మొలక లింకు ఫార్మాటింగు కొరకు హద్దు ($1):",
        "stub-threshold-sample-link": "నమూనా",
        "stub-threshold-disabled": "అచేతనం",
        "recentchangesdays": "ఇటీవలి మార్పులు లో చూపించవలసిన రోజులు:",
        "prefs-help-recentchangescount": "ఇది ఇటీవలి మార్పులు, పేజీ చరిత్రలు, మరియు చిట్టాలకు వర్తిస్తుంది.",
        "prefs-help-watchlist-token2": "మీ వీక్షణజాబితా యొక్క జాలవడ్డింపుకు చెందిన రహస్య తాళమిది.\nఈ తాళం తెలిసిన ఎవరైనా మీ వీక్షణజాబితాను చదవగలుగుతారు. అందుచేత దీన్ని ఎవరికీ ఇవ్వకండి.\n[[Special:ResetTokens|దాన్ని మార్చాలంటే ఇక్కడ నొక్కండి]].",
        "savedprefs": "మీ అభిరుచులను భద్రపరిచాం.",
+       "savedrights": "{{GENDER:$1|$1}} వాడుకరి హక్కులను భద్రపరచాం.",
        "timezonelegend": "కాల మండలం:",
        "localtime": "స్థానిక సమయం:",
        "timezoneuseserverdefault": "వికీ అప్రమేయాన్ని ఉపయోగించు ($1)",
        "badsig": "సంతకం చెల్లనిది.\nHTML ట్యాగులను ఒకసారి సరిచూసుకోండి.",
        "badsiglength": "మీ సంతకం చాలా పెద్దగా ఉంది.\nఇది తప్పనిసరిగా $1 {{PLURAL:$1|అక్షరం|అక్షరాల}} లోపులోనే ఉండాలి.",
        "yourgender": "మిమ్మల్ని మీరు ఎలా వర్ణించుకుంటారు?",
-       "gender-unknown": "à°µà±\86à°²à±\8dలడిà°\82à°\9aడానిà°\95à°¿ à°¨à±\87à°¨à±\81 à°\87à°·à±\8dà°\9fపడà°\9fà±\8dà°²à±\87à°¦à±\81",
+       "gender-unknown": "సాఫà±\8dà°\9fà±\81à°µà±\87à°°à±\81 à°®à°¿à°®à±\8dమలà±\8dని à°\89à°²à±\8dà°²à±\87à°\96à°¿à°\82à°\9aà±\87 à°¸à°\82దరà±\8dà°­à°\82à°²à±\8b, à°µà±\80à°²à±\88à°¨à°\82తవరà°\95à±\81 à°²à°¿à°\82à°\97 à°¤à°\9fà°¸à±\8dథతనà±\81 à°\85వలà°\82బిసà±\8dà°¤à±\81à°\82ది",
        "gender-male": "అతను వికీ పేజీలను సరిదిద్దుతాడు",
        "gender-female": "ఆమె వికీ పేజీలను సరిదిద్దుతుంది",
        "prefs-help-gender": "ఈ అభిరుచిని అమర్చుకోవడం ఐచ్చికం.\nమిమ్మల్ని సంబోధించేప్పుడూ మిమ్మల్ని పేర్కొనేప్పుడూ వ్యాకరణపరంగా సరైన లింగాన్ని  వాడటానికి ఈ విలువ ఉపయోగపడుతుంది.\nఈ సమాచారం బహిరంగం.",
        "prefs-tokenwatchlist": "టోకెన్",
        "prefs-diffs": "తేడాలు",
        "prefs-help-prefershttps": "ఈ అభిరుచి మీరు పైసారి లాగినైనపుడు అమలౌతుంది.",
+       "prefswarning-warning": "మీ అభిరుచులలో మీరు చేసిన మార్పులను ఇంకా భద్రపరచలేదు. మీరు \"$1\" ను నొక్కకుండా ఈ పేజీని వదలి వెళ్తే, మీ అభిరుచులు భద్రం కావు.",
        "prefs-tabs-navigation-hint": "చిట్కా: ట్యాబుల జాబితాలో ఓ ట్యాబు నుండి మరోదానికి వెళ్ళేందుకు కుడి ఎడమ బాణాల కీలను వాడవచ్చు.",
        "userrights": "వాడుకరి హక్కుల నిర్వహణ",
        "userrights-lookup-user": "వాడుకరి సమూహాలను నిర్వహించండి",
        "userrights-user-editname": "వాడుకరిపేరును ఇవ్వండి:",
-       "editusergroup": "వాడుకరి గుంపులను మార్చు",
-       "editinguser": "వాడుకరి '''[[User:$1|$1]]''' $2 యొక్క వాడుకరి హక్కులను మారుస్తున్నారు",
+       "editusergroup": "{{GENDER:$1|వాడుకరి}} గుంపులను మార్చు",
+       "editinguser": "{{GENDER:$1|వాడుకరి}} <strong>[[వాడుకరి:$1|$1]]</strong> $2 యొక్క వాడుకరి హక్కులను మారుస్తున్నారు",
        "userrights-editusergroup": "వాడుకరి సమూహాలను మార్చండి",
-       "saveusergroups": "వాడుకరి గుంపులను భద్రపరచు",
+       "saveusergroups": "{{GENDER:$1|వాడుకరి}} గుంపులను భద్రపరచు",
        "userrights-groupsmember": "సభ్యులు:",
        "userrights-groupsmember-auto": "సంభావిత సభ్యులు:",
        "userrights-groups-help": "ఈ వాడుకరి ఏయే గుంపులలో ఉండాలో మీరు మార్చవచ్చు.\n* టిక్కు పెట్టివుంటే ఆ గుంపులో ఈ వాడుకరి ఉన్నట్టు.\n* టిక్కు లేకుంటే ఆ గుంపులో ఈ వాడుకరి లేనట్టు.\n* * ఉంటే ఒకసారి ఆ గుంపుని చేర్చాక మీరు తీసివేయలేరు, లేదా తీసివేసాక తిరిగి చేర్చలేరు.",
        "userrights-changeable-col": "మీరు మార్చదగిన గుంపులు",
        "userrights-unchangeable-col": "మీరు మార్చలేని గుంపులు",
        "userrights-conflict": "వాడుకరి హక్కుల మార్పులలో ఘర్షణ! మీ మార్పులను సమీక్షించి, నిర్ధారించండి.",
-       "userrights-removed-self": "à°®à±\80 à°¹à°\95à±\8dà°\95à±\81లనà±\81 à°®à±\80à°°à±\81 à°µà°¿à°\9cయవà°\82à°¤à°\82à°\97à°¾ à°¤à±\8aà°²à°\97à°¿à°\82à°\9aà±\81à°\95à±\81à°¨à±\8dనారà±\81. à°¤à°¦à±\8dవారా, à°\88 à°ªà±\87à°\9cà±\80ని à°\9aà±\82డడానిà°\95à°¿ à°®à±\80à°\95à±\81 à°\87à°\95 à°\85à°¨à±\81మతి à°²à±\87à°¦ు.",
+       "userrights-removed-self": "à°®à±\80 à°¹à°\95à±\8dà°\95à±\81లనà±\81 à°®à±\80à°°à±\81 à°¤à±\8aà°²à°\97à°¿à°\82à°\9aà±\81à°\95à±\81à°¨à±\8dనారà±\81. à°\87à°\95, à°®à±\80à°°à±\80 à°ªà±\87à°\9cà±\80ని à°\9aà±\82à°¡à°²à±\87à°°ు.",
        "group": "గుంపు:",
        "group-user": "వాడుకరులు",
        "group-autoconfirmed": "ఆటోమాటిగ్గా నిర్ధారించబడిన వాడుకరులు",
        "right-managechangetags": "డేటాబేసులో [[Special:Tags|ట్యాగుల]]ను సృష్టించడం, తొలగించడం",
        "right-applychangetags": "తన మార్పులతో [[Special:Tags|ట్యాగుల]]ను ఆపాదించడం",
        "right-changetags": "విడి కూర్పులకు, చిట్టా పద్దులకు ఏవైనా [[Special:Tags|ట్యాగుల]]ను చేర్చడం, తొలగించడం",
+       "right-deletechangetags": "[[ప్రత్యేక:Tags|ట్యాగులను]] డేటాబేసు నుండి తొలగించు",
+       "grant-generic": "\"$1\" హక్కుల కట్ట",
+       "grant-group-email": "ఈమెయిలు పంపించడం",
+       "grant-group-administration": "నిర్వాహక చర్యలు చేపట్టడం",
+       "grant-group-private-information": "మీ గోపనీయ డేటాను చూడడం",
        "newuserlogpage": "కొత్త వాడుకరుల చిట్టా",
        "newuserlogpagetext": "ఇది వాడుకరి నమోదుల చిట్టా.",
        "rightslog": "వాడుకరుల హక్కుల మార్పుల చిట్టా",
index f81a37c..2eaa98c 100644 (file)
        "linkaccounts-submit": "Пов'язати облікові записи",
        "unlinkaccounts": "Відв'язати облікові записи",
        "unlinkaccounts-success": "Обліковий запис було відв'язано.",
-       "authenticationdatachange-ignored": "Неопрацьована зміна облікових даних. Можливо, жоден з провайдерів не був налаштований?"
+       "authenticationdatachange-ignored": "Неопрацьована зміна облікових даних. Можливо, жоден з провайдерів не був налаштований?",
+       "userjsispublic": "Будь ласка, зверніть увагу: підсторінки JavaScript не повинні містити конфіденційних даних, бо їх можуть бачити інші користувачі.",
+       "usercssispublic": "Будь ласка, зверніть увагу: підсторінки CSS не повинні містити конфіденційних даних, бо їх можуть бачити інші користувачі."
 }
index 14059a5..2afd362 100644 (file)
        "changepassword-throttled": "Bạn đã thử đăng nhập gần đây nhiều lần quá. Xin chờ $1 trước khi bạn thử lần nữa.",
        "botpasswords": "Mật khẩu Bot",
        "botpasswords-summary": "<em>Mật khẩu bot</em> cho phép truy cập một tài khoản người dùng qua API mà không sử dụng thông tin chứng nhận chính của tài khoản. Các quyền người dùng có thể bị hạn chế khi đăng nhập dùng mật khẩu bot.\n\nNếu bạn không hiểu tại sao cần sử dụng mật khẩu bot, có lẽ bạn không nên sử dụng nó. Không ai bao giờ có lý do chính đáng để yêu cầu bạn tạo ra một mật khẩu bot và cung cấp nó cho họ.",
-       "botpasswords-disabled": "Mật khẩu Bot bị vô hiệu hoá.",
+       "botpasswords-disabled": "Mật khẩu bot bị vô hiệu hóa.",
        "botpasswords-no-central-id": "Để sử dụng mật khẩu bot, bạn phải đăng nhập vào một tài khoản tập trung.",
        "botpasswords-existing": "Mật khẩu bot hiện tại",
        "botpasswords-createnew": "Tạo một mật khẩu mới bot",
        "grant-group-high-volume": "Hoạt động với tần số cao",
        "grant-group-customization": "Tùy biến và tùy chọn",
        "grant-group-administration": "Thực hiện các hành động bảo quản",
+       "grant-group-private-information": "Truy cập dữ liệu cá nhân của bạn",
        "grant-group-other": "Hoạt động khác",
        "grant-blockusers": "Cấm và bỏ cấm người dùng",
        "grant-createaccount": "Mở tài khoản",
        "grant-highvolume": "Sửa đổi tốc độ cao",
        "grant-oversight": "Ẩn người dùng và phiên bản",
        "grant-patrol": "Tuần tra các thay đổi trang",
+       "grant-privateinfo": "Truy cập dữ liệu cá nhân",
        "grant-protect": "Khóa và mở khóa các trang",
        "grant-rollback": "Lùi một loạt thay đổi vào một trang",
        "grant-sendemail": "Gửi thư điện tử cho người dùng khác",
        "uploadstash-errclear": "Việc dọn sạch các tập tin bị thất bại.",
        "uploadstash-refresh": "Làm mới danh sách tập tin",
        "uploadstash-thumbnail": "xem hình thu nhỏ",
+       "uploadstash-exception": "Không thể lưu tập tin vào hàng đợi tải lên ($1): “$2”.",
        "invalid-chunk-offset": "Khúc lệch (chunk offset) không hợp lệ",
        "img-auth-accessdenied": "Không cho phép truy cập",
        "img-auth-nopathinfo": "Thiếu PATH_INFO.\nMáy chủ của bạn không được thiết lập để truyền thông tin này.\nCó thể do nó dựa trên CGI và không hỗ trợ img_auth.\nXem [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization hướng dẫn điều khiển truy cập hình ảnh].",
        "watchnologin": "Chưa đăng nhập",
        "addwatch": "Thêm vào danh sách theo dõi",
        "addedwatchtext": "“[[:$1]]” cùng trang thảo luận đã vào [[Special:Watchlist|danh sách theo dõi]] của bạn.",
+       "addedwatchtext-talk": "“[[:$1]]” cùng trang đi kèm đã vào [[Special:Watchlist|danh sách theo dõi]] của bạn.",
        "addedwatchtext-short": "Trang “$1” đã được thêm vào danh sách theo dõi của bạn.",
        "removewatch": "Gỡ khỏi danh sách theo dõi",
        "removedwatchtext": "“[[:$1]]” cùng trang thảo luận đã được đưa ra khỏi [[Special:Watchlist|danh sách theo dõi]] của bạn.",
+       "removedwatchtext-talk": "“[[:$1]]” cùng trang đi kèm đã được đưa ra khỏi [[Special:Watchlist|danh sách theo dõi]] của bạn.",
        "removedwatchtext-short": "Trang “$1” đã được xóa khỏi danh sách theo dõi của bạn.",
        "watch": "Theo dõi",
        "watchthispage": "Theo dõi trang này",
        "undeletehistorynoadmin": "Trang này đã bị xóa.\nLý do xóa trang được hiển thị dưới đây, cùng với thông tin về những người đã sửa đổi trang này trước khi bị xóa.\nChỉ có bảo quản viên mới xem được văn bản đầy đủ của những phiên bản trang bị xóa.",
        "undelete-revision": "Phiên bản đã xóa của $1 (vào lúc $4 tại $5) do $3 sửa đổi:",
        "undeleterevision-missing": "Phiên bản này không hợp lệ hay không tồn tại. Đây có thể là một địa chỉ sai, hoặc là phiên bản đã được phục hồi hoặc đã xóa khỏi kho lưu trữ.",
+       "undeleterevision-duplicate-revid": "Không thể phục hồi {{PLURAL:$1|một phiên bản|$1 phiên bản}} vì <code>rev_id</code> của {{PLURAL:$1|nó|chúng}} đã được sử dụng.",
        "undelete-nodiff": "Không tìm thấy phiên bản cũ hơn.",
        "undeletebtn": "Phục hồi",
        "undeletelink": "xem lại/phục hồi",
        "undeletedrevisions": "$1 phiên bản được phục hồi",
        "undeletedrevisions-files": "$1 phiên bản và $2 tập tin đã được phục hồi",
        "undeletedfiles": "$1 tập tin đã được phục hồi",
-       "cannotundelete": "Phục hồi thất bại:\n$1",
+       "cannotundelete": "Phục hồi bị thất bại một phần hoặc hoàn toàn:\n$1",
        "undeletedpage": "'''$1 đã được khôi phục'''\n\nXem nhật trình xóa và phục hồi các trang gần đây tại [[Special:Log/delete|nhật trình xóa]].",
        "undelete-header": "Xem các trang bị xóa gần đây tại [[Special:Log/delete|nhật trình xóa]].",
        "undelete-search-title": "Tìm kiếm trang đã bị xóa",
        "sp-contributions-newbies-sub": "Các thành viên mới",
        "sp-contributions-newbies-title": "Đóng góp của các thành viên mới",
        "sp-contributions-blocklog": "nhật trình cấm",
-       "sp-contributions-suppresslog": "đóng góp của người dùng đã bị xóa hẳn",
-       "sp-contributions-deleted": "đóng góp đã bị xóa của thành viên",
+       "sp-contributions-suppresslog": "đóng góp của {{GENDER:$1}}người dùng đã bị xóa hẳn",
+       "sp-contributions-deleted": "đóng góp đã bị xóa của {{GENDER:$1}}thành viên",
        "sp-contributions-uploads": "tập tin tải lên",
        "sp-contributions-logs": "nhật trình",
        "sp-contributions-talk": "thảo luận",
index 1fa701e..2d04f63 100644 (file)
@@ -250,8 +250,8 @@ $namespaceNames = [
        NS_MEDIA            => 'Médiá',
        NS_SPECIAL          => 'Špeciálne',
        NS_TALK             => 'Diskusia',
-       NS_USER             => 'Redaktor',
-       NS_USER_TALK        => 'Diskusia_s_redaktorom',
+       NS_USER             => 'Užívateľ',
+       NS_USER_TALK        => 'Diskusia_s_užívateľom',
        NS_PROJECT_TALK     => 'Diskusia_k_{{GRAMMAR:datív|$1}}',
        NS_FILE             => 'Súbor',
        NS_FILE_TALK        => 'Diskusia_k_súboru',
@@ -267,6 +267,8 @@ $namespaceNames = [
 
 $namespaceAliases = [
        "Komentár"               => NS_TALK,
+       'Redaktor'               => NS_USER,
+       'Diskusia_s_redaktorom'  => NS_USER_TALK,
        "Komentár_k_redaktorovi" => NS_USER_TALK,
        "Komentár_k_Wikipédii"   => NS_PROJECT_TALK,
        'Obrázok' => NS_FILE,
@@ -275,6 +277,11 @@ $namespaceAliases = [
        "Komentár_k_MediaWiki"   => NS_MEDIAWIKI_TALK,
 ];
 
+$namespaceGenderAliases = [
+       NS_USER => [ 'male' => 'Užívateľ', 'female' => 'Užívateľka' ],
+       NS_USER_TALK => [ 'male' => 'Diskusia_s_užívateľom', 'female' => 'Diskusia_s_užívateľkou' ],
+];
+
 $separatorTransformTable = [
        ',' => "\xc2\xa0",
        '.' => ','
index 9cf7b2b..bd34a50 100644 (file)
@@ -8,7 +8,7 @@ class ValidateRegistrationFile extends Maintenance {
                $this->addArg( 'path', 'Path to extension.json/skin.json file.', true );
        }
        public function execute() {
-               if ( !class_exists( 'JsonSchema\Uri\UriRetriever' ) ) {
+               if ( !class_exists( 'JsonSchema\Validato' ) ) {
                        $this->error( 'The JsonSchema library cannot be found, please install it through composer.', 1 );
                }
 
@@ -38,11 +38,8 @@ class ValidateRegistrationFile extends Maintenance {
                        $this->output( "Warning: $path is using a deprecated schema, and should be updated to "
                                . ExtensionRegistry::MANIFEST_VERSION . "\n" );
                }
-               $retriever = new JsonSchema\Uri\UriRetriever();
-               $schema = $retriever->retrieve( 'file://' . $schemaPath );
-
-               $validator = new JsonSchema\Validator();
-               $validator->check( $data, $schema );
+               $validator = new JsonSchema\Validator;
+               $validator->check( $data, (object) [ '$ref' => 'file://' . $schemaPath ] );
                if ( $validator->isValid() ) {
                        $this->output( "$path validates against the version $version schema!\n" );
                } else {
index 0bdf02e..946823d 100644 (file)
                        $.each( response.query.pages, function ( index, page ) {
                                var title = new ForeignTitle( page.title ).getPrefixedText();
                                cache.existenceCache[ title ] = !page.missing;
+                               if ( !queue[ title ] ) {
+                                       // Debugging for T139130
+                                       throw new Error( 'No queue for "' + title + '", requested "' + titles.join( '|' ) + '"' );
+                               }
                                queue[ title ].resolve( cache.existenceCache[ title ] );
                        } );
                } );
index 3cdab3c..a8786ef 100644 (file)
@@ -6,7 +6,7 @@
 
        function addMulti( $oldContainer, $container ) {
                var name = $oldContainer.find( 'input:first-child' ).attr( 'name' ),
-                       oldClass = ( ' ' + $oldContainer.attr( 'class' ) + ' ' ).replace( /(mw-htmlform-field-HTMLMultiSelectField|mw-chosen)/g, '' ),
+                       oldClass = ( ' ' + $oldContainer.attr( 'class' ) + ' ' ).replace( /(mw-htmlform-field-HTMLMultiSelectField|mw-chosen|mw-htmlform-dropdown)/g, '' ),
                        $select = $( '<select>' ),
                        dataPlaceholder = mw.message( 'htmlform-chosen-placeholder' );
                oldClass = $.trim( oldClass );
@@ -53,9 +53,9 @@
        }
 
        mw.hook( 'htmlform.enhance' ).add( function ( $root ) {
-               if ( $root.find( '.mw-chosen' ).length ) {
+               if ( $root.find( '.mw-htmlform-dropdown' ).length ) {
                        mw.loader.using( 'jquery.chosen', function () {
-                               $root.find( '.mw-chosen' ).each( function () {
+                               $root.find( '.mw-htmlform-dropdown' ).each( function () {
                                        var type = this.nodeName.toLowerCase(),
                                                $converted = convertCheckboxesToMulti( $( this ), type );
                                        $converted.find( '.htmlform-chzn-select' ).chosen( { width: 'auto' } );
index c7bbc62..3e9fef8 100644 (file)
@@ -2824,7 +2824,7 @@ parsoid
 !! wikitext
 {{echo|[{{fullurl:{{FULLPAGENAME}}|action=edit}} bar]}}
 !! html
-<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[{{fullurl:{{FULLPAGENAME}}|action=edit}} bar]"}},"i":0}}]}'>[Main_Page bar]</p>
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[{{fullurl:{{FULLPAGENAME}}|action=edit}} bar]"}},"i":0}}]}'>[Main Page bar]</p>
 !! end
 
 !! test
@@ -3173,58 +3173,19 @@ foo
 
 !!end
 
-!!test
+!! test
 4. Indent-Pre and extension tags
 !! wikitext
- a <gallery>
-File:foobar.jpg
-</gallery>
-!! html
- a <ul class="gallery mw-gallery-traditional">
-               <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div>
-                       <div class="gallerytext">
-                       </div>
-               </div></li>
-</ul>
-
-!! html+tidy
-<p>a</p>
-<ul class="gallery mw-gallery-traditional">
-<li class="gallerybox" style="width: 155px">
-<div style="width: 155px">
-<div class="thumb" style="width: 150px;">
-<div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div>
-</div>
-<div class="gallerytext"></div>
-</div>
-</li>
-</ul>
-!!end
+ a <tag />
+!! html/php
+ a <pre>
+NULL
+array (
+)
+</pre>
 
-!! test
-Table wikitext syntax outside wiki-tables
-!! wikitext
-a
-! not a table heading
-|- not a table row
-| not a table cell
-| class="foo bar" | baz
-b
-|}
-|-
-c
-!! html
-<p>a
-! not a table heading
-|- not a table row
-| not a table cell
-| class="foo bar" | baz
-b
-|}
-|-
-c
-</p>
+!! html/parsoid
+ a <pre typeof="mw:Extension/tag" about="#mwt2" data-parsoid='{}' data-mw='{"name":"tag","attrs":{},"body":null}'></pre>
 !! end
 
 !!test
@@ -4865,13 +4826,20 @@ And again with mixed protocols: [ftp://example.com?url=http://example.com link]
 </p>
 !!end
 
+# Since Parsoid is starting to emit canonical wikitext for links,
+# [http://example.com http://example.com] will not RT back to that
+# form anymore.
 !! test
 External links: URL in text
+!! options
+parsoid=wt2html
 !! wikitext
 URL in text: [http://example.com http://example.com]
-!! html
+!! html/php
 <p>URL in text: <a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>
 </p>
+!! html/parsoid
+<p>URL in text: <a rel="mw:ExtLink" href="http://example.com">http://example.com</a></p>
 !! end
 
 !! test
@@ -7619,11 +7587,14 @@ Just a test of an article title containing a percent.
 Link containing % (not as a hex sequence)
 !! wikitext
 [[7% Solution]]
+[[7% Solution|7%25 Solution]]
 !! html/php
 <p><a href="/wiki/7%25_Solution" title="7% Solution">7% Solution</a>
+<a href="/wiki/7%25_Solution" title="7% Solution">7%25 Solution</a>
 </p>
 !! html/parsoid
-<p><a rel="mw:WikiLink" href="./7%25_Solution" title="7% Solution">7% Solution</a></p>
+<p><a rel="mw:WikiLink" href="./7%25_Solution" title="7% Solution">7% Solution</a>
+<a rel="mw:WikiLink" href="./7%25_Solution" title="7% Solution">7%25 Solution</a></p>
 !! end
 
 # note that the parsoid HTML is identical to the previous test output,
@@ -7635,11 +7606,14 @@ Link containing % as a single hex sequence interpreted to char
 parsoid=wt2wt,wt2html,html2html
 !! wikitext
 [[7%25 Solution]]
+[[7%25 Solution|7%25 Solution]]
 !! html/php
 <p><a href="/wiki/7%25_Solution" title="7% Solution">7% Solution</a>
+<a href="/wiki/7%25_Solution" title="7% Solution">7%25 Solution</a>
 </p>
 !! html/parsoid
-<p><a rel="mw:WikiLink" href="./7%25_Solution" title="7% Solution">7% Solution</a></p>
+<p><a rel="mw:WikiLink" href="./7%25_Solution" title="7% Solution">7% Solution</a>
+<a rel="mw:WikiLink" href="./7%25_Solution" title="7% Solution">7%25 Solution</a></p>
 !!end
 
 !! test
@@ -8004,6 +7978,28 @@ Link with multiple ":" in a subpage-supporting namespace (bug 63636)
 <p><a rel="mw:WikiLink" href="./User:Foo/Test/63636:Bar" title="User:Foo/Test/63636:Bar">Test</a></p>
 !! end
 
+## Mainly a sanity check for Parsoid
+!! test
+Handle title parsing for subpages
+!! options
+title=[[/123123]]
+!! wikitext
+123
+!! html/parsoid
+<p>123</p>
+!! end
+
+## FIXME: Add a working php section here
+!! test
+Link to a subpage from a namespace other than main
+!! options
+title=[[User:test]]
+!! wikitext
+[[/123]]
+!! html/parsoid
+<p><a rel="mw:WikiLink" href="./User:Test/123" title="User:Test/123" data-parsoid='{"stx":"simple","a":{"href":"./User:Test/123"},"sa":{"href":"/123"}}'>/123</a></p>
+!! end
+
 !! test
 Purely hash wikilink
 !! options
@@ -8515,18 +8511,25 @@ language=ln
 !! test
 Parsoid bug 53221: Wikilinks should be properly entity-escaped
 !! options
-parsoid=html2wt
+parsoid={ "modes": ["html2wt"], "suppressErrors": true }
 !! html/parsoid
 <p>He&amp;nbsp;llo <a href="Foo" rel="mw:WikiLink">He&amp;nbsp;llo</a></p>
 <p>He&amp;nbsp;llo <a href="He&amp;nbsp;llo" rel="mw:WikiLink">He&amp;nbsp;llo</a></p>
 !! wikitext
 He&amp;nbsp;llo [[Foo|He&amp;nbsp;llo]]
 
-He&amp;nbsp;llo [[He&amp;nbsp;llo]]
+He&amp;nbsp;llo He&amp;nbsp;llo
+!! html/php
+<p>He&amp;nbsp;llo <a href="/wiki/Foo" title="Foo">He&amp;nbsp;llo</a>
+</p><p>He&amp;nbsp;llo He&amp;nbsp;llo
+</p>
 !! end
 
+# html2wt will fail because of title normalization without data-parsoid
 !! test
 Parsoid: handle constructor well
+!! options
+parsoid=wt2html,wt2wt
 !! wikitext
 [[constructor]]
 
@@ -8536,9 +8539,9 @@ Parsoid: handle constructor well
 </p><p><a href="/index.php?title=Constructor:foo&amp;action=edit&amp;redlink=1" class="new" title="Constructor:foo (page does not exist)">constructor:foo</a>
 </p>
 !! html/parsoid
-<p><a rel="mw:WikiLink" href="./Constructor" title="Constructor" data-parsoid="{&quot;stx&quot;:&quot;simple&quot;,&quot;a&quot;:{&quot;href&quot;:&quot;./Constructor&quot;},&quot;sa&quot;:{&quot;href&quot;:&quot;constructor&quot;}}">constructor</a></p>
+<p><a rel="mw:WikiLink" href="./Constructor" title="Constructor" data-parsoid='{"stx":"simple","a":{"href":"./Constructor"},"sa":{"href":"constructor"}}'>constructor</a></p>
 
-<p><a rel="mw:WikiLink" href="./Foo" title="Foo" data-parsoid="{&quot;stx&quot;:&quot;simple&quot;,&quot;a&quot;:{&quot;href&quot;:&quot;./Foo&quot;},&quot;sa&quot;:{&quot;href&quot;:&quot;constructor:foo&quot;}}">constructor:foo</a></p>
+<p><a rel="mw:WikiLink" href="./Constructor:foo" title="Constructor:foo" data-parsoid='{"stx":"simple","a":{"href":"./Constructor:foo"},"sa":{"href":"constructor:foo"}}'>constructor:foo</a></p>
 !! end
 
 !! article
@@ -10140,7 +10143,7 @@ Parsoid: Page property magic word with magic word contents
 !! wikitext
 {{DISPLAYTITLE:''{{PAGENAME}}''}}
 !! html/parsoid
-<meta property="mw:PageProp/displaytitle" content="Main_Page" about="#mwt2" typeof="mw:ExpandedAttrs" data-parsoid='{"src":"{{DISPLAYTITLE:&#39;&#39;{{PAGENAME}}&#39;&#39;}}"}' data-mw='{"attribs":[[{"txt":"content"},{"html":"&lt;i data-parsoid=&#39;{\"dsr\":[15,31,2,2]}&#39;>&lt;span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=&#39;{\"pi\":[[]],\"dsr\":[17,29,null,null]}&#39; data-mw=&#39;{\"parts\":[{\"template\":{\"target\":{\"wt\":\"PAGENAME\",\"function\":\"pagename\"},\"params\":{},\"i\":0}}]}&#39;>Main_Page&lt;/span>&lt;/i>"}]]}'/>
+<meta property="mw:PageProp/displaytitle" content="Main Page" about="#mwt2" typeof="mw:ExpandedAttrs" data-parsoid='{"src":"{{DISPLAYTITLE:&#39;&#39;{{PAGENAME}}&#39;&#39;}}"}' data-mw='{"attribs":[[{"txt":"content"},{"html":"&lt;i data-parsoid=&#39;{\"dsr\":[15,31,2,2]}&#39;>&lt;span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=&#39;{\"pi\":[[]],\"dsr\":[17,29,null,null]}&#39; data-mw=&#39;{\"parts\":[{\"template\":{\"target\":{\"wt\":\"PAGENAME\",\"function\":\"pagename\"},\"params\":{},\"i\":0}}]}&#39;>Main Page&lt;/span>&lt;/i>"}]]}'/>
 !! end
 
 !! test
@@ -10970,7 +10973,7 @@ foo {{''}} baz
 <p>foo bar baz
 </p>
 !! html/parsoid
-<p>foo <span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"&#39;&#39;"},"params":{},"i":0}}]}'>bar</span> baz
+<p>foo <span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"&#39;&#39;","href":"./Template:&#39;&#39;"},"params":{},"i":0}}]}'>bar</span> baz
 </p>
 !! end
 
@@ -11444,6 +11447,33 @@ parsoid=wt2html
 </tbody></table>
 !!end
 
+!! test
+Table wikitext syntax outside wiki-tables
+!! wikitext
+a
+|+ not a caption
+! not a table heading
+|- not a table row
+| not a table cell
+| class="foo bar" | baz
+b
+|}
+|-
+c
+!! html
+<p>a
+|+ not a caption
+! not a table heading
+|- not a table row
+| not a table cell
+| class="foo bar" | baz
+b
+|}
+|-
+c
+</p>
+!! end
+
 ###
 ### Testing parsing of templates where a template arg
 ### has the same name as the template itself.
@@ -13955,6 +13985,17 @@ Escape HTML special chars in image alt text
 <p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"&amp; &lt; > \""}]}' data-mw='{"caption":"&amp;amp; &amp;lt; > \""}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
 !! end
 
+!! test
+Entities in file name and attributes
+!! wikitext
+[[File:7%25 solution.gif|manualthumb=7%25 solution.gif|link=7%25 solution|[[7%25 solution]]]]
+!! html/php
+<p><a href="/index.php?title=Special:Upload&amp;wpDestFile=7%25_solution.gif" class="new" title="File:7% solution.gif">7% solution</a>
+</p>
+!! html/parsoid
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-parsoid='{"optList":[{"ck":"bogus","ak":"manualthumb=7%25 solution.gif"},{"ck":"link","ak":"link=7%25 solution"},{"ck":"caption","ak":"[[7%25 solution]]"}]}' data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"&lt;a rel=\"mw:WikiLink\" href=\"./7%25_solution\" title=\"7% solution\" data-parsoid=&#39;{\"stx\":\"simple\",\"a\":{\"href\":\"./7%25_solution\"},\"sa\":{\"href\":\"7%25 solution\"},\"dsr\":[74,91,2,2]}&#39;>7% solution&lt;/a>"}'><a href="./7%25_solution" data-parsoid='{"a":{"href":"./7%25_solution"},"sa":{"href":"link=7%25 solution"}}'><img resource="./File:7%25_solution.gif" src="./Special:FilePath/7%25_solution.gif" height="220" width="220" data-parsoid='{"a":{"resource":"./File:7%25_solution.gif","height":"220","width":"220"},"sa":{"resource":"File:7%25 solution.gif"}}'/></a></span></p>
+!! end
+
 !! test
 BUG 499: Alt text should have &#1234;, not &amp;1234;
 !! wikitext
@@ -14920,6 +14961,14 @@ parsoid=wt2html
 <link rel="mw:PageProp/Category" href="./Category:Baz" data-parsoid='{"stx":"simple","a":{"href":"./Category:Baz"},"sa":{"href":"Category:Baz"}}'/>
 !! end
 
+!! test
+Category links with multiple namespaces
+!! wikitext
+[[Category:Project:Foo]]
+!! html/parsoid
+<link rel="mw:PageProp/Category" href="./Category:Project:Foo" />
+!! end
+
 !! test
 Parsoid: Serialize link to category page with colon escape
 !! options
@@ -19329,10 +19378,14 @@ subpage title=[[Subpage test/L1/L2]]
 </p>
 !! end
 
+# This is wt2html only in Parsoid because we add <nowiki>
+# because of {{..}} and we don't expect to fix that to
+# eliminate the nowikis selective for {{..}} markup.
 !! test
 Non-transclusion because of too many up levels
 !! options
 subpage title=[[Subpage test/L1/L2/L3]]
+parsoid=wt2html
 !! wikitext
 {{../../../../More than parent}}
 !! html
@@ -20036,10 +20089,14 @@ Nested: -{zh-hans:Hi -{zh-cn:China;zh-sg:Singapore;}-;zh-hant:Hello -{zh-tw:Taiw
 </p>
 !! end
 
+# Since Parsoid is starting to emit canonical wikitext for links,
+# [http://example.com http://example.com] will not RT back to that
+# form anymore.
 !! test
 Proper conversion of text in external links
 !! options
 language=sr variant=sr-ec
+parsoid=wt2html
 !! wikitext
 http://www.google.com
 gopher://www.google.com
@@ -20048,7 +20105,7 @@ gopher://www.google.com
 [https://www.google.com irc://www.google.com]
 [ftp://www.google.com www.google.com/ftp://dir]
 [//www.google.com www.google.com]
-!! html
+!! html/php
 <p><a rel="nofollow" class="external free" href="http://www.google.com">http://www.google.com</a>
 <a rel="nofollow" class="external free" href="gopher://www.google.com">gopher://www.google.com</a>
 <a rel="nofollow" class="external free" href="http://www.google.com">http://www.google.com</a>
@@ -20057,6 +20114,14 @@ gopher://www.google.com
 <a rel="nofollow" class="external text" href="ftp://www.google.com">www.гоогле.цом/фтп://дир</a>
 <a rel="nofollow" class="external text" href="//www.google.com">www.гоогле.цом</a>
 </p>
+!! html/parsoid
+<p><a rel="mw:ExtLink" href="http://www.google.com">http://www.google.com</a>
+<a rel="mw:ExtLink" href="gopher://www.google.com">gopher://www.google.com</a>
+<a rel="mw:ExtLink" href="http://www.google.com">http://www.google.com</a>
+<a rel="mw:ExtLink" href="gopher://www.google.com">gopher://www.google.com</a>
+<a rel="mw:ExtLink" href="https://www.google.com">irc://www.google.com</a>
+<a rel="mw:ExtLink" href="ftp://www.google.com">www.гоогле.цом/фтп://дир</a>
+<a rel="mw:ExtLink" href="//www.google.com">www.гоогле.цом</a></p>
 !! end
 
 !! test
@@ -24954,11 +25019,25 @@ Don't block XML namespace declaration
 
 # -----------------------------------------------------------------
 # The following section of tests are primarily to spec requirements
-# around serialization of new/edited content.
+# around Parsoid's serialization (old, new, edited content)
 #
 # All these tests are marked Parsoid html2wt and html2html only
 # ----------------------------------------------------------------
 
+!! test
+Ignore rel attribute in a-tags during serialization to url-links
+!! options
+parsoid=html2wt
+!! html/parsoid
+<a href='http://en.wikipedia.org/wiki/Foobar'>http://en.wikipedia.org/wiki/Foobar</a>
+<a href='http://en.wikipedia.org/wiki/Foobar' rel='mw:ExtLink'>http://en.wikipedia.org/wiki/Foobar</a>
+<a href='http://en.wikipedia.org/wiki/Foobar' rel='mw:WikiLink'>http://en.wikipedia.org/wiki/Foobar</a>
+!! wikitext
+http://en.wikipedia.org/wiki/Foobar
+http://en.wikipedia.org/wiki/Foobar
+http://en.wikipedia.org/wiki/Foobar
+!! end
+
 # 'mi' is a localinterwiki prefix as well as a language
 !! test
 Serialize interwiki links pointing to the current wiki as plain wiki links (bug 65869)
@@ -24978,9 +25057,15 @@ parsoid=html2wt
 !! html/parsoid
 <a rel="mw:WikiLink" href="./Foo" title="Foo" data-parsoid='{}'>Foo</a>
 <a rel="mw:WikiLink" href="./Foo" title="Foo">Foo</a>
+<a href="//en.wikipedia.org/wiki/Foo">//en.wikipedia.org/wiki/Foo</a>
+<a href="http://en.wikipedia.org/wiki/Foo">http://en.wikipedia.org/wiki/Foo</a>
+<a href="//en.wikipedia.org/wiki/Foo_bar">//en.wikipedia.org/wiki/Foo bar</a>
 !! wikitext
 [[Foo]]
 [[Foo]]
+[[:en:Foo|//en.wikipedia.org/wiki/Foo]]
+http://en.wikipedia.org/wiki/Foo
+[[:en:Foo_bar|//en.wikipedia.org/wiki/Foo bar]]
 !! end
 
 !! test
@@ -25291,6 +25376,17 @@ parsoid=html2wt
 [[File:Foobar.jpg|link=]]
 !! end
 
+!! test
+Image: Invalid title as link
+!! wikitext
+[[File:Foobar.jpg|link=<]]
+!! html/php
+<p><a href="/wiki/File:Foobar.jpg" class="image" title="link=&lt;"><img alt="link=&lt;" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
+</p>
+!! html/parsoid
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"link","ak":"link=&lt;"}]}' data-mw='{"caption":"link=&amp;lt;"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
+!! end
+
 !! test
 Lists: Serialize correctly even when list content is wrapped in p-tags (like VE does)
 !! options
index ac8c43b..8c2b143 100644 (file)
@@ -324,6 +324,7 @@ class MediaWikiServicesTest extends MediaWikiTestCase {
                        '_MediaWikiTitleCodec' => [ '_MediaWikiTitleCodec', MediaWikiTitleCodec::class ],
                        'TitleFormatter' => [ 'TitleFormatter', TitleFormatter::class ],
                        'TitleParser' => [ 'TitleParser', TitleParser::class ],
+                       'VirtualRESTServiceClient' => [ 'VirtualRESTServiceClient', VirtualRESTServiceClient::class ]
                ];
        }
 
index b4ae765..b290f8f 100644 (file)
@@ -459,4 +459,30 @@ class TextContentTest extends MediaWikiLangTestCase {
                        $this->assertEquals( $expectedNative, $converted->getNativeData() );
                }
        }
+
+       /**
+        * @covers TextContent::normalizeLineEndings
+        * @dataProvider provideNormalizeLineEndings
+        */
+       public function testNormalizeLineEndings( $input, $expected ) {
+               $this->assertEquals( $expected, TextContent::normalizeLineEndings( $input ) );
+       }
+
+       public static function provideNormalizeLineEndings() {
+               return [
+                       [
+                               "Foo\r\nbar",
+                               "Foo\nbar"
+                       ],
+                       [
+                               "Foo\rbar",
+                               "Foo\nbar"
+                       ],
+                       [
+                               "Foobar\n  ",
+                               "Foobar"
+                       ]
+               ];
+       }
+
 }
index 7fe8055..a01cc6b 100644 (file)
@@ -5,6 +5,10 @@
  */
 class CachedBagOStuffTest extends PHPUnit_Framework_TestCase {
 
+       /**
+        * @covers CachedBagOStuff::__construct
+        * @covers CachedBagOStuff::doGet
+        */
        public function testGetFromBackend() {
                $backend = new HashBagOStuff;
                $cache = new CachedBagOStuff( $backend );
@@ -16,6 +20,10 @@ class CachedBagOStuffTest extends PHPUnit_Framework_TestCase {
                $this->assertEquals( 'bar', $cache->get( 'foo' ), 'cached' );
        }
 
+       /**
+        * @covers CachedBagOStuff::set
+        * @covers CachedBagOStuff::delete
+        */
        public function testSetAndDelete() {
                $backend = new HashBagOStuff;
                $cache = new CachedBagOStuff( $backend );
@@ -30,6 +38,10 @@ class CachedBagOStuffTest extends PHPUnit_Framework_TestCase {
                }
        }
 
+       /**
+        * @covers CachedBagOStuff::set
+        * @covers CachedBagOStuff::delete
+        */
        public function testWriteCacheOnly() {
                $backend = new HashBagOStuff;
                $cache = new CachedBagOStuff( $backend );
@@ -50,6 +62,9 @@ class CachedBagOStuffTest extends PHPUnit_Framework_TestCase {
                $this->assertEquals( 'old', $cache->get( 'foo' ) ); // Reloaded from backend
        }
 
+       /**
+        * @covers CachedBagOStuff::doGet
+        */
        public function testCacheBackendMisses() {
                $backend = new HashBagOStuff;
                $cache = new CachedBagOStuff( $backend );
index fce09ae..c4db0cf 100644 (file)
@@ -5,6 +5,9 @@
  */
 class HashBagOStuffTest extends PHPUnit_Framework_TestCase {
 
+       /**
+        * @covers HashBagOStuff::delete
+        */
        public function testDelete() {
                $cache = new HashBagOStuff();
                for ( $i = 0; $i < 10; $i++ ) {
@@ -15,6 +18,9 @@ class HashBagOStuffTest extends PHPUnit_Framework_TestCase {
                }
        }
 
+       /**
+        * @covers HashBagOStuff::clear
+        */
        public function testClear() {
                $cache = new HashBagOStuff();
                for ( $i = 0; $i < 10; $i++ ) {
@@ -27,6 +33,10 @@ class HashBagOStuffTest extends PHPUnit_Framework_TestCase {
                }
        }
 
+       /**
+        * @covers HashBagOStuff::doGet
+        * @covers HashBagOStuff::expire
+        */
        public function testExpire() {
                $cache = new HashBagOStuff();
                $cacheInternal = TestingAccessWrapper::newFromObject( $cache );
@@ -45,6 +55,9 @@ class HashBagOStuffTest extends PHPUnit_Framework_TestCase {
 
        /**
         * Ensure maxKeys eviction prefers keeping new keys.
+        *
+        * @covers HashBagOStuff::__construct
+        * @covers HashBagOStuff::set
         */
        public function testEvictionAdd() {
                $cache = new HashBagOStuff( [ 'maxKeys' => 10 ] );
@@ -62,6 +75,9 @@ class HashBagOStuffTest extends PHPUnit_Framework_TestCase {
        /**
         * Ensure maxKeys eviction prefers recently set keys
         * even if the keys pre-exist.
+        *
+        * @covers HashBagOStuff::__construct
+        * @covers HashBagOStuff::set
         */
        public function testEvictionSet() {
                $cache = new HashBagOStuff( [ 'maxKeys' => 3 ] );
@@ -85,6 +101,10 @@ class HashBagOStuffTest extends PHPUnit_Framework_TestCase {
 
        /**
         * Ensure maxKeys eviction prefers recently retrieved keys (LRU).
+        *
+        * @covers HashBagOStuff::__construct
+        * @covers HashBagOStuff::doGet
+        * @covers HashBagOStuff::hasKey
         */
        public function testEvictionGet() {
                $cache = new HashBagOStuff( [ 'maxKeys' => 3 ] );
index 6df74d6..38d63e3 100644 (file)
@@ -23,6 +23,10 @@ class MultiWriteBagOStuffTest extends MediaWikiTestCase {
                ] );
        }
 
+       /**
+        * @covers MultiWriteBagOStuff::set
+        * @covers MultiWriteBagOStuff::doWrite
+        */
        public function testSetImmediate() {
                $key = wfRandomString();
                $value = wfRandomString();
@@ -34,6 +38,9 @@ class MultiWriteBagOStuffTest extends MediaWikiTestCase {
                $this->assertEquals( $value, $this->cache2->get( $key ), 'Written to tier 2' );
        }
 
+       /**
+        * @covers MultiWriteBagOStuff
+        */
        public function testSyncMerge() {
                $key = wfRandomString();
                $value = wfRandomString();
@@ -69,6 +76,9 @@ class MultiWriteBagOStuffTest extends MediaWikiTestCase {
                $dbw->commit();
        }
 
+       /**
+        * @covers MultiWriteBagOStuff::set
+        */
        public function testSetDelayed() {
                $key = wfRandomString();
                $value = wfRandomString();
index 275c0d1..711eab6 100644 (file)
@@ -74,11 +74,9 @@ class ExtensionJsonValidationTest extends PHPUnit_Framework_TestCase {
                        $version <= ExtensionRegistry::MANIFEST_VERSION,
                        "$path is using a non-supported schema version"
                );
-               $retriever = new JsonSchema\Uri\UriRetriever();
-               $schema = $retriever->retrieve( 'file://' . $schemaPath );
 
-               $validator = new JsonSchema\Validator();
-               $validator->check( $data, $schema );
+               $validator = new JsonSchema\Validator;
+               $validator->check( $data, (object) [ '$ref' => 'file://' . $schemaPath ] );
                if ( $validator->isValid() ) {
                        // All good.
                        $this->assertTrue( true );