Merge "Avoid TransactionProfiler notices for TEMPORARY table writes"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 20 Sep 2016 22:45:17 +0000 (22:45 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 20 Sep 2016 22:45:17 +0000 (22:45 +0000)
57 files changed:
RELEASE-NOTES-1.28
includes/MediaWiki.php
includes/OutputPage.php
includes/Title.php
includes/actions/HistoryAction.php
includes/api/ApiBase.php
includes/api/ApiFormatBase.php
includes/api/ApiFormatJson.php
includes/api/ApiMain.php
includes/api/ApiQuery.php
includes/api/ApiResult.php
includes/api/SearchApi.php
includes/cache/FileCacheBase.php
includes/cache/HTMLFileCache.php
includes/changetags/ChangeTags.php
includes/import/WikiRevision.php
includes/installer/SqliteInstaller.php
includes/installer/i18n/bg.json
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/database/DatabaseMysqlBase.php
includes/libs/rdbms/database/DatabasePostgres.php
includes/libs/rdbms/database/DatabaseSqlite.php
includes/libs/rdbms/lbfactory/LBFactory.php
includes/libs/rdbms/lbfactory/LBFactoryMulti.php
includes/libs/rdbms/lbfactory/LBFactorySimple.php
includes/libs/rdbms/loadbalancer/ILoadBalancer.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/page/Article.php
includes/page/WikiPage.php
includes/search/SearchEngine.php
includes/skins/SkinTemplate.php
languages/i18n/ast.json
languages/i18n/be-tarask.json
languages/i18n/be.json
languages/i18n/bs.json
languages/i18n/cdo.json
languages/i18n/diq.json
languages/i18n/dty.json
languages/i18n/egl.json
languages/i18n/en.json
languages/i18n/eo.json
languages/i18n/he.json
languages/i18n/mk.json
languages/i18n/my.json
languages/i18n/qqq.json
languages/i18n/ru.json
languages/i18n/ur.json
maintenance/rebuildFileCache.php
resources/src/mediawiki.less/mediawiki.ui/mixins.less
resources/src/mediawiki.less/mediawiki.ui/variables.less
resources/src/mediawiki.special/mediawiki.special.userlogin.login.css
resources/src/mediawiki.widgets.datetime/mediawiki.widgets.datetime.definitions.less
resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.less
resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.less
resources/src/mediawiki/mediawiki.Upload.BookletLayout.css
tests/phpunit/includes/api/ApiOpenSearchTest.php
tests/phpunit/includes/api/ApiResultTest.php

index c3a91c4..fd6c613 100644 (file)
@@ -26,7 +26,7 @@ production.
   https://www.mediawiki.org/beacon with basic information about the local
   MediaWiki installation. This data includes, for example, the type of system,
   PHP version, and chosen database backend. This behavior is off by default.
-* When $EditSubmitButtonLabelPublish is true, MediaWiki will label the button
+* When $wgEditSubmitButtonLabelPublish is true, MediaWiki will label the button
   to store-to-database-and-show-to-others as "Publish page"/"Publish changes";
   if false, the default, they will be "Save page"/"Save changes".
 * The 'editcontentmodel' permission is now granted to all logged-in users ('user').
@@ -114,6 +114,36 @@ production.
   interact with ApiParse and ApiExpandTemplates.
 * (T139565) SECURITY: API: Generate head items in the context of the given title
 * (T115333) SECURITY: Check read permission when loading page content in ApiParse
+* ApiBase::makeHelpArrayToString() was removed (deprecated since 1.25)
+* ApiBase::makeHelpMsgParameters() was removed (deprecated since 1.25)
+* ApiBase::makeHelpMsg() was removed (deprecated since 1.25)
+* ApiFormatBase::formatHTML() was removed (deprecated since 1.25)
+* ApiFormatBase::getNeedsRawData() was removed (deprecated since 1.25)
+* ApiFormatBase::getWantsHelp() was removed (deprecated since 1.25)
+* ApiFormatBase::setBufferResult() was removed (deprecated since 1.25)
+* ApiFormatBase::setHelp() was removed (deprecated since 1.25)
+* ApiFormatBase::setUnescapeAmps() was removed (deprecated since 1.25)
+* ApiMain::makeHelpMsgHeader() was removed (deprecated since 1.25)
+* ApiMain::reallyMakeHelpMsg() was removed (deprecated since 1.25)
+* ApiMain::setHelp() was removed (deprecated since 1.25)
+* ApiResult::beginContinuation() was removed (deprecated since 1.25)
+* ApiResult::cleanUpUTF8() was removed (deprecated since 1.25)
+* ApiResult::convertStatusToArray() was removed (deprecated since 1.25)
+* ApiResult::disableSizeCheck() was removed (deprecated since 1.24)
+* ApiResult::enableSizeCheck() was removed (deprecated since 1.24)
+* ApiResult::endContinuation() was removed (deprecated since 1.25)
+* ApiResult::getData() was removed (deprecated since 1.25)
+* ApiResult::getIsRawMode() was removed (deprecated since 1.25)
+* ApiResult::setContent() was removed (deprecated since 1.25)
+* ApiResult::setContinueParam() was removed (deprecated since 1.25)
+* ApiResult::setElement() was removed (deprecated since 1.25)
+* ApiResult::setGeneratorContinueParam() was removed (deprecated since 1.25)
+* ApiResult::setIndexedTagName_internal() was removed (deprecated since 1.25)
+* ApiResult::setIndexedTagName_recursive() was removed (deprecated since 1.25)
+* ApiResult::setMainForContinuation() was removed (deprecated since 1.25)
+* ApiResult::setParsedLimit() was removed (deprecated since 1.25)
+* ApiResult::setRawMode() was removed (deprecated since 1.25)
+* ApiResult::size() was removed (deprecated since 1.25)
 
 === Languages updated in 1.28 ===
 
index 2fce08c..8cf009f 100644 (file)
@@ -529,11 +529,12 @@ class MediaWiki {
                        }
                } catch ( Exception $e ) {
                        $context = $this->context;
+                       $action = $context->getRequest()->getVal( 'action', 'view' );
                        if (
                                $e instanceof DBConnectionError &&
                                $context->hasTitle() &&
                                $context->getTitle()->canExist() &&
-                               $context->getRequest()->getVal( 'action', 'view' ) === 'view' &&
+                               in_array( $action, [ 'view', 'history' ], true ) &&
                                HTMLFileCache::useFileCache( $this->context, HTMLFileCache::MODE_OUTAGE )
                        ) {
                                // Try to use any (even stale) file during outages...
index ba14b99..c57e219 100644 (file)
@@ -67,13 +67,6 @@ class OutputPage extends ContextSource {
         */
        public $mBodytext = '';
 
-       /**
-        * Holds the debug lines that will be output as comments in page source if
-        * $wgDebugComments is enabled. See also $wgShowDebug.
-        * @deprecated since 1.20; use MWDebug class instead.
-        */
-       public $mDebugtext = '';
-
        /** @var string Stores contents of "<title>" tag */
        private $mHTMLtitle = '';
 
index 6d9ddd6..27a334d 100644 (file)
@@ -1079,7 +1079,7 @@ class Title implements LinkTarget {
        /**
         * Returns true if the title is inside one of the specified namespaces.
         *
-        * @param int $namespaces,... The namespaces to check for
+        * @param int|int[] $namespaces,... The namespaces to check for
         * @return bool
         * @since 1.19
         */
index 41378fb..f3ef3b3 100644 (file)
@@ -105,8 +105,7 @@ class HistoryAction extends FormlessAction {
                $config = $this->context->getConfig();
 
                # Fill in the file cache if not set already
-               $useFileCache = $config->get( 'UseFileCache' );
-               if ( $useFileCache && HTMLFileCache::useFileCache( $this->getContext() ) ) {
+               if ( HTMLFileCache::useFileCache( $this->getContext() ) ) {
                        $cache = new HTMLFileCache( $this->getTitle(), 'history' );
                        if ( !$cache->isCacheGood( /* Assume up to date */ ) ) {
                                ob_start( [ &$cache, 'saveToFileCache' ] );
index f763e45..809d567 100644 (file)
@@ -2680,275 +2680,6 @@ abstract class ApiBase extends ContextSource {
                return false;
        }
 
-       /**
-        * Generates help message for this module, or false if there is no description
-        * @deprecated since 1.25
-        * @return string|bool
-        */
-       public function makeHelpMsg() {
-               wfDeprecated( __METHOD__, '1.25' );
-               static $lnPrfx = "\n  ";
-
-               $msg = $this->getFinalDescription();
-
-               if ( $msg !== false ) {
-
-                       if ( !is_array( $msg ) ) {
-                               $msg = [
-                                       $msg
-                               ];
-                       }
-                       $msg = $lnPrfx . implode( $lnPrfx, $msg ) . "\n";
-
-                       $msg .= $this->makeHelpArrayToString( $lnPrfx, false, $this->getHelpUrls() );
-
-                       if ( $this->isReadMode() ) {
-                               $msg .= "\nThis module requires read rights";
-                       }
-                       if ( $this->isWriteMode() ) {
-                               $msg .= "\nThis module requires write rights";
-                       }
-                       if ( $this->mustBePosted() ) {
-                               $msg .= "\nThis module only accepts POST requests";
-                       }
-                       if ( $this->isReadMode() || $this->isWriteMode() ||
-                               $this->mustBePosted()
-                       ) {
-                               $msg .= "\n";
-                       }
-
-                       // Parameters
-                       $paramsMsg = $this->makeHelpMsgParameters();
-                       if ( $paramsMsg !== false ) {
-                               $msg .= "Parameters:\n$paramsMsg";
-                       }
-
-                       $examples = $this->getExamples();
-                       if ( $examples ) {
-                               if ( !is_array( $examples ) ) {
-                                       $examples = [
-                                               $examples
-                                       ];
-                               }
-                               $msg .= 'Example' . ( count( $examples ) > 1 ? 's' : '' ) . ":\n";
-                               foreach ( $examples as $k => $v ) {
-                                       if ( is_numeric( $k ) ) {
-                                               $msg .= "  $v\n";
-                                       } else {
-                                               if ( is_array( $v ) ) {
-                                                       $msgExample = implode( "\n", array_map( [ $this, 'indentExampleText' ], $v ) );
-                                               } else {
-                                                       $msgExample = "  $v";
-                                               }
-                                               $msgExample .= ':';
-                                               $msg .= wordwrap( $msgExample, 100, "\n" ) . "\n    $k\n";
-                                       }
-                               }
-                       }
-               }
-
-               return $msg;
-       }
-
-       /**
-        * @deprecated since 1.25
-        * @param string $item
-        * @return string
-        */
-       private function indentExampleText( $item ) {
-               return '  ' . $item;
-       }
-
-       /**
-        * @deprecated since 1.25
-        * @param string $prefix Text to split output items
-        * @param string $title What is being output
-        * @param string|array $input
-        * @return string
-        */
-       protected function makeHelpArrayToString( $prefix, $title, $input ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               if ( $input === false ) {
-                       return '';
-               }
-               if ( !is_array( $input ) ) {
-                       $input = [ $input ];
-               }
-
-               if ( count( $input ) > 0 ) {
-                       if ( $title ) {
-                               $msg = $title . ( count( $input ) > 1 ? 's' : '' ) . ":\n  ";
-                       } else {
-                               $msg = '  ';
-                       }
-                       $msg .= implode( $prefix, $input ) . "\n";
-
-                       return $msg;
-               }
-
-               return '';
-       }
-
-       /**
-        * Generates the parameter descriptions for this module, to be displayed in the
-        * module's help.
-        * @deprecated since 1.25
-        * @return string|bool
-        */
-       public function makeHelpMsgParameters() {
-               wfDeprecated( __METHOD__, '1.25' );
-               $params = $this->getFinalParams( ApiBase::GET_VALUES_FOR_HELP );
-               if ( $params ) {
-                       $paramsDescription = $this->getFinalParamDescription();
-                       $msg = '';
-                       $paramPrefix = "\n" . str_repeat( ' ', 24 );
-                       $descWordwrap = "\n" . str_repeat( ' ', 28 );
-                       foreach ( $params as $paramName => $paramSettings ) {
-                               $desc = isset( $paramsDescription[$paramName] ) ? $paramsDescription[$paramName] : '';
-                               if ( is_array( $desc ) ) {
-                                       $desc = implode( $paramPrefix, $desc );
-                               }
-
-                               // handle shorthand
-                               if ( !is_array( $paramSettings ) ) {
-                                       $paramSettings = [
-                                               self::PARAM_DFLT => $paramSettings,
-                                       ];
-                               }
-
-                               // handle missing type
-                               if ( !isset( $paramSettings[ApiBase::PARAM_TYPE] ) ) {
-                                       $dflt = isset( $paramSettings[ApiBase::PARAM_DFLT] )
-                                               ? $paramSettings[ApiBase::PARAM_DFLT]
-                                               : null;
-                                       if ( is_bool( $dflt ) ) {
-                                               $paramSettings[ApiBase::PARAM_TYPE] = 'boolean';
-                                       } elseif ( is_string( $dflt ) || is_null( $dflt ) ) {
-                                               $paramSettings[ApiBase::PARAM_TYPE] = 'string';
-                                       } elseif ( is_int( $dflt ) ) {
-                                               $paramSettings[ApiBase::PARAM_TYPE] = 'integer';
-                                       }
-                               }
-
-                               if ( isset( $paramSettings[self::PARAM_DEPRECATED] )
-                                       && $paramSettings[self::PARAM_DEPRECATED]
-                               ) {
-                                       $desc = "DEPRECATED! $desc";
-                               }
-
-                               if ( isset( $paramSettings[self::PARAM_REQUIRED] )
-                                       && $paramSettings[self::PARAM_REQUIRED]
-                               ) {
-                                       $desc .= $paramPrefix . 'This parameter is required';
-                               }
-
-                               $type = isset( $paramSettings[self::PARAM_TYPE] )
-                                       ? $paramSettings[self::PARAM_TYPE]
-                                       : null;
-                               if ( isset( $type ) ) {
-                                       $hintPipeSeparated = true;
-                                       $multi = isset( $paramSettings[self::PARAM_ISMULTI] )
-                                               ? $paramSettings[self::PARAM_ISMULTI]
-                                               : false;
-                                       if ( $multi ) {
-                                               $prompt = 'Values (separate with \'|\'): ';
-                                       } else {
-                                               $prompt = 'One value: ';
-                                       }
-
-                                       if ( $type === 'submodule' ) {
-                                               if ( isset( $paramSettings[self::PARAM_SUBMODULE_MAP] ) ) {
-                                                       $type = array_keys( $paramSettings[self::PARAM_SUBMODULE_MAP] );
-                                               } else {
-                                                       $type = $this->getModuleManager()->getNames( $paramName );
-                                               }
-                                               sort( $type );
-                                       }
-                                       if ( is_array( $type ) ) {
-                                               $choices = [];
-                                               $nothingPrompt = '';
-                                               foreach ( $type as $t ) {
-                                                       if ( $t === '' ) {
-                                                               $nothingPrompt = 'Can be empty, or ';
-                                                       } else {
-                                                               $choices[] = $t;
-                                                       }
-                                               }
-                                               $desc .= $paramPrefix . $nothingPrompt . $prompt;
-                                               $choicesstring = implode( ', ', $choices );
-                                               $desc .= wordwrap( $choicesstring, 100, $descWordwrap );
-                                               $hintPipeSeparated = false;
-                                       } else {
-                                               switch ( $type ) {
-                                                       case 'namespace':
-                                                               // Special handling because namespaces are
-                                                               // type-limited, yet they are not given
-                                                               $desc .= $paramPrefix . $prompt;
-                                                               $desc .= wordwrap( implode( ', ', MWNamespace::getValidNamespaces() ),
-                                                                       100, $descWordwrap );
-                                                               $hintPipeSeparated = false;
-                                                               break;
-                                                       case 'limit':
-                                                               $desc .= $paramPrefix . "No more than {$paramSettings[self::PARAM_MAX]}";
-                                                               if ( isset( $paramSettings[self::PARAM_MAX2] ) ) {
-                                                                       $desc .= " ({$paramSettings[self::PARAM_MAX2]} for bots)";
-                                                               }
-                                                               $desc .= ' allowed';
-                                                               break;
-                                                       case 'integer':
-                                                               $s = $multi ? 's' : '';
-                                                               $hasMin = isset( $paramSettings[self::PARAM_MIN] );
-                                                               $hasMax = isset( $paramSettings[self::PARAM_MAX] );
-                                                               if ( $hasMin || $hasMax ) {
-                                                                       if ( !$hasMax ) {
-                                                                               $intRangeStr = "The value$s must be no less than " .
-                                                                                       "{$paramSettings[self::PARAM_MIN]}";
-                                                                       } elseif ( !$hasMin ) {
-                                                                               $intRangeStr = "The value$s must be no more than " .
-                                                                                       "{$paramSettings[self::PARAM_MAX]}";
-                                                                       } else {
-                                                                               $intRangeStr = "The value$s must be between " .
-                                                                                       "{$paramSettings[self::PARAM_MIN]} and {$paramSettings[self::PARAM_MAX]}";
-                                                                       }
-
-                                                                       $desc .= $paramPrefix . $intRangeStr;
-                                                               }
-                                                               break;
-                                                       case 'upload':
-                                                               $desc .= $paramPrefix . 'Must be posted as a file upload using multipart/form-data';
-                                                               break;
-                                               }
-                                       }
-
-                                       if ( $multi ) {
-                                               if ( $hintPipeSeparated ) {
-                                                       $desc .= $paramPrefix . "Separate values with '|'";
-                                               }
-
-                                               $isArray = is_array( $type );
-                                               if ( !$isArray
-                                                       || $isArray && count( $type ) > self::LIMIT_SML1
-                                               ) {
-                                                       $desc .= $paramPrefix . 'Maximum number of values ' .
-                                                               self::LIMIT_SML1 . ' (' . self::LIMIT_SML2 . ' for bots)';
-                                               }
-                                       }
-                               }
-
-                               $default = isset( $paramSettings[self::PARAM_DFLT] ) ? $paramSettings[self::PARAM_DFLT] : null;
-                               if ( !is_null( $default ) && $default !== false ) {
-                                       $desc .= $paramPrefix . "Default: $default";
-                               }
-
-                               $msg .= sprintf( "  %-19s - %s\n", $this->encodeParamName( $paramName ), $desc );
-                       }
-
-                       return $msg;
-               }
-
-               return false;
-       }
-
        /**
         * @deprecated since 1.25, always returns empty string
         * @param IDatabase|bool $db
index c826bba..5011f48 100644 (file)
@@ -300,144 +300,6 @@ abstract class ApiFormatBase extends ApiBase {
                return 'https://www.mediawiki.org/wiki/API:Data_formats';
        }
 
-       /************************************************************************//**
-        * @name   Deprecated
-        * @{
-        */
-
-       /**
-        * Specify whether or not sequences like &amp;quot; should be unescaped
-        * to &quot; . This should only be set to true for the help message
-        * when rendered in the default (xmlfm) format. This is a temporary
-        * special-case fix that should be removed once the help has been
-        * reworked to use a fully HTML interface.
-        *
-        * @deprecated since 1.25
-        * @param bool $b Whether or not ampersands should be escaped.
-        */
-       public function setUnescapeAmps( $b ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               $this->mUnescapeAmps = $b;
-       }
-
-       /**
-        * Whether this formatter can format the help message in a nice way.
-        * By default, this returns the same as getIsHtml().
-        * When action=help is set explicitly, the help will always be shown
-        * @deprecated since 1.25
-        * @return bool
-        */
-       public function getWantsHelp() {
-               wfDeprecated( __METHOD__, '1.25' );
-               return $this->getIsHtml();
-       }
-
-       /**
-        * Sets whether the pretty-printer should format *bold*
-        * @deprecated since 1.25
-        * @param bool $help
-        */
-       public function setHelp( $help = true ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               $this->mHelp = $help;
-       }
-
-       /**
-        * Pretty-print various elements in HTML format, such as xml tags and
-        * URLs. This method also escapes characters like <
-        * @deprecated since 1.25
-        * @param string $text
-        * @return string
-        */
-       protected function formatHTML( $text ) {
-               wfDeprecated( __METHOD__, '1.25' );
-
-               // Escape everything first for full coverage
-               $text = htmlspecialchars( $text );
-
-               if ( $this->mFormat === 'XML' ) {
-                       // encode all comments or tags as safe blue strings
-                       $text = str_replace( '&lt;', '<span style="color:blue;">&lt;', $text );
-                       $text = str_replace( '&gt;', '&gt;</span>', $text );
-               }
-
-               // identify requests to api.php
-               $text = preg_replace( '#^(\s*)(api\.php\?[^ <\n\t]+)$#m', '\1<a href="\2">\2</a>', $text );
-               if ( $this->mHelp ) {
-                       // make lines inside * bold
-                       $text = preg_replace( '#^(\s*)(\*[^<>\n]+\*)(\s*)$#m', '$1<b>$2</b>$3', $text );
-               }
-
-               // Armor links (bug 61362)
-               $masked = [];
-               $text = preg_replace_callback( '#<a .*?</a>#', function ( $matches ) use ( &$masked ) {
-                       $sha = sha1( $matches[0] );
-                       $masked[$sha] = $matches[0];
-                       return "<$sha>";
-               }, $text );
-
-               // identify URLs
-               $protos = wfUrlProtocolsWithoutProtRel();
-               // This regex hacks around bug 13218 (&quot; included in the URL)
-               $text = preg_replace(
-                       "#(((?i)$protos).*?)(&quot;)?([ \\'\"<>\n]|&lt;|&gt;|&quot;)#",
-                       '<a href="\\1">\\1</a>\\3\\4',
-                       $text
-               );
-
-               // Unarmor links
-               $text = preg_replace_callback( '#<([0-9a-f]{40})>#', function ( $matches ) use ( &$masked ) {
-                       $sha = $matches[1];
-                       return isset( $masked[$sha] ) ? $masked[$sha] : $matches[0];
-               }, $text );
-
-               /**
-                * Temporary fix for bad links in help messages. As a special case,
-                * XML-escaped metachars are de-escaped one level in the help message
-                * for legibility. Should be removed once we have completed a fully-HTML
-                * version of the help message.
-                */
-               if ( $this->mUnescapeAmps ) {
-                       $text = preg_replace( '/&amp;(amp|quot|lt|gt);/', '&\1;', $text );
-               }
-
-               return $text;
-       }
-
-       /**
-        * @see ApiBase::getDescription
-        * @deprecated since 1.25
-        */
-       public function getDescription() {
-               return $this->getIsHtml() ? ' (pretty-print in HTML)' : '';
-       }
-
-       /**
-        * Set the flag to buffer the result instead of printing it.
-        * @deprecated since 1.25, output is always buffered
-        * @param bool $value
-        */
-       public function setBufferResult( $value ) {
-       }
-
-       /**
-        * Formerly indicated whether the formatter needed metadata from ApiResult.
-        *
-        * ApiResult previously (indirectly) used this to decide whether to add
-        * metadata or to ignore calls to metadata-setting methods, which
-        * unfortunately made several methods that should have been static have to
-        * be dynamic instead. Now ApiResult always stores metadata and formatters
-        * are required to ignore it or filter it out.
-        *
-        * @deprecated since 1.25
-        * @return bool Always true
-        */
-       public function getNeedsRawData() {
-               wfDeprecated( __METHOD__, '1.25' );
-               return true;
-       }
-
-       /**@}*/
 }
 
 /**
index 814450e..2e917e1 100644 (file)
@@ -56,15 +56,6 @@ class ApiFormatJson extends ApiFormatBase {
                return 'application/json';
        }
 
-       /**
-        * @deprecated since 1.25
-        */
-       public function getWantsHelp() {
-               wfDeprecated( __METHOD__, '1.25' );
-               // Help is always ugly in JSON
-               return false;
-       }
-
        public function execute() {
                $params = $this->extractRequestParams();
 
index ae3f3f2..8d5af59 100644 (file)
@@ -258,7 +258,6 @@ class ApiMain extends ApiBase {
                $this->mResult = new ApiResult( $this->getConfig()->get( 'APIMaxResultSize' ) );
                $this->mErrorFormatter = new ApiErrorFormatter_BackCompat( $this->mResult );
                $this->mResult->setErrorFormatter( $this->mErrorFormatter );
-               $this->mResult->setMainForContinuation( $this );
                $this->mContinuationManager = null;
                $this->mEnableWrite = $enableWrite;
 
@@ -1816,119 +1815,6 @@ class ApiMain extends ApiBase {
                        $this->getRequest()->getHeader( 'User-agent' )
                );
        }
-
-       /************************************************************************//**
-        * @name   Deprecated
-        * @{
-        */
-
-       /**
-        * Sets whether the pretty-printer should format *bold* and $italics$
-        *
-        * @deprecated since 1.25
-        * @param bool $help
-        */
-       public function setHelp( $help = true ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               $this->mPrinter->setHelp( $help );
-       }
-
-       /**
-        * Override the parent to generate help messages for all available modules.
-        *
-        * @deprecated since 1.25
-        * @return string
-        */
-       public function makeHelpMsg() {
-               wfDeprecated( __METHOD__, '1.25' );
-
-               $this->setHelp();
-               $cacheHelpTimeout = $this->getConfig()->get( 'APICacheHelpTimeout' );
-
-               return ObjectCache::getMainWANInstance()->getWithSetCallback(
-                       wfMemcKey(
-                               'apihelp',
-                               $this->getModuleName(),
-                               str_replace( ' ', '_', SpecialVersion::getVersion( 'nodb' ) )
-                       ),
-                       $cacheHelpTimeout > 0 ? $cacheHelpTimeout : WANObjectCache::TTL_UNCACHEABLE,
-                       [ $this, 'reallyMakeHelpMsg' ]
-               );
-       }
-
-       /**
-        * @deprecated since 1.25
-        * @return mixed|string
-        */
-       public function reallyMakeHelpMsg() {
-               wfDeprecated( __METHOD__, '1.25' );
-               $this->setHelp();
-
-               // Use parent to make default message for the main module
-               $msg = parent::makeHelpMsg();
-
-               $asterisks = str_repeat( '*** ', 14 );
-               $msg .= "\n\n$asterisks Modules  $asterisks\n\n";
-
-               foreach ( $this->mModuleMgr->getNames( 'action' ) as $name ) {
-                       $module = $this->mModuleMgr->getModule( $name );
-                       $msg .= self::makeHelpMsgHeader( $module, 'action' );
-
-                       $msg2 = $module->makeHelpMsg();
-                       if ( $msg2 !== false ) {
-                               $msg .= $msg2;
-                       }
-                       $msg .= "\n";
-               }
-
-               $msg .= "\n$asterisks Permissions $asterisks\n\n";
-               foreach ( self::$mRights as $right => $rightMsg ) {
-                       $rightsMsg = $this->msg( $rightMsg['msg'], $rightMsg['params'] )
-                               ->useDatabase( false )
-                               ->inLanguage( 'en' )
-                               ->text();
-                       $groups = User::getGroupsWithPermission( $right );
-                       $msg .= '* ' . $right . " *\n  $rightsMsg" .
-                               "\nGranted to:\n  " . str_replace( '*', 'all', implode( ', ', $groups ) ) . "\n\n";
-               }
-
-               $msg .= "\n$asterisks Formats  $asterisks\n\n";
-               foreach ( $this->mModuleMgr->getNames( 'format' ) as $name ) {
-                       $module = $this->mModuleMgr->getModule( $name );
-                       $msg .= self::makeHelpMsgHeader( $module, 'format' );
-                       $msg2 = $module->makeHelpMsg();
-                       if ( $msg2 !== false ) {
-                               $msg .= $msg2;
-                       }
-                       $msg .= "\n";
-               }
-
-               $credits = $this->msg( 'api-credits' )->useDatabase( 'false' )->inLanguage( 'en' )->text();
-               $credits = str_replace( "\n", "\n   ", $credits );
-               $msg .= "\n*** Credits: ***\n   $credits\n";
-
-               return $msg;
-       }
-
-       /**
-        * @deprecated since 1.25
-        * @param ApiBase $module
-        * @param string $paramName What type of request is this? e.g. action,
-        *    query, list, prop, meta, format
-        * @return string
-        */
-       public static function makeHelpMsgHeader( $module, $paramName ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               $modulePrefix = $module->getModulePrefix();
-               if ( strval( $modulePrefix ) !== '' ) {
-                       $modulePrefix = "($modulePrefix) ";
-               }
-
-               return "* $paramName={$module->getModuleName()} $modulePrefix*";
-       }
-
-       /**@}*/
-
 }
 
 /**
index 5eb86ab..5e3c709 100644 (file)
@@ -495,61 +495,6 @@ class ApiQuery extends ApiBase {
                return $result;
        }
 
-       /**
-        * Override the parent to generate help messages for all available query modules.
-        * @deprecated since 1.25
-        * @return string
-        */
-       public function makeHelpMsg() {
-               wfDeprecated( __METHOD__, '1.25' );
-
-               // Use parent to make default message for the query module
-               $msg = parent::makeHelpMsg();
-
-               $querySeparator = str_repeat( '--- ', 12 );
-               $moduleSeparator = str_repeat( '*** ', 14 );
-               $msg .= "\n$querySeparator Query: Prop  $querySeparator\n\n";
-               $msg .= $this->makeHelpMsgHelper( 'prop' );
-               $msg .= "\n$querySeparator Query: List  $querySeparator\n\n";
-               $msg .= $this->makeHelpMsgHelper( 'list' );
-               $msg .= "\n$querySeparator Query: Meta  $querySeparator\n\n";
-               $msg .= $this->makeHelpMsgHelper( 'meta' );
-               $msg .= "\n\n$moduleSeparator Modules: continuation  $moduleSeparator\n\n";
-
-               return $msg;
-       }
-
-       /**
-        * For all modules of a given group, generate help messages and join them together
-        * @deprecated since 1.25
-        * @param string $group Module group
-        * @return string
-        */
-       private function makeHelpMsgHelper( $group ) {
-               $moduleDescriptions = [];
-
-               $moduleNames = $this->mModuleMgr->getNames( $group );
-               sort( $moduleNames );
-               foreach ( $moduleNames as $name ) {
-                       /**
-                        * @var $module ApiQueryBase
-                        */
-                       $module = $this->mModuleMgr->getModule( $name );
-
-                       $msg = ApiMain::makeHelpMsgHeader( $module, $group );
-                       $msg2 = $module->makeHelpMsg();
-                       if ( $msg2 !== false ) {
-                               $msg .= $msg2;
-                       }
-                       if ( $module instanceof ApiQueryGeneratorBase ) {
-                               $msg .= "Generator:\n  This module may be used as a generator\n";
-                       }
-                       $moduleDescriptions[] = $msg;
-               }
-
-               return implode( "\n", $moduleDescriptions );
-       }
-
        public function isReadMode() {
                // We need to make an exception for certain meta modules that should be
                // accessible even without the 'read' right. Restrict the exception as
index e308ba4..6e27fc8 100644 (file)
@@ -406,12 +406,12 @@ class ApiResult implements ApiSerializable {
                $arr = &$this->path( $path, ( $flags & ApiResult::ADD_ON_TOP ) ? 'prepend' : 'append' );
 
                if ( $this->checkingSize && !( $flags & ApiResult::NO_SIZE_CHECK ) ) {
-                       // self::valueSize needs the validated value. Then flag
+                       // self::size needs the validated value. Then flag
                        // to not re-validate later.
                        $value = self::validateValue( $value );
                        $flags |= ApiResult::NO_VALIDATE;
 
-                       $newsize = $this->size + self::valueSize( $value );
+                       $newsize = $this->size + self::size( $value );
                        if ( $this->maxSize !== false && $newsize > $this->maxSize ) {
                                /// @todo Add i18n message when replacing calls to ->setWarning()
                                $msg = new ApiRawMessage( 'This result was truncated because it would otherwise ' .
@@ -462,7 +462,7 @@ class ApiResult implements ApiSerializable {
                }
                $ret = self::unsetValue( $this->path( $path, 'dummy' ), $name );
                if ( $this->checkingSize && !( $flags & ApiResult::NO_SIZE_CHECK ) ) {
-                       $newsize = $this->size - self::valueSize( $ret );
+                       $newsize = $this->size - self::size( $ret );
                        $this->size = max( $newsize, 0 );
                }
                return $ret;
@@ -1085,17 +1085,15 @@ class ApiResult implements ApiSerializable {
        /**
         * Get the 'real' size of a result item. This means the strlen() of the item,
         * or the sum of the strlen()s of the elements if the item is an array.
-        * @note Once the deprecated public self::size is removed, we can rename
-        *       this back to a less awkward name.
         * @param mixed $value Validated value (see self::validateValue())
         * @return int
         */
-       private static function valueSize( $value ) {
+       private static function size( $value ) {
                $s = 0;
                if ( is_array( $value ) ) {
                        foreach ( $value as $k => $v ) {
                                if ( !self::isMetadataKey( $k ) ) {
-                                       $s += self::valueSize( $v );
+                                       $s += self::size( $v );
                                }
                        }
                } elseif ( is_scalar( $value ) ) {
@@ -1202,310 +1200,6 @@ class ApiResult implements ApiSerializable {
 
        /**@}*/
 
-       /************************************************************************//**
-        * @name   Deprecated
-        * @{
-        */
-
-       /**
-        * Formerly used to enable/disable "raw mode".
-        * @deprecated since 1.25, you shouldn't have been using it in the first place
-        * @since 1.23 $flag parameter added
-        * @param bool $flag Set the raw mode flag to this state
-        */
-       public function setRawMode( $flag = true ) {
-               wfDeprecated( __METHOD__, '1.25' );
-       }
-
-       /**
-        * Returns true, the equivalent of "raw mode" is always enabled now
-        * @deprecated since 1.25, you shouldn't have been using it in the first place
-        * @return bool
-        */
-       public function getIsRawMode() {
-               wfDeprecated( __METHOD__, '1.25' );
-               return true;
-       }
-
-       /**
-        * Get the result's internal data array (read-only)
-        * @deprecated since 1.25, use $this->getResultData() instead
-        * @return array
-        */
-       public function getData() {
-               wfDeprecated( __METHOD__, '1.25' );
-               return $this->getResultData( null, [
-                       'BC' => [],
-                       'Types' => [],
-                       'Strip' => 'all',
-               ] );
-       }
-
-       /**
-        * Disable size checking in addValue(). Don't use this unless you
-        * REALLY know what you're doing. Values added while size checking
-        * was disabled will not be counted (ever)
-        * @deprecated since 1.24, use ApiResult::NO_SIZE_CHECK
-        */
-       public function disableSizeCheck() {
-               wfDeprecated( __METHOD__, '1.24' );
-               $this->checkingSize = false;
-       }
-
-       /**
-        * Re-enable size checking in addValue()
-        * @deprecated since 1.24, use ApiResult::NO_SIZE_CHECK
-        */
-       public function enableSizeCheck() {
-               wfDeprecated( __METHOD__, '1.24' );
-               $this->checkingSize = true;
-       }
-
-       /**
-        * Alias for self::setValue()
-        *
-        * @since 1.21 int $flags replaced boolean $override
-        * @deprecated since 1.25, use self::setValue() instead
-        * @param array $arr To add $value to
-        * @param string $name Index of $arr to add $value at
-        * @param mixed $value
-        * @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP.
-        *    This parameter used to be boolean, and the value of OVERRIDE=1 was
-        *    specifically chosen so that it would be backwards compatible with the
-        *    new method signature.
-        */
-       public static function setElement( &$arr, $name, $value, $flags = 0 ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               self::setValue( $arr, $name, $value, $flags );
-       }
-
-       /**
-        * Adds a content element to an array.
-        * Use this function instead of hardcoding the '*' element.
-        * @deprecated since 1.25, use self::setContentValue() instead
-        * @param array $arr To add the content element to
-        * @param mixed $value
-        * @param string $subElemName When present, content element is created
-        *  as a sub item of $arr. Use this parameter to create elements in
-        *  format "<elem>text</elem>" without attributes.
-        */
-       public static function setContent( &$arr, $value, $subElemName = null ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               if ( is_array( $value ) ) {
-                       throw new InvalidArgumentException( __METHOD__ . ': Bad parameter' );
-               }
-               if ( is_null( $subElemName ) ) {
-                       self::setContentValue( $arr, 'content', $value );
-               } else {
-                       if ( !isset( $arr[$subElemName] ) ) {
-                               $arr[$subElemName] = [];
-                       }
-                       self::setContentValue( $arr[$subElemName], 'content', $value );
-               }
-       }
-
-       /**
-        * Set indexed tag name on all subarrays of $arr
-        *
-        * Does not set the tag name for $arr itself.
-        *
-        * @deprecated since 1.25, use self::setIndexedTagNameRecursive() instead
-        * @param array $arr
-        * @param string $tag Tag name
-        */
-       public function setIndexedTagName_recursive( &$arr, $tag ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               if ( !is_array( $arr ) ) {
-                       return;
-               }
-               if ( !is_string( $tag ) ) {
-                       throw new InvalidArgumentException( 'Bad tag name' );
-               }
-               foreach ( $arr as $k => &$v ) {
-                       if ( !self::isMetadataKey( $k ) && is_array( $v ) ) {
-                               $v[self::META_INDEXED_TAG_NAME] = $tag;
-                               $this->setIndexedTagName_recursive( $v, $tag );
-                       }
-               }
-       }
-
-       /**
-        * Alias for self::addIndexedTagName()
-        * @deprecated since 1.25, use $this->addIndexedTagName() instead
-        * @param array $path Path to the array, like addValue()'s $path
-        * @param string $tag
-        */
-       public function setIndexedTagName_internal( $path, $tag ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               $this->addIndexedTagName( $path, $tag );
-       }
-
-       /**
-        * Alias for self::addParsedLimit()
-        * @deprecated since 1.25, use $this->addParsedLimit() instead
-        * @param string $moduleName
-        * @param int $limit
-        */
-       public function setParsedLimit( $moduleName, $limit ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               $this->addParsedLimit( $moduleName, $limit );
-       }
-
-       /**
-        * Set the ApiMain for use by $this->beginContinuation()
-        * @since 1.25
-        * @deprecated for backwards compatibility only, do not use
-        * @param ApiMain $main
-        */
-       public function setMainForContinuation( ApiMain $main ) {
-               $this->mainForContinuation = $main;
-       }
-
-       /**
-        * Parse a 'continue' parameter and return status information.
-        *
-        * This must be balanced by a call to endContinuation().
-        *
-        * @since 1.24
-        * @deprecated since 1.25, use ApiContinuationManager instead
-        * @param string|null $continue
-        * @param ApiBase[] $allModules
-        * @param array $generatedModules
-        * @return array
-        */
-       public function beginContinuation(
-               $continue, array $allModules = [], array $generatedModules = []
-       ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               if ( $this->mainForContinuation->getContinuationManager() ) {
-                       throw new UnexpectedValueException(
-                               __METHOD__ . ': Continuation already in progress from ' .
-                               $this->mainForContinuation->getContinuationManager()->getSource()
-                       );
-               }
-
-               // Ugh. If $continue doesn't match that in the request, temporarily
-               // replace the request when creating the ApiContinuationManager.
-               if ( $continue === null ) {
-                       $continue = '';
-               }
-               if ( $this->mainForContinuation->getVal( 'continue', '' ) !== $continue ) {
-                       $oldCtx = $this->mainForContinuation->getContext();
-                       $newCtx = new DerivativeContext( $oldCtx );
-                       $newCtx->setRequest( new DerivativeRequest(
-                               $oldCtx->getRequest(),
-                               [ 'continue' => $continue ] + $oldCtx->getRequest()->getValues(),
-                               $oldCtx->getRequest()->wasPosted()
-                       ) );
-                       $this->mainForContinuation->setContext( $newCtx );
-                       $reset = new ScopedCallback(
-                               [ $this->mainForContinuation, 'setContext' ],
-                               [ $oldCtx ]
-                       );
-               }
-               $manager = new ApiContinuationManager(
-                       $this->mainForContinuation, $allModules, $generatedModules
-               );
-               $reset = null;
-
-               $this->mainForContinuation->setContinuationManager( $manager );
-
-               return [
-                       $manager->isGeneratorDone(),
-                       $manager->getRunModules(),
-               ];
-       }
-
-       /**
-        * @since 1.24
-        * @deprecated since 1.25, use ApiContinuationManager instead
-        * @param ApiBase $module
-        * @param string $paramName
-        * @param string|array $paramValue
-        */
-       public function setContinueParam( ApiBase $module, $paramName, $paramValue ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               if ( $this->mainForContinuation->getContinuationManager() ) {
-                       $this->mainForContinuation->getContinuationManager()->addContinueParam(
-                               $module, $paramName, $paramValue
-                       );
-               }
-       }
-
-       /**
-        * @since 1.24
-        * @deprecated since 1.25, use ApiContinuationManager instead
-        * @param ApiBase $module
-        * @param string $paramName
-        * @param string|array $paramValue
-        */
-       public function setGeneratorContinueParam( ApiBase $module, $paramName, $paramValue ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               if ( $this->mainForContinuation->getContinuationManager() ) {
-                       $this->mainForContinuation->getContinuationManager()->addGeneratorContinueParam(
-                               $module, $paramName, $paramValue
-                       );
-               }
-       }
-
-       /**
-        * Close continuation, writing the data into the result
-        * @since 1.24
-        * @deprecated since 1.25, use ApiContinuationManager instead
-        * @param string $style 'standard' for the new style since 1.21, 'raw' for
-        *   the style used in 1.20 and earlier.
-        */
-       public function endContinuation( $style = 'standard' ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               if ( !$this->mainForContinuation->getContinuationManager() ) {
-                       return;
-               }
-
-               if ( $style === 'raw' ) {
-                       $data = $this->mainForContinuation->getContinuationManager()->getRawContinuation();
-                       if ( $data ) {
-                               $this->addValue( null, 'query-continue', $data, self::ADD_ON_TOP | self::NO_SIZE_CHECK );
-                       }
-               } else {
-                       $this->mainForContinuation->getContinuationManager()->setContinuationIntoResult( $this );
-               }
-       }
-
-       /**
-        * No-op, this is now checked on insert.
-        * @deprecated since 1.25
-        */
-       public function cleanUpUTF8() {
-               wfDeprecated( __METHOD__, '1.25' );
-       }
-
-       /**
-        * Get the 'real' size of a result item. This means the strlen() of the item,
-        * or the sum of the strlen()s of the elements if the item is an array.
-        * @deprecated since 1.25, no external users known and there doesn't seem
-        *  to be any case for such use over just checking the return value from the
-        *  add/set methods.
-        * @param mixed $value
-        * @return int
-        */
-       public static function size( $value ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               return self::valueSize( self::validateValue( $value ) );
-       }
-
-       /**
-        * Converts a Status object to an array suitable for addValue
-        * @deprecated since 1.25, use ApiErrorFormatter::arrayFromStatus()
-        * @param Status $status
-        * @param string $errorType
-        * @return array
-        */
-       public function convertStatusToArray( $status, $errorType = 'error' ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               return $this->errorFormatter->arrayFromStatus( $status, $errorType );
-       }
-
-       /**@}*/
 }
 
 /**
index 8ae1192..fb9c4e6 100644 (file)
@@ -104,7 +104,8 @@ trait SearchApi {
                $searchEngine = MediaWikiServices::getInstance()->newSearchEngine();
                $params = [];
                foreach ( $configs as $paramName => $paramConfig ) {
-                       $profiles = $searchEngine->getProfiles( $paramConfig['profile-type'] );
+                       $profiles = $searchEngine->getProfiles( $paramConfig['profile-type'],
+                               $this->getContext()->getUser() );
                        if ( !$profiles ) {
                                continue;
                        }
@@ -188,4 +189,9 @@ trait SearchApi {
         *  containing 'help-message' and 'profile-type' keys.
         */
        abstract public function getSearchProfileParams();
+
+       /**
+        * @return IContextSource
+        */
+       abstract public function getContext();
 }
index 360420b..e25f882 100644 (file)
@@ -157,12 +157,6 @@ abstract class FileCacheBase {
         * @return string Compressed text
         */
        public function saveText( $text ) {
-               global $wgUseFileCache;
-
-               if ( !$wgUseFileCache ) {
-                       return false;
-               }
-
                if ( $this->useGzip() ) {
                        $text = gzencode( $text );
                }
index 71011e0..a85639f 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup Cache
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Page view caching in the file system.
  * The only cacheable actions are "view" and "history". Also special pages
@@ -31,6 +33,7 @@
 class HTMLFileCache extends FileCacheBase {
        const MODE_NORMAL = 0; // normal cache mode
        const MODE_OUTAGE = 1; // fallback cache for DB outages
+       const MODE_REBUILD = 2; // background cache rebuild mode
 
        /**
         * Construct an HTMLFileCache object from a Title and an action
@@ -52,6 +55,7 @@ class HTMLFileCache extends FileCacheBase {
         */
        public function __construct( $title, $action ) {
                parent::__construct();
+
                $allowedTypes = self::cacheablePageActions();
                if ( !in_array( $action, $allowedTypes ) ) {
                        throw new MWException( 'Invalid file cache type given.' );
@@ -96,16 +100,15 @@ class HTMLFileCache extends FileCacheBase {
        /**
         * Check if pages can be cached for this request/user
         * @param IContextSource $context
-        * @param integer $mode One of the HTMLFileCache::MODE_* constants
+        * @param integer $mode One of the HTMLFileCache::MODE_* constants (since 1.28)
         * @return bool
         */
        public static function useFileCache( IContextSource $context, $mode = self::MODE_NORMAL ) {
-               global $wgUseFileCache, $wgDebugToolbar, $wgContLang;
+               $config = MediaWikiServices::getInstance()->getMainConfig();
 
-               if ( !$wgUseFileCache ) {
+               if ( !$config->get( 'UseFileCache' ) && $mode !== self::MODE_REBUILD ) {
                        return false;
-               }
-               if ( $wgDebugToolbar ) {
+               } elseif ( $config->get( 'DebugToolbar' ) ) {
                        wfDebug( "HTML file cache skipped. \$wgDebugToolbar on\n" );
 
                        return false;
@@ -133,7 +136,7 @@ class HTMLFileCache extends FileCacheBase {
                $ulang = $context->getLanguage();
 
                // Check that there are no other sources of variation
-               if ( $user->getId() || !$ulang->equals( $wgContLang ) ) {
+               if ( $user->getId() || $ulang->getCode() !== $config->get( 'LanguageCode' ) ) {
                        return false;
                }
 
@@ -154,7 +157,7 @@ class HTMLFileCache extends FileCacheBase {
         * @return void
         */
        public function loadFromFileCache( IContextSource $context, $mode = self::MODE_NORMAL ) {
-               global $wgMimeType, $wgContLang;
+               $config = MediaWikiServices::getInstance()->getMainConfig();
 
                wfDebug( __METHOD__ . "()\n" );
                $filename = $this->cachePath();
@@ -165,8 +168,8 @@ class HTMLFileCache extends FileCacheBase {
                }
 
                $context->getOutput()->sendCacheControl();
-               header( "Content-Type: $wgMimeType; charset=UTF-8" );
-               header( 'Content-Language: ' . $wgContLang->getHtmlCode() );
+               header( "Content-Type: {$config->get( 'MimeType' )}; charset=UTF-8" );
+               header( "Content-Language: {$config->get( 'LanguageCode' )}" );
                if ( $this->useGzip() ) {
                        if ( wfClientAcceptsGzip() ) {
                                header( 'Content-Encoding: gzip' );
@@ -179,19 +182,24 @@ class HTMLFileCache extends FileCacheBase {
                } else {
                        readfile( $filename );
                }
+
                $context->getOutput()->disable(); // tell $wgOut that output is taken care of
        }
 
        /**
         * Save this cache object with the given text.
         * Use this as an ob_start() handler.
+        *
+        * Normally this is only registed as a handler if $wgUseFileCache is on.
+        * If can be explicitly called by rebuildFileCache.php when it takes over
+        * handling file caching itself, disabling any automatic handling the the
+        * process.
+        *
         * @param string $text
-        * @return bool Whether $wgUseFileCache is enabled
+        * @return string|bool The annotated $text or false on error
         */
        public function saveToFileCache( $text ) {
-               global $wgUseFileCache;
-
-               if ( !$wgUseFileCache || strlen( $text ) < 512 ) {
+               if ( strlen( $text ) < 512 ) {
                        // Disabled or empty/broken output (OOM and PHP errors)
                        return $text;
                }
@@ -234,9 +242,9 @@ class HTMLFileCache extends FileCacheBase {
         * @return bool Whether $wgUseFileCache is enabled
         */
        public static function clearFileCache( Title $title ) {
-               global $wgUseFileCache;
+               $config = MediaWikiServices::getInstance()->getMainConfig();
 
-               if ( !$wgUseFileCache ) {
+               if ( !$config->get( 'UseFileCache' ) ) {
                        return false;
                }
 
index 3ef9641..6455a3a 100644 (file)
@@ -571,7 +571,7 @@ class ChangeTags {
                        // This function is from revision deletion logic and has nothing to do with
                        // change tags, but it appears to be the only other place in core where we
                        // perform logged actions on log items.
-                       $logEntry->setTarget( RevDelLogList::suggestTarget( 0, [ $log_id ] ) );
+                       $logEntry->setTarget( RevDelLogList::suggestTarget( null, [ $log_id ] ) );
                }
 
                if ( !$logEntry->getTarget() ) {
@@ -1038,7 +1038,7 @@ class ChangeTags {
                // let's not allow error results, as the actual tag deletion succeeded
                if ( !$status->isOK() ) {
                        wfDebug( 'ChangeTagAfterDelete error condition downgraded to warning' );
-                       $status->ok = true;
+                       $status->setOK( true );
                }
 
                // clear the memcache of defined tags
index d78d61a..1e866f3 100644 (file)
@@ -319,7 +319,7 @@ class WikiRevision {
         * @deprecated Since 1.21, use getContent() instead.
         */
        function getText() {
-               ContentHandler::deprecated( __METHOD__, '1.21' );
+               wfDeprecated( __METHOD__, '1.21' );
 
                return $this->text;
        }
index 9bf87f4..0adeddf 100644 (file)
@@ -261,6 +261,11 @@ EOT;
                return $this->getConnection();
        }
 
+       /**
+        * @param $dir
+        * @param $db
+        * @return Status
+        */
        protected function makeStubDBFile( $dir, $db ) {
                $file = DatabaseSqlite::generateFileName( $dir, $db );
                if ( file_exists( $file ) ) {
index 4e34c7d..d3973a1 100644 (file)
@@ -44,7 +44,7 @@
        "config-help-restart": "Необходимо е потвърждение за изтриване на всички въведени и съхранени данни и започване отначало на процеса по инсталация.",
        "config-restart": "Да, започване отначало",
        "config-welcome": "=== Проверка на средата ===\nЩе бъдат извършени основни проверки, които да установят дали средата е подходяща за инсталиране на МедияУики.\nАко е необходима помощ по време на инсталацията, резултатите от направените проверки трябва също да бъдат предоставени.",
-       "config-copyright": "=== Авторски права и Условия ===\n\n$1\n\nТази програма е свободен софтуер, който може да се променя и/или разпространява според Общия публичен лиценз на GNU, както е публикуван от Free Software Foundation във версия на Лиценза 2 или по-късна версия.\n\nТази програма се разпространява с надеждата, че ще е полезна, но '''без каквито и да е гаранции'''; без дори косвена гаранция за '''продаваемост''' или '''прогодност за конкретна употреба'''.\nЗа повече подробности се препоръчва преглеждането на Общия публичен лиценз на GNU.\n\nКъм програмата трябва да е приложено <doclink href=Copying>копие на Общия публичен лиценз на GNU</doclink>; ако не, можете да пишете на Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. или да [http://www.gnu.org/copyleft/gpl.html го прочетете онлайн].",
+       "config-copyright": "=== Авторски права и условия ===\n\n$1\n\nТази програма е свободен софтуер, който може да се променя и/или разпространява според Общия публичен лиценз на GNU, както е публикуван от Free Software Foundation във версия на Лиценза 2 или по-късна версия.\n\nТази програма се разпространява с надеждата, че ще е полезна, но <strong>без каквито и да е гаранции</strong>; без дори косвена гаранция за <strong>продаваемост</strong>  или <strong>прогодност за конкретна употреба</strong> .\nЗа повече подробности се препоръчва преглеждането на Общия публичен лиценз на GNU.\n\nКъм програмата трябва да е приложено <doclink href=Copying>копие на Общия публичен лиценз на GNU</doclink>; ако не, можете да пишете на Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA, или да [http://www.gnu.org/copyleft/gpl.html го прочетете онлайн].",
        "config-sidebar": "* [https://www.mediawiki.org Сайт на МедияУики]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Наръчник на потребителя]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Наръчник на администратора]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ ЧЗВ]\n----\n* <doclink href=Readme>Документация</doclink>\n* <doclink href=ReleaseNotes>Бележки за версията</doclink>\n* <doclink href=Copying>Авторски права</doclink>\n* <doclink href=UpgradeDoc>Обновяване</doclink>",
        "config-env-good": "Средата беше проверена.\nИнсталирането на МедияУики е възможно.",
        "config-env-bad": "Средата беше проверена.\nНе е възможна инсталация на МедияУики.",
@@ -59,7 +59,7 @@
        "config-pcre-old": "<strong>Фатална грешка:</strong> Изисква се PCRE версия $1 или по-нова.\nИзпълнимият файл на PHP е свързан с PCRE версия $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/Повече информация за PCRE].",
        "config-pcre-no-utf8": "'''Фатално''': Модулът PCRE на PHP изглежда е компилиран без поддръжка на PCRE_UTF8.\nЗа да функционира правилно, МедияУики изисква поддръжка на UTF-8.",
        "config-memory-raised": "<code>memory_limit</code> на PHP е $1, увеличаване до $2.",
-       "config-memory-bad": "'''Предупреждение:''' <code>memory_limit</code> на PHP е $1.\nСтойността вероятно е твърде ниска.\nВъзможно е инсталацията да се провали!",
+       "config-memory-bad": "<strong>Предупреждение:<strong> <code>memory_limit</code> на PHP е $1.\nСтойността вероятно е твърде ниска.\nВъзможно е инсталацията да се провали!",
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] е инсталиран",
        "config-apc": "[http://www.php.net/apc APC] е инсталиран",
        "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] е инсталиран",
index 538d0b8..deaa396 100644 (file)
@@ -233,35 +233,27 @@ abstract class Database implements IDatabase, LoggerAwareInterface {
        protected $trxProfiler;
 
        /**
-        * Constructor.
-        *
-        * FIXME: It is possible to construct a Database object with no associated
-        * connection object, by specifying no parameters to __construct(). This
-        * feature is deprecated and should be removed.
+        * Constructor and database handle and attempt to connect to the DB server
         *
         * IDatabase classes should not be constructed directly in external
-        * code. DatabaseBase::factory() should be used instead.
+        * code. Database::factory() should be used instead.
         *
-        * @param array $params Parameters passed from DatabaseBase::factory()
+        * @param array $params Parameters passed from Database::factory()
         */
        function __construct( array $params ) {
                $server = $params['host'];
                $user = $params['user'];
                $password = $params['password'];
                $dbName = $params['dbname'];
-               $flags = $params['flags'];
 
                $this->mSchema = $params['schema'];
                $this->mTablePrefix = $params['tablePrefix'];
 
-               $this->cliMode = isset( $params['cliMode'] )
-                       ? $params['cliMode']
-                       : ( PHP_SAPI === 'cli' );
-               $this->agent = isset( $params['agent'] )
-                       ? str_replace( '/', '-', $params['agent'] ) // escape for comment
-                       : '';
+               $this->cliMode = $params['cliMode'];
+               // Agent name is added to SQL queries in a comment, so make sure it can't break out
+               $this->agent = str_replace( '/', '-', $params['agent'] );
 
-               $this->mFlags = $flags;
+               $this->mFlags = $params['flags'];
                if ( $this->mFlags & DBO_DEFAULT ) {
                        if ( $this->cliMode ) {
                                $this->mFlags &= ~DBO_TRX;
@@ -276,50 +268,70 @@ abstract class Database implements IDatabase, LoggerAwareInterface {
                        ? $params['srvCache']
                        : new HashBagOStuff();
 
-               $this->profiler = isset( $params['profiler'] ) ? $params['profiler'] : null;
-               $this->trxProfiler = isset( $params['trxProfiler'] )
-                       ? $params['trxProfiler']
-                       : new TransactionProfiler();
-               $this->connLogger = isset( $params['connLogger'] )
-                       ? $params['connLogger']
-                       : new \Psr\Log\NullLogger();
-               $this->queryLogger = isset( $params['queryLogger'] )
-                       ? $params['queryLogger']
-                       : new \Psr\Log\NullLogger();
+               $this->profiler = $params['profiler'];
+               $this->trxProfiler = $params['trxProfiler'];
+               $this->connLogger = $params['connLogger'];
+               $this->queryLogger = $params['queryLogger'];
+
+               // Set initial dummy domain until open() sets the final DB/prefix
+               $this->currentDomain = DatabaseDomain::newUnspecified();
 
                if ( $user ) {
                        $this->open( $server, $user, $password, $dbName );
-               }
-
-               $this->currentDomain = ( $this->mDBname != '' )
-                       ? new DatabaseDomain( $this->mDBname, null, $this->mTablePrefix )
-                       : DatabaseDomain::newUnspecified();
-       }
-
-       /**
-        * Given a DB type, construct the name of the appropriate child class of
-        * IDatabase. This is designed to replace all of the manual stuff like:
-        *    $class = 'Database' . ucfirst( strtolower( $dbType ) );
-        * as well as validate against the canonical list of DB types we have
-        *
-        * This factory function is mostly useful for when you need to connect to a
-        * database other than the MediaWiki default (such as for external auth,
-        * an extension, et cetera). Do not use this to connect to the MediaWiki
-        * database. Example uses in core:
-        * @see LoadBalancer::reallyOpenConnection()
-        * @see ForeignDBRepo::getMasterDB()
-        * @see WebInstallerDBConnect::execute()
-        *
-        * @since 1.18
-        *
-        * @param string $dbType A possible DB type
-        * @param array $p An array of options to pass to the constructor.
-        *    Valid options are: host, user, password, dbname, flags, tablePrefix, schema, driver
-        * @return IDatabase|null If the database driver or extension cannot be found
+               } elseif ( $this->requiresDatabaseUser() ) {
+                       throw new InvalidArgumentException( "No database user provided." );
+               }
+
+               // Set the domain object after open() sets the relevant fields
+               if ( $this->mDBname != '' ) {
+                       // Domains with server scope but a table prefix are not used by IDatabase classes
+                       $this->currentDomain = new DatabaseDomain( $this->mDBname, null, $this->mTablePrefix );
+               }
+       }
+
+       /**
+        * Construct a Database subclass instance given a database type and parameters
+        *
+        * This also connects to the database immediately upon object construction
+        *
+        * @param string $dbType A possible DB type (sqlite, mysql, postgres)
+        * @param array $p Parameter map with keys:
+        *   - host : The hostname of the DB server
+        *   - user : The name of the database user the client operates under
+        *   - password : The password for the database user
+        *   - dbname : The name of the database to use where queries do not specify one.
+        *      The database must exist or an error might be thrown. Setting this to the empty string
+        *      will avoid any such errors and make the handle have no implicit database scope. This is
+        *      useful for queries like SHOW STATUS, CREATE DATABASE, or DROP DATABASE. Note that a
+        *      "database" in Postgres is rougly equivalent to an entire MySQL server. This the domain
+        *      in which user names and such are defined, e.g. users are database-specific in Postgres.
+        *   - schema : The database schema to use (if supported). A "schema" in Postgres is roughly
+        *      equivalent to a "database" in MySQL. Note that MySQL and SQLite do not use schemas.
+        *   - tablePrefix : Optional table prefix that is implicitly added on to all table names
+        *      recognized in queries. This can be used in place of schemas for handle site farms.
+        *   - flags : Optional bitfield of DBO_* constants that define connection, protocol,
+        *      buffering, and transaction behavior. It is STRONGLY adviced to leave the DBO_DEFAULT
+        *      flag in place UNLESS this this database simply acts as a key/value store.
+        *   - driver: Optional name of a specific DB client driver. For MySQL, there is the old
+        *      'mysql' driver and the newer 'mysqli' driver.
+        *   - variables: Optional map of session variables to set after connecting. This can be
+        *      used to adjust lock timeouts or encoding modes and the like.
+        *   - connLogger: Optional PSR-3 logger interface instance.
+        *   - queryLogger: Optional PSR-3 logger interface instance.
+        *   - profiler: Optional class name or object with profileIn()/profileOut() methods.
+        *      These will be called in query(), using a simplified version of the SQL that also
+        *      includes the agent as a SQL comment.
+        *   - trxProfiler: Optional TransactionProfiler instance.
+        *   - errorLogger: Optional callback that takes an Exception and logs it.
+        *   - cliMode: Whether to consider the execution context that of a CLI script.
+        *   - agent: Optional name used to identify the end-user in query profiling/logging.
+        *   - srvCache: Optional BagOStuff instance to an APC-style cache.
+        * @return Database|null If the database driver or extension cannot be found
         * @throws InvalidArgumentException If the database driver or extension cannot be found
+        * @since 1.18
         */
        final public static function factory( $dbType, $p = [] ) {
-               $canonicalDBTypes = [
+               static $canonicalDBTypes = [
                        'mysql' => [ 'mysqli', 'mysql' ],
                        'postgres' => [],
                        'sqlite' => [],
@@ -365,22 +377,25 @@ abstract class Database implements IDatabase, LoggerAwareInterface {
                        $p['variables'] = isset( $p['variables'] ) ? $p['variables'] : [];
                        $p['tablePrefix'] = isset( $p['tablePrefix'] ) ? $p['tablePrefix'] : '';
                        $p['schema'] = isset( $p['schema'] ) ? $p['schema'] : '';
-                       $p['foreign'] = isset( $p['foreign'] ) ? $p['foreign'] : false;
-
-                       $conn = new $class( $p );
-                       if ( isset( $p['connLogger'] ) ) {
-                               $conn->connLogger = $p['connLogger'];
+                       $p['cliMode'] = isset( $p['cliMode'] ) ? $p['cliMode'] : ( PHP_SAPI === 'cli' );
+                       $p['agent'] = isset( $p['agent'] ) ? $p['agent'] : '';
+                       if ( !isset( $p['connLogger'] ) ) {
+                               $p['connLogger'] = new \Psr\Log\NullLogger();
                        }
-                       if ( isset( $p['queryLogger'] ) ) {
-                               $conn->queryLogger = $p['queryLogger'];
+                       if ( !isset( $p['queryLogger'] ) ) {
+                               $p['queryLogger'] = new \Psr\Log\NullLogger();
                        }
-                       if ( isset( $p['errorLogger'] ) ) {
-                               $conn->errorLogger = $p['errorLogger'];
-                       } else {
-                               $conn->errorLogger = function ( Exception $e ) {
+                       $p['profiler'] = isset( $p['profiler'] ) ? $p['profiler'] : null;
+                       if ( !isset( $p['trxProfiler'] ) ) {
+                               $p['trxProfiler'] = new TransactionProfiler();
+                       }
+                       if ( !isset( $p['errorLogger'] ) ) {
+                               $p['errorLogger'] = function ( Exception $e ) {
                                        trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_WARNING );
                                };
                        }
+
+                       $conn = new $class( $p );
                } else {
                        $conn = null;
                }
@@ -669,7 +684,7 @@ abstract class Database implements IDatabase, LoggerAwareInterface {
        }
 
        /**
-        * Create a log context to pass to PSR logging functions.
+        * Create a log context to pass to PSR-3 logger functions.
         *
         * @param array $extras Additional data to add to context
         * @return array
@@ -3489,6 +3504,14 @@ abstract class Database implements IDatabase, LoggerAwareInterface {
                $this->tableAliases = $aliases;
        }
 
+       /**
+        * @return bool Whether a DB user is required to access the DB
+        * @since 1.28
+        */
+       protected function requiresDatabaseUser() {
+               return true;
+       }
+
        /**
         * @since 1.19
         * @return string
@@ -3497,6 +3520,26 @@ abstract class Database implements IDatabase, LoggerAwareInterface {
                return (string)$this->mConn;
        }
 
+       /**
+        * Make sure that copies do not share the same client binding handle
+        * @throws DBConnectionError
+        */
+       public function __clone() {
+               $this->connLogger->debug(
+                       "Cloning " . get_class( $this ) . " is not recomended; forking connection:\n" .
+                       ( new RuntimeException() )->getTraceAsString()
+               );
+
+               if ( $this->isOpen() ) {
+                       // Open a new connection resource without messing with the old one
+                       $this->mOpened = false;
+                       $this->mConn = false;
+                       $this->mTrxLevel = 0; // no trx anymore
+                       $this->open( $this->mServer, $this->mUser, $this->mPassword, $this->mDBname );
+                       $this->lastPing = microtime( true );
+               }
+       }
+
        /**
         * Called by serialize. Throw an exception when DB connection is serialized.
         * This causes problems on some database engines because the connection is
@@ -3508,7 +3551,7 @@ abstract class Database implements IDatabase, LoggerAwareInterface {
        }
 
        /**
-        * Run a few simple sanity checks
+        * Run a few simple sanity checks and close dangling connections
         */
        public function __destruct() {
                if ( $this->mTrxLevel && $this->mTrxDoneWrites ) {
@@ -3520,5 +3563,12 @@ abstract class Database implements IDatabase, LoggerAwareInterface {
                        $fnames = implode( ', ', $danglingWriters );
                        trigger_error( "DB transaction writes or callbacks still pending ($fnames)." );
                }
+
+               if ( $this->mConn ) {
+                       // Avoid connection leaks for sanity
+                       $this->closeConnection();
+                       $this->mConn = false;
+                       $this->mOpened = false;
+               }
        }
 }
index 2d19081..9be3ede 100644 (file)
@@ -518,6 +518,12 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
                return (int)$rows;
        }
 
+       function tableExists( $table, $fname = __METHOD__ ) {
+               $encLike = $this->buildLike( $table );
+
+               return $this->query( "SHOW TABLES $encLike", $fname )->numRows() > 0;
+       }
+
        /**
         * @param string $table
         * @param string $field
index b07ac16..e79b28b 100644 (file)
@@ -43,8 +43,8 @@ class DatabasePostgres extends DatabaseBase {
        private $mCoreSchema;
 
        public function __construct( array $params ) {
-               parent::__construct( $params );
                $this->port = isset( $params['port'] ) ? $params['port'] : false;
+               parent::__construct( $params );
        }
 
        function getType() {
index 8881983..6614898 100644 (file)
@@ -1046,11 +1046,14 @@ class DatabaseSqlite extends DatabaseBase {
                return $this->query( $sql, $fName );
        }
 
+       protected function requiresDatabaseUser() {
+               return false; // just a file
+       }
+
        /**
         * @return string
         */
        public function __toString() {
                return 'SQLite ' . (string)$this->mConn->getAttribute( PDO::ATTR_SERVER_VERSION );
        }
-
 }
index 40ba458..cf9a298 100644 (file)
@@ -80,8 +80,26 @@ abstract class LBFactory {
                [ 'replLogger', 'connLogger', 'queryLogger', 'perfLogger' ];
 
        /**
-        * @TODO: document base params here
-        * @param array $conf
+        * Construct a manager of ILoadBalancer objects
+        *
+        * Sub-classes will extend the required keys in $conf with additional parameters
+        *
+        * @param $conf $params Array with keys:
+        *  - localDomain: A DatabaseDomain or domain ID string.
+        *  - readOnlyReason : Reason the master DB is read-only if so [optional]
+        *  - srvCache : BagOStuff object for server cache [optional]
+        *  - memCache : BagOStuff object for cluster memory cache [optional]
+        *  - wanCache : WANObjectCache object [optional]
+        *  - hostname : The name of the current server [optional]
+        *  - cliMode: Whether the execution context is a CLI script. [optional]
+        *  - profiler : Class name or instance with profileIn()/profileOut() methods. [optional]
+        *  - trxProfiler: TransactionProfiler instance. [optional]
+        *  - replLogger: PSR-3 logger instance. [optional]
+        *  - connLogger: PSR-3 logger instance. [optional]
+        *  - queryLogger: PSR-3 logger instance. [optional]
+        *  - perfLogger: PSR-3 logger instance. [optional]
+        *  - errorLogger : Callback that takes an Exception and logs it. [optional]
+        * @throws InvalidArgumentException
         */
        public function __construct( array $conf ) {
                $this->localDomain = isset( $conf['localDomain'] )
@@ -107,8 +125,6 @@ abstract class LBFactory {
                                trigger_error( E_WARNING, get_class( $e ) . ': ' . $e->getMessage() );
                        };
 
-               $this->chronProt = isset( $conf['chronProt'] ) ? $conf['chronProt'] : null;
-
                $this->profiler = isset( $params['profiler'] ) ? $params['profiler'] : null;
                $this->trxProfiler = isset( $conf['trxProfiler'] )
                        ? $conf['trxProfiler']
@@ -130,7 +146,7 @@ abstract class LBFactory {
        /**
         * Disables all load balancers. All connections are closed, and any attempt to
         * open a new connection will result in a DBAccessError.
-        * @see LoadBalancer::disable()
+        * @see ILoadBalancer::disable()
         */
        public function destroy() {
                $this->shutdown( self::SHUTDOWN_NO_CHRONPROT );
@@ -670,7 +686,7 @@ abstract class LBFactory {
                        $prefix
                );
 
-               $this->forEachLB( function( LoadBalancer $lb ) use ( $prefix ) {
+               $this->forEachLB( function( ILoadBalancer $lb ) use ( $prefix ) {
                        $lb->setDomainPrefix( $prefix );
                } );
        }
index 0f1493a..25e1fe0 100644 (file)
  * A multi-database, multi-master factory for Wikimedia and similar installations.
  * Ignores the old configuration globals.
  *
- * Template override precedence (highest => lowest):
- *   - templateOverridesByServer
- *   - masterTemplateOverrides
- *   - templateOverridesBySection/templateOverridesByCluster
- *   - externalTemplateOverrides
- *   - serverTemplate
- * Overrides only work on top level keys (so nested values will not be merged).
- *
- * Configuration:
- *     sectionsByDB                A map of database names to section names.
- *
- *     sectionLoads                A 2-d map. For each section, gives a map of server names to
- *                                 load ratios. For example:
- *                                 [
- *                                     'section1' => [
- *                                         'db1' => 100,
- *                                         'db2' => 100
- *                                     ]
- *                                 ]
- *
- *     serverTemplate              A server info associative array as documented for $wgDBservers.
- *                                 The host, hostName and load entries will be overridden.
- *
- *     groupLoadsBySection         A 3-d map giving server load ratios for each section and group.
- *                                 For example:
- *                                 [
- *                                     'section1' => [
- *                                         'group1' => [
- *                                             'db1' => 100,
- *                                             'db2' => 100
- *                                         ]
- *                                     ]
- *                                 ]
- *
- *     groupLoadsByDB              A 3-d map giving server load ratios by DB name.
- *
- *     hostsByName                 A map of hostname to IP address.
- *
- *     externalLoads               A map of external storage cluster name to server load map.
- *
- *     externalTemplateOverrides   A set of server info keys overriding serverTemplate for external
- *                                 storage.
- *
- *     templateOverridesByServer   A 2-d map overriding serverTemplate and
- *                                 externalTemplateOverrides on a server-by-server basis. Applies
- *                                 to both core and external storage.
- *     templateOverridesBySection  A 2-d map overriding the server info by section.
- *     templateOverridesByCluster  A 2-d map overriding the server info by external storage cluster.
- *
- *     masterTemplateOverrides     An override array for all master servers.
- *
- *     loadMonitorClass            Name of the LoadMonitor class to always use.
- *
- *     readOnlyBySection           A map of section name to read-only message.
- *                                 Missing or false for read/write.
- *
  * @ingroup Database
  */
 class LBFactoryMulti extends LBFactory {
@@ -141,8 +85,6 @@ class LBFactoryMulti extends LBFactory {
         */
        private $readOnlyBySection = [];
 
-       // Other stuff
-
        /** @var array Load balancer factory configuration */
        private $conf;
 
@@ -162,8 +104,60 @@ class LBFactoryMulti extends LBFactory {
        private $lastSection;
 
        /**
-        * @param array $conf
-        * @throws InvalidArgumentException
+        * @see LBFactory::__construct()
+        *
+        * Template override precedence (highest => lowest):
+        *   - templateOverridesByServer
+        *   - masterTemplateOverrides
+        *   - templateOverridesBySection/templateOverridesByCluster
+        *   - externalTemplateOverrides
+        *   - serverTemplate
+        * Overrides only work on top level keys (so nested values will not be merged).
+        *
+        * Server configuration maps should be of the format Database::factory() requires.
+        * Additionally, a 'max lag' key should also be set on server maps, indicating how stale the
+        * data can be before the load balancer tries to avoid using it. The map can have 'is static'
+        * set to disable blocking  replication sync checks (intended for archive servers with
+        * unchanging data).
+        *
+        * @param array $conf Parameters of LBFactory::__construct() as well as:
+        *   - sectionsByDB                Map of database names to section names.
+        *   - sectionLoads                2-d map. For each section, gives a map of server names to
+        *                                 load ratios. For example:
+        *                                 [
+        *                                     'section1' => [
+        *                                         'db1' => 100,
+        *                                         'db2' => 100
+        *                                     ]
+        *                                 ]
+        *   - serverTemplate              Server configuration map intended for Database::factory().
+        *                                 Note that "host", "hostName" and "load" entries will be
+        *                                 overridden by "sectionLoads" and "hostsByName".
+        *   - groupLoadsBySection         3-d map giving server load ratios for each section/group.
+        *                                 For example:
+        *                                 [
+        *                                     'section1' => [
+        *                                         'group1' => [
+        *                                             'db1' => 100,
+        *                                             'db2' => 100
+        *                                         ]
+        *                                     ]
+        *                                 ]
+        *   - groupLoadsByDB              3-d map giving server load ratios by DB name.
+        *   - hostsByName                 Map of hostname to IP address.
+        *   - externalLoads               Map of external storage cluster name to server load map.
+        *   - externalTemplateOverrides   Set of server configuration maps overriding
+        *                                 "serverTemplate" for external storage.
+        *   - templateOverridesByServer   2-d map overriding "serverTemplate" and
+        *                                 "externalTemplateOverrides" on a server-by-server basis.
+        *                                 Applies to both core and external storage.
+        *   - templateOverridesBySection  2-d map overriding the server configuration maps by section.
+        *   - templateOverridesByCluster  2-d map overriding the server configuration maps by external
+        *                                 storage cluster.
+        *   - masterTemplateOverrides     Server configuration map overrides for all master servers.
+        *   - loadMonitorClass            Name of the LoadMonitor class to always use.
+        *   - readOnlyBySection           A map of section name to read-only message.
+        *                                 Missing or false for read/write.
         */
        public function __construct( array $conf ) {
                parent::__construct( $conf );
index 0949092..b90afe6 100644 (file)
@@ -38,6 +38,18 @@ class LBFactorySimple extends LBFactory {
        /** @var string */
        private $loadMonitorClass;
 
+       /**
+        * @see LBFactory::__construct()
+        * @param array $conf Parameters of LBFactory::__construct() as well as:
+        *   - servers : list of server configuration maps to Database::factory().
+        *      Additionally, the server maps should have a 'load' key, which is used to decide
+        *      how often clients connect to one server verses the others. A 'max lag' key should
+        *      also be set on server maps, indicating how stale the data can be before the load
+        *      balancer tries to avoid using it. The map can have 'is static' set to disable blocking
+        *      replication sync checks (intended for archive servers with unchanging data).
+        *   - externalClusters : map of cluster names to server arrays. The servers arrays have the
+        *      same format as "servers" above.
+        */
        public function __construct( array $conf ) {
                parent::__construct( $conf );
 
index 0f6bea3..0efd8bc 100644 (file)
  */
 interface ILoadBalancer {
        /**
-        * @param array $params Array with keys:
+        * Construct a manager of IDatabase connection objects
+        *
+        * @param array $params Parameter map with keys:
         *  - servers : Required. Array of server info structures.
+        *  - localDomain: A DatabaseDomain or domain ID string.
         *  - loadMonitor : Name of a class used to fetch server lag and load.
         *  - readOnlyReason : Reason the master DB is read-only if so [optional]
         *  - waitTimeout : Maximum time to wait for replicas for consistency [optional]
         *  - srvCache : BagOStuff object for server cache [optional]
         *  - memCache : BagOStuff object for cluster memory cache [optional]
         *  - wanCache : WANObjectCache object [optional]
-        *  - hostname : the name of the current server [optional]
+        *  - hostname : The name of the current server [optional]
+        *  - cliMode: Whether the execution context is a CLI script. [optional]
+        *  - profiler : Class name or instance with profileIn()/profileOut() methods. [optional]
+        *  - trxProfiler: TransactionProfiler instance. [optional]
+        *  - replLogger: PSR-3 logger instance. [optional]
+        *  - connLogger: PSR-3 logger instance. [optional]
+        *  - queryLogger: PSR-3 logger instance. [optional]
+        *  - perfLogger: PSR-3 logger instance. [optional]
+        *  - errorLogger : Callback that takes an Exception and logs it. [optional]
         * @throws InvalidArgumentException
         */
        public function __construct( array $params );
@@ -50,11 +61,11 @@ interface ILoadBalancer {
         *
         * Side effect: opens connections to databases
         * @param string|bool $group Query group, or false for the generic reader
-        * @param string|bool $wiki Wiki ID, or false for the current wiki
+        * @param string|bool $domain Domain ID, or false for the current domain
         * @throws DBError
         * @return bool|int|string
         */
-       public function getReaderIndex( $group = false, $wiki = false );
+       public function getReaderIndex( $group = false, $domain = false );
 
        /**
         * Set the master wait position
@@ -98,12 +109,12 @@ interface ILoadBalancer {
         *
         * @param int $i Server index
         * @param array|string|bool $groups Query group(s), or false for the generic reader
-        * @param string|bool $wiki Wiki ID, or false for the current wiki
+        * @param string|bool $domain Domain ID, or false for the current domain
         *
         * @throws DBError
         * @return IDatabase
         */
-       public function getConnection( $i, $groups = [], $wiki = false );
+       public function getConnection( $i, $groups = [], $domain = false );
 
        /**
         * Mark a foreign connection as being available for reuse under a different
@@ -124,10 +135,10 @@ interface ILoadBalancer {
         *
         * @param int $db
         * @param array|string|bool $groups Query group(s), or false for the generic reader
-        * @param string|bool $wiki Wiki ID, or false for the current wiki
+        * @param string|bool $domain Domain ID, or false for the current domain
         * @return DBConnRef
         */
-       public function getConnectionRef( $db, $groups = [], $wiki = false );
+       public function getConnectionRef( $db, $groups = [], $domain = false );
 
        /**
         * Get a database connection handle reference without connecting yet
@@ -138,10 +149,10 @@ interface ILoadBalancer {
         *
         * @param int $db
         * @param array|string|bool $groups Query group(s), or false for the generic reader
-        * @param string|bool $wiki Wiki ID, or false for the current wiki
+        * @param string|bool $domain Domain ID, or false for the current domain
         * @return DBConnRef
         */
-       public function getLazyConnectionRef( $db, $groups = [], $wiki = false );
+       public function getLazyConnectionRef( $db, $groups = [], $domain = false );
 
        /**
         * Open a connection to the server given by the specified index
@@ -154,10 +165,10 @@ interface ILoadBalancer {
         * @note If disable() was called on this LoadBalancer, this method will throw a DBAccessError.
         *
         * @param int $i Server index
-        * @param string|bool $wiki Wiki ID, or false for the current wiki
+        * @param string|bool $domain Domain ID, or false for the current domain
         * @return IDatabase|bool Returns false on errors
         */
-       public function openConnection( $i, $wiki = false );
+       public function openConnection( $i, $domain = false );
 
        /**
         * @return int
@@ -352,10 +363,10 @@ interface ILoadBalancer {
 
        /**
         * @note This method will trigger a DB connection if not yet done
-        * @param string|bool $wiki Wiki ID, or false for the current wiki
+        * @param string|bool $domain Domain ID, or false for the current domain
         * @return bool Whether the generic connection for reads is highly "lagged"
         */
-       public function getLaggedReplicaMode( $wiki = false );
+       public function getLaggedReplicaMode( $domain = false );
 
        /**
         * @note This method will never cause a new DB connection
@@ -365,11 +376,11 @@ interface ILoadBalancer {
 
        /**
         * @note This method may trigger a DB connection if not yet done
-        * @param string|bool $wiki Wiki ID, or false for the current wiki
+        * @param string|bool $domain Domain ID, or false for the current domain
         * @param IDatabase|null DB master connection; used to avoid loops [optional]
         * @return string|bool Reason the master is read-only or false if it is not
         */
-       public function getReadOnlyReason( $wiki = false, IDatabase $conn = null );
+       public function getReadOnlyReason( $domain = false, IDatabase $conn = null );
 
        /**
         * Disables/enables lag checks
@@ -411,10 +422,10 @@ interface ILoadBalancer {
         * May attempt to open connections to replica DBs on the default DB. If there is
         * no lag, the maximum lag will be reported as -1.
         *
-        * @param bool|string $wiki Wiki ID, or false for the default database
+        * @param bool|string $domain Domain ID, or false for the default database
         * @return array ( host, max lag, index of max lagged host )
         */
-       public function getMaxLag( $wiki = false );
+       public function getMaxLag( $domain = false );
 
        /**
         * Get an estimate of replication lag (in seconds) for each server
@@ -423,10 +434,10 @@ interface ILoadBalancer {
         *
         * Values may be "false" if replication is too broken to estimate
         *
-        * @param string|bool $wiki
+        * @param string|bool $domain
         * @return int[] Map of (server index => float|int|bool)
         */
-       public function getLagTimes( $wiki = false );
+       public function getLagTimes( $domain = false );
 
        /**
         * Get the lag in seconds for a given connection, or zero if this load
@@ -471,4 +482,25 @@ interface ILoadBalancer {
         * @param callable|null $callback
         */
        public function setTransactionListener( $name, callable $callback = null );
+
+       /**
+        * Set a new table prefix for the existing local domain ID for testing
+        *
+        * @param string $prefix
+        */
+       public function setDomainPrefix( $prefix );
+
+       /**
+        * Make certain table names use their own database, schema, and table prefix
+        * when passed into SQL queries pre-escaped and without a qualified database name
+        *
+        * For example, "user" can be converted to "myschema.mydbname.user" for convenience.
+        * Appearances like `user`, somedb.user, somedb.someschema.user will used literally.
+        *
+        * Calling this twice will completely clear any old table aliases. Also, note that
+        * callers are responsible for making sure the schemas and databases actually exist.
+        *
+        * @param array[] $aliases Map of (table => (dbname, schema, prefix) map)
+        */
+       public function setTableAliases( array $aliases );
 }
index 2bc378a..c78f0ae 100644 (file)
@@ -406,16 +406,6 @@ class LoadBalancer implements ILoadBalancer {
                }
        }
 
-       /**
-        * Set the master wait position and wait for a "generic" replica DB to catch up to it
-        *
-        * This can be used a faster proxy for waitForAll()
-        *
-        * @param DBMasterPos $pos
-        * @param int $timeout Max seconds to wait; default is mWaitTimeout
-        * @return bool Success (able to connect and no timeouts reached)
-        * @since 1.26
-        */
        public function waitForOne( $pos, $timeout = null ) {
                $this->mWaitForPos = $pos;
 
@@ -630,38 +620,12 @@ class LoadBalancer implements ILoadBalancer {
                }
        }
 
-       /**
-        * Get a database connection handle reference
-        *
-        * The handle's methods wrap simply wrap those of a IDatabase handle
-        *
-        * @see LoadBalancer::getConnection() for parameter information
-        *
-        * @param int $db
-        * @param array|string|bool $groups Query group(s), or false for the generic reader
-        * @param string|bool $domain Domain ID, or false for the current domain
-        * @return DBConnRef
-        * @since 1.22
-        */
        public function getConnectionRef( $db, $groups = [], $domain = false ) {
                $domain = ( $domain !== false ) ? $domain : $this->localDomain;
 
                return new DBConnRef( $this, $this->getConnection( $db, $groups, $domain ) );
        }
 
-       /**
-        * Get a database connection handle reference without connecting yet
-        *
-        * The handle's methods wrap simply wrap those of a IDatabase handle
-        *
-        * @see LoadBalancer::getConnection() for parameter information
-        *
-        * @param int $db
-        * @param array|string|bool $groups Query group(s), or false for the generic reader
-        * @param string|bool $domain Domain ID, or false for the current domain
-        * @return DBConnRef
-        * @since 1.22
-        */
        public function getLazyConnectionRef( $db, $groups = [], $domain = false ) {
                $domain = ( $domain !== false ) ? $domain : $this->localDomain;
 
@@ -966,12 +930,6 @@ class LoadBalancer implements ILoadBalancer {
                return false;
        }
 
-       /**
-        * Disable this load balancer. All connections are closed, and any attempt to
-        * open a new connection will result in a DBAccessError.
-        *
-        * @since 1.27
-        */
        public function disable() {
                $this->closeAll();
                $this->disabled = true;
@@ -979,6 +937,8 @@ class LoadBalancer implements ILoadBalancer {
 
        public function closeAll() {
                $this->forEachOpenConnection( function ( IDatabase $conn ) {
+                       $host = $conn->getServer();
+                       $this->connLogger->debug( "Closing connection to database '$host'." );
                        $conn->close();
                } );
 
@@ -999,6 +959,8 @@ class LoadBalancer implements ILoadBalancer {
 
                        foreach ( $connsByServer[$serverIndex] as $i => $trackedConn ) {
                                if ( $conn === $trackedConn ) {
+                                       $host = $this->getServerName( $i );
+                                       $this->connLogger->debug( "Closing connection to database $i at '$host'." );
                                        unset( $this->mConns[$type][$serverIndex][$i] );
                                        --$this->connsOpened;
                                        break 2;
@@ -1036,11 +998,6 @@ class LoadBalancer implements ILoadBalancer {
                }
        }
 
-       /**
-        * Perform all pre-commit callbacks that remain part of the atomic transactions
-        * and disable any post-commit callbacks until runMasterPostTrxCallbacks()
-        * @since 1.28
-        */
        public function finalizeMasterChanges() {
                $this->forEachOpenMasterConnection( function ( DatabaseBase $conn ) {
                        // Any error should cause all DB transactions to be rolled back together
@@ -1051,13 +1008,6 @@ class LoadBalancer implements ILoadBalancer {
                } );
        }
 
-       /**
-        * Perform all pre-commit checks for things like replication safety
-        * @param array $options Includes:
-        *   - maxWriteDuration : max write query duration time in seconds
-        * @throws DBTransactionError
-        * @since 1.28
-        */
        public function approveMasterChanges( array $options ) {
                $limit = isset( $options['maxWriteDuration'] ) ? $options['maxWriteDuration'] : 0;
                $this->forEachOpenMasterConnection( function ( IDatabase $conn ) use ( $limit ) {
@@ -1091,19 +1041,6 @@ class LoadBalancer implements ILoadBalancer {
                } );
        }
 
-       /**
-        * Flush any master transaction snapshots and set DBO_TRX (if DBO_DEFAULT is set)
-        *
-        * The DBO_TRX setting will be reverted to the default in each of these methods:
-        *   - commitMasterChanges()
-        *   - rollbackMasterChanges()
-        *   - commitAll()
-        * This allows for custom transaction rounds from any outer transaction scope.
-        *
-        * @param string $fname
-        * @throws DBExpectedError
-        * @since 1.28
-        */
        public function beginMasterChanges( $fname = __METHOD__ ) {
                if ( $this->trxRoundId !== false ) {
                        throw new DBTransactionError(
@@ -1167,12 +1104,6 @@ class LoadBalancer implements ILoadBalancer {
                }
        }
 
-       /**
-        * Issue all pending post-COMMIT/ROLLBACK callbacks
-        * @param integer $type IDatabase::TRIGGER_* constant
-        * @return Exception|null The first exception or null if there were none
-        * @since 1.28
-        */
        public function runMasterPostTrxCallbacks( $type ) {
                $e = null; // first exception
                $this->forEachOpenMasterConnection( function ( DatabaseBase $conn ) use ( $type, &$e ) {
@@ -1206,12 +1137,6 @@ class LoadBalancer implements ILoadBalancer {
                return $e;
        }
 
-       /**
-        * Issue ROLLBACK only on master, only if queries were done on connection
-        * @param string $fname Caller name
-        * @throws DBExpectedError
-        * @since 1.23
-        */
        public function rollbackMasterChanges( $fname = __METHOD__ ) {
                $restore = ( $this->trxRoundId !== false );
                $this->trxRoundId = false;
@@ -1227,11 +1152,6 @@ class LoadBalancer implements ILoadBalancer {
                );
        }
 
-       /**
-        * Suppress all pending post-COMMIT/ROLLBACK callbacks
-        * @return Exception|null The first exception or null if there were none
-        * @since 1.28
-        */
        public function suppressTransactionEndCallbacks() {
                $this->forEachOpenMasterConnection( function ( DatabaseBase $conn ) {
                        $conn->setTrxEndCallbackSuppression( true );
@@ -1261,31 +1181,16 @@ class LoadBalancer implements ILoadBalancer {
                }
        }
 
-       /**
-        * Commit all replica DB transactions so as to flush any REPEATABLE-READ or SSI snapshot
-        *
-        * @param string $fname Caller name
-        * @since 1.28
-        */
        public function flushReplicaSnapshots( $fname = __METHOD__ ) {
                $this->forEachOpenReplicaConnection( function ( IDatabase $conn ) {
                        $conn->flushSnapshot( __METHOD__ );
                } );
        }
 
-       /**
-        * @return bool Whether a master connection is already open
-        * @since 1.24
-        */
        public function hasMasterConnection() {
                return $this->isOpen( $this->getWriterIndex() );
        }
 
-       /**
-        * Determine if there are pending changes in a transaction by this thread
-        * @since 1.23
-        * @return bool
-        */
        public function hasMasterChanges() {
                $pending = 0;
                $this->forEachOpenMasterConnection( function ( IDatabase $conn ) use ( &$pending ) {
@@ -1295,11 +1200,6 @@ class LoadBalancer implements ILoadBalancer {
                return (bool)$pending;
        }
 
-       /**
-        * Get the timestamp of the latest write query done by this thread
-        * @since 1.25
-        * @return float|bool UNIX timestamp or false
-        */
        public function lastMasterChangeTimestamp() {
                $lastTime = false;
                $this->forEachOpenMasterConnection( function ( IDatabase $conn ) use ( &$lastTime ) {
@@ -1309,14 +1209,6 @@ class LoadBalancer implements ILoadBalancer {
                return $lastTime;
        }
 
-       /**
-        * Check if this load balancer object had any recent or still
-        * pending writes issued against it by this PHP thread
-        *
-        * @param float $age How many seconds ago is "recent" [defaults to mWaitTimeout]
-        * @return bool
-        * @since 1.25
-        */
        public function hasOrMadeRecentMasterChanges( $age = null ) {
                $age = ( $age === null ) ? $this->mWaitTimeout : $age;
 
@@ -1324,12 +1216,6 @@ class LoadBalancer implements ILoadBalancer {
                        || $this->lastMasterChangeTimestamp() > microtime( true ) - $age );
        }
 
-       /**
-        * Get the list of callers that have pending master changes
-        *
-        * @return string[] List of method names
-        * @since 1.27
-        */
        public function pendingMasterChangeCallers() {
                $fnames = [];
                $this->forEachOpenMasterConnection( function ( IDatabase $conn ) use ( &$fnames ) {
@@ -1365,11 +1251,6 @@ class LoadBalancer implements ILoadBalancer {
                return $this->getLaggedReplicaMode( $domain );
        }
 
-       /**
-        * @note This method will never cause a new DB connection
-        * @return bool Whether any generic connection used for reads was highly "lagged"
-        * @since 1.28
-        */
        public function laggedReplicaUsed() {
                return $this->laggedReplicaMode;
        }
@@ -1383,13 +1264,6 @@ class LoadBalancer implements ILoadBalancer {
                return $this->laggedReplicaUsed();
        }
 
-       /**
-        * @note This method may trigger a DB connection if not yet done
-        * @param string|bool $domain Domain ID, or false for the current domain
-        * @param IDatabase|null DB master connection; used to avoid loops [optional]
-        * @return string|bool Reason the master is read-only or false if it is not
-        * @since 1.27
-        */
        public function getReadOnlyReason( $domain = false, IDatabase $conn = null ) {
                if ( $this->readOnlyReason !== false ) {
                        return $this->readOnlyReason;
@@ -1466,12 +1340,6 @@ class LoadBalancer implements ILoadBalancer {
                }
        }
 
-       /**
-        * Call a function with each open connection object to a master
-        * @param callable $callback
-        * @param array $params
-        * @since 1.28
-        */
        public function forEachOpenMasterConnection( $callback, array $params = [] ) {
                $masterIndex = $this->getWriterIndex();
                foreach ( $this->mConns as $connsByServer ) {
@@ -1485,12 +1353,6 @@ class LoadBalancer implements ILoadBalancer {
                }
        }
 
-       /**
-        * Call a function with each open replica DB connection object
-        * @param callable $callback
-        * @param array $params
-        * @since 1.28
-        */
        public function forEachOpenReplicaConnection( $callback, array $params = [] ) {
                foreach ( $this->mConns as $connsByServer ) {
                        foreach ( $connsByServer as $i => $serverConns ) {
@@ -1543,17 +1405,6 @@ class LoadBalancer implements ILoadBalancer {
                }
        }
 
-       /**
-        * Wait for a replica DB to reach a specified master position
-        *
-        * This will connect to the master to get an accurate position if $pos is not given
-        *
-        * @param IDatabase $conn Replica DB
-        * @param DBMasterPos|bool $pos Master position; default: current position
-        * @param integer $timeout Timeout in seconds
-        * @return bool Success
-        * @since 1.27
-        */
        public function safeWaitForMasterPos( IDatabase $conn, $pos = false, $timeout = 10 ) {
                if ( $this->getServerCount() == 1 || !$conn->getLBInfo( 'replica' ) ) {
                        return true; // server is not a replica DB
@@ -1577,24 +1428,10 @@ class LoadBalancer implements ILoadBalancer {
                return $ok;
        }
 
-       /**
-        * Clear the cache for slag lag delay times
-        *
-        * This is only used for testing
-        * @since 1.26
-        */
        public function clearLagTimeCache() {
                $this->getLoadMonitor()->clearCaches();
        }
 
-       /**
-        * Set a callback via IDatabase::setTransactionListener() on
-        * all current and future master connections of this load balancer
-        *
-        * @param string $name Callback name
-        * @param callable|null $callback
-        * @since 1.28
-        */
        public function setTransactionListener( $name, callable $callback = null ) {
                if ( $callback ) {
                        $this->trxRecurringCallbacks[$name] = $callback;
@@ -1608,29 +1445,10 @@ class LoadBalancer implements ILoadBalancer {
                );
        }
 
-       /**
-        * Make certain table names use their own database, schema, and table prefix
-        * when passed into SQL queries pre-escaped and without a qualified database name
-        *
-        * For example, "user" can be converted to "myschema.mydbname.user" for convenience.
-        * Appearances like `user`, somedb.user, somedb.someschema.user will used literally.
-        *
-        * Calling this twice will completely clear any old table aliases. Also, note that
-        * callers are responsible for making sure the schemas and databases actually exist.
-        *
-        * @param array[] $aliases Map of (table => (dbname, schema, prefix) map)
-        * @since 1.28
-        */
        public function setTableAliases( array $aliases ) {
                $this->tableAliases = $aliases;
        }
 
-       /**
-        * Set a new table prefix for the existing local domain ID for testing
-        *
-        * @param string $prefix
-        * @since 1.28
-        */
        public function setDomainPrefix( $prefix ) {
                $this->localDomain = new DatabaseDomain(
                        $this->localDomain->getDatabase(),
@@ -1642,4 +1460,9 @@ class LoadBalancer implements ILoadBalancer {
                        $db->tablePrefix( $prefix );
                } );
        }
+
+       function __destruct() {
+               // Avoid connection leaks for sanity
+               $this->closeAll();
+       }
 }
index db6df86..ba0a484 100644 (file)
@@ -333,7 +333,7 @@ class Article implements Page {
        function fetchContent() {
                // BC cruft!
 
-               ContentHandler::deprecated( __METHOD__, '1.21' );
+               wfDeprecated( __METHOD__, '1.21' );
 
                if ( $this->mContentLoaded && $this->mContent ) {
                        return $this->mContent;
@@ -1932,12 +1932,13 @@ class Article implements Page {
 
        /**
         * Check if the page can be cached
+        * @param integer $mode One of the HTMLFileCache::MODE_* constants (since 1.28)
         * @return bool
         */
-       public function isFileCacheable() {
+       public function isFileCacheable( $mode = HTMLFileCache::MODE_NORMAL ) {
                $cacheable = false;
 
-               if ( HTMLFileCache::useFileCache( $this->getContext() ) ) {
+               if ( HTMLFileCache::useFileCache( $this->getContext(), $mode ) ) {
                        $cacheable = $this->mPage->getId()
                                && !$this->mRedirectedFrom && !$this->getTitle()->isRedirect();
                        // Extension may have reason to disable file caching on some pages.
index 2308ef0..fe0fffc 100644 (file)
@@ -3735,7 +3735,7 @@ class WikiPage implements Page, IDBAccessObject {
         *
         * @param Content|null $content Optional Content object for determining the
         *   necessary updates.
-        * @return DataUpdate[]
+        * @return DeferrableUpdate[]
         */
        public function getDeletionUpdates( Content $content = null ) {
                if ( !$content ) {
index 1eba141..696facb 100644 (file)
@@ -267,36 +267,60 @@ abstract class SearchEngine {
 
        /**
         * Parse some common prefixes: all (search everything)
-        * or namespace names
+        * or namespace names and set the list of namespaces
+        * of this class accordingly.
         *
         * @param string $query
         * @return string
         */
        function replacePrefixes( $query ) {
+               $queryAndNs = self::parseNamespacePrefixes( $query );
+               if ( $queryAndNs === false ) {
+                       return $query;
+               }
+               $this->namespaces = $queryAndNs[1];
+               return $queryAndNs[0];
+       }
+
+       /**
+        * Parse some common prefixes: all (search everything)
+        * or namespace names
+        *
+        * @param string $query
+        * @return false|array false if no namespace was extracted, an array
+        * with the parsed query at index 0 and an array of namespaces at index
+        * 1 (or null for all namespaces).
+        */
+       public static function parseNamespacePrefixes( $query ) {
                global $wgContLang;
 
                $parsed = $query;
                if ( strpos( $query, ':' ) === false ) { // nothing to do
-                       return $parsed;
+                       return false;
                }
+               $extractedNamespace = null;
 
                $allkeyword = wfMessage( 'searchall' )->inContentLanguage()->text() . ":";
                if ( strncmp( $query, $allkeyword, strlen( $allkeyword ) ) == 0 ) {
-                       $this->namespaces = null;
+                       $extractedNamespace = null;
                        $parsed = substr( $query, strlen( $allkeyword ) );
                } elseif ( strpos( $query, ':' ) !== false ) {
+                       // TODO: should we unify with PrefixSearch::extractNamespace ?
                        $prefix = str_replace( ' ', '_', substr( $query, 0, strpos( $query, ':' ) ) );
                        $index = $wgContLang->getNsIndex( $prefix );
                        if ( $index !== false ) {
-                               $this->namespaces = [ $index ];
+                               $extractedNamespace = [ $index ];
                                $parsed = substr( $query, strlen( $prefix ) + 1 );
+                       } else {
+                               return false;
                        }
                }
+
                if ( trim( $parsed ) == '' ) {
                        $parsed = $query; // prefix was the whole query
                }
 
-               return $parsed;
+               return [ $parsed, $extractedNamespace ];
        }
 
        /**
@@ -648,10 +672,11 @@ abstract class SearchEngine {
         * - default: set to true if this profile is the default
         *
         * @since 1.28
-        * @param $profileType the type of profiles
+        * @param string $profileType the type of profiles
+        * @param User|null $user the user requesting the list of profiles
         * @return array|null the list of profiles or null if none available
         */
-       public function getProfiles( $profileType ) {
+       public function getProfiles( $profileType, User $user = null ) {
                return null;
        }
 
index 2351ab8..ed7c6df 100644 (file)
@@ -1302,6 +1302,7 @@ class SkinTemplate extends Skin {
 
                        if ( $this->showEmailUser( $user ) ) {
                                $nav_urls['emailuser'] = [
+                                       'text' => $this->msg( 'tool-link-emailuser', $rootUser )->text(),
                                        'href' => self::makeSpecialUrlSubpage( 'Emailuser', $rootUser ),
                                        'tooltip-params' => [ $rootUser ],
                                ];
@@ -1312,6 +1313,7 @@ class SkinTemplate extends Skin {
                                $sur->setContext( $this->getContext() );
                                if ( $sur->userCanExecute( $this->getUser() ) ) {
                                        $nav_urls['userrights'] = [
+                                               'text' => $this->msg( 'tool-link-userrights', $this->getUser()->getName() )->text(),
                                                'href' => self::makeSpecialUrlSubpage( 'Userrights', $rootUser )
                                        ];
                                }
index cf0ab1b..0920f68 100644 (file)
@@ -42,7 +42,7 @@
        "tog-enotifminoredits": "Mandame tamién un corréu cuando heba ediciones menores de les páxines y ficheros",
        "tog-enotifrevealaddr": "Amosar la mio direición de corréu nos correos de notificación",
        "tog-shownumberswatching": "Amosar el númberu d'usuarios que tán vixilando la páxina",
-       "tog-oldsig": "Firma esistente:",
+       "tog-oldsig": "La to firma actual:",
        "tog-fancysig": "Tratar la firma como testu wiki (ensin enllaz automáticu)",
        "tog-uselivepreview": "Usar vista previa en tiempu real",
        "tog-forceeditsummary": "Avisame cuando grabe col resume d'edición en blanco",
        "category-file-count-limited": "{{PLURAL:$1El ficheru siguiente ta|Los $1 ficheeros siguientes tán}} na categoría actual.",
        "listingcontinuesabbrev": "cont.",
        "index-category": "Páxines indexaes",
-       "noindex-category": "Páxines non indexaes",
+       "noindex-category": "Páxines sin indexar",
        "broken-file-category": "Páxines con enllaces frañíos a ficheros",
        "about": "Tocante a",
        "article": "Páxina de conteníu",
        "newwindow": "(s'abre nuna ventana nueva)",
        "cancel": "Encaboxar",
        "moredotdotdot": "Más...",
-       "morenotlisted": "Esta llista nun ta completa.",
+       "morenotlisted": "Esta llista puede tar incompleta.",
        "mypage": "Páxina",
        "mytalk": "Alderique",
        "anontalk": "Alderique",
index c0e78e6..6530ebc 100644 (file)
        "log-action-filter-move": "Тып пераносу:",
        "log-action-filter-newusers": "Тып стварэньня рахунку:",
        "log-action-filter-patrol": "Тып патруляваньня:",
+       "log-action-filter-protect": "Тып абароны:",
+       "log-action-filter-rights": "Тып зьмены правоў:",
        "log-action-filter-all": "Усе",
        "log-action-filter-block-block": "Заблякаваць",
        "log-action-filter-block-reblock": "Зьмяненьне блякаваньня",
index c8a6fe0..ac0322a 100644 (file)
        "apisandbox-submit-invalid-fields-title": "Некаторыя палі недапушчальныя",
        "apisandbox-submit-invalid-fields-message": "Калі ласка, выпраўце адзначаныя палі і паспрабуйце ізноў.",
        "apisandbox-results": "Вынікі",
+       "apisandbox-request-url-label": "URL-адрас запыту:",
+       "apisandbox-request-time": "Час запыту: {{PLURAL:$1|$1 мс}}",
+       "apisandbox-results-fixtoken": "Папраўце токен і паўтарыце адпраўку",
        "apisandbox-alert-page": "Палі на гэтай старонцы недапушчальныя.",
        "apisandbox-alert-field": "Значэнне гэтага поля недапушчальнае.",
        "booksources": "Кнігі",
index bc4466a..92c4cb3 100644 (file)
        "watchlistanontext": "Morate biti prijavljeni kako biste vidjeli ili uređivali svoj spisak praćenih članaka.",
        "watchnologin": "Niste prijavljeni",
        "addwatch": "Dodaj na spisak praćenja",
-       "addedwatchtext": "Stranica \"[[:$1]]\" i njena stranica za razgovor dodani su na vaš [[Special:Watchlist|spisak praćenja]].",
+       "addedwatchtext": "Stranica \"[[:$1]]\" i njena stranica za razgovor dodani su na Vaš [[Special:Watchlist|spisak praćenja]].",
+       "addedwatchtext-talk": "\"[[:$1]]\" i njoj pridružena stranica dodane su na Vaš [[Special:Watchlist|spisak praćenja]].",
        "addedwatchtext-short": "Stranica \"$1\" je dodana na vaš spisak praćenja.",
        "removewatch": "Ukloni sa spiska praćenja",
-       "removedwatchtext": "Stranica \"[[:$1]]\" i njena stranica za razgovor uklonjeni su s [[Special:Watchlist|Vašeg spiska praćenja]].",
+       "removedwatchtext": "Stranica \"[[:$1]]\" i njena stranica za razgovor uklonjeni su s Vašeg [[Special:Watchlist|spiska praćenja]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" i njoj pridružena stranica uklonjene su s Vašeg [[Special:Watchlist|spiska praćenja]].",
        "removedwatchtext-short": "Stranica \"$1\" je uklonjena sa vašeg spiska praćenja.",
        "watch": "Prati članak",
        "watchthispage": "Prati ovu stranicu",
index 82cfba2..071a23d 100644 (file)
                        "GnuDoyng"
                ]
        },
-       "tog-underline": "下劃綫鏈接",
-       "tog-hideminor": "囥起最近改變其過幼修改",
-       "tog-hidepatrolled": "囥起最近改變其巡邏修改",
-       "tog-newpageshidepatrolled": "共巡邏視頁趁新建頁列表𡅏囥起去",
+       "tog-underline": "Â-hĕk-siáng lièng-giék",
+       "tog-hideminor": "Káung kī cī-bŏng gì guó-éu siŭ-gāi",
+       "tog-hidepatrolled": "Káung kī cī-bŏng ī giēng-că gì siŭ-gāi",
+       "tog-newpageshidepatrolled": "Káung kī sĭng hiĕk dăng-dăng gà̤-dēng ī-gĭng giēng-că guó gì hiĕk",
        "tog-extendwatchlist": "敆擴展監視單單臺中顯示所有其更改,伓啻最近其更改",
        "tog-usenewrc": "按頁顯示最近修改共監視列表臺中其群組改變",
        "tog-numberheadings": "自動編號其標題",
@@ -38,7 +38,7 @@
        "tog-enotifminoredits": "就㑚講是過幼編輯,也着發電子郵件乞我",
        "tog-enotifrevealaddr": "敆通知郵件臺中顯示我其電子郵件地址",
        "tog-shownumberswatching": "顯示監視用戶其數量",
-       "tog-oldsig": "存在其簽名",
+       "tog-oldsig": "Nṳ̄ còng-câi gì chiĕng-miàng:",
        "tog-fancysig": "共簽名當成維基文本(無自動鏈接)",
        "tog-uselivepreview": "使即時預覽",
        "tog-forceeditsummary": "提醒我行遘蜀萆空白其編輯總結",
        "tog-watchlisthidebots": "囥起監視單其機器人其修改",
        "tog-watchlisthideminor": "囥起監視單其過幼修改",
        "tog-watchlisthideliu": "共已經登錄其用戶其編輯趁監視單𡅏囥起咯",
+       "tog-watchlistreloadautomatically": "Sìng-tō̤ dèu-giông gāi-biéng sèng-hâiu cê̤ṳ-dông gĕng-sĭng gáng-sê-dăng (JavaScript diŏh kŭi lā̤)",
        "tog-watchlisthideanons": "共匿名其用戶其編輯趁監視單𡅏囥起咯",
        "tog-watchlisthidepatrolled": "共巡查其編輯趁監視單𡅏囥起咯",
+       "tog-watchlisthidecategorization": "Káung kī hiĕk gì lôi-biék",
        "tog-ccmeonemails": "共我發乞其他用戶其電子郵件其備份發乞我。",
        "tog-diffonly": "伓使敆下底其顯示𣍐蜀様其地方顯示頁面內容",
        "tog-showhiddencats": "㪗藏類別",
        "tog-norollbackdiff": "敆回滾其時候,無叕𣍐蜀様其地方",
        "tog-useeditwarning": "我編輯頁面其時候離開,起動警告我蜀下",
-       "tog-prefershttps": "躒入以後始終使安全連接",
+       "tog-prefershttps": "Láuk-diē ī-hâiu sṳ̄-cṳ̆ng sāi ăng-cuòng lièng-giék",
        "underline-always": "直頭",
        "underline-never": "頭𡅏無",
        "underline-default": "皮膚或者瀏覽器默認其",
        "october-date": "十月$1號",
        "november-date": "十一月$1號",
        "december-date": "十二月$1號",
+       "period-am": "AM",
+       "period-pm": "PM",
        "pagecategories": "{{PLURAL:$1}} Lôi-biék",
        "category_header": "「$1」類別下底其頁面",
        "subcategories": "子類別",
        "category-media-header": "「$1」類別下底其媒體",
        "category-empty": "''茲類別下底現在無文章也無媒體。''",
-       "hidden-categories": "{{PLURAL:$1}} bĭk ké̤ṳk káung kī gì lui-biék",
+       "hidden-categories": "{{PLURAL:$1}} bĭk ké̤ṳk káung kī gì lôi-biék",
        "hidden-category-category": "已經囥起其類別",
        "category-subcat-count": "{{PLURAL:$2|茲萆分類僅包括下底蜀萆子分類|茲分類有 {{PLURAL:$1|子分類|$1 萆子分類}},總計 $2 萆。}}",
        "category-subcat-count-limited": "茲蜀萆類別下底有子類別{{PLURAL:$1}}",
        "category-file-count-limited": "下底其茲$1萆文件都敆茲蜀萆類別𡅏。{{PLURAL:$1}}",
        "listingcontinuesabbrev": "(繼續前斗)",
        "index-category": "索引其頁面",
-       "noindex-category": "未索引其頁面",
+       "noindex-category": "Muôi sáuk-īng gì hiĕk",
        "broken-file-category": "獃其文件鏈接其頁面",
        "about": "關於",
        "article": "文章",
        "newwindow": "(敆新窗口打開)",
        "cancel": "取消",
        "moredotdotdot": "更価...",
-       "morenotlisted": "茲蜀萆單單𣍐完整。",
+       "morenotlisted": "Ciā dăng-dăng mâ̤ uòng-cīng.",
        "mypage": "頁面",
        "mytalk": "我其討論",
-       "anontalk": "茲隻IP其討論頁",
+       "anontalk": "Páng-gōng",
        "navigation": "Īng-dô̤:",
        "and": "&#32;gâe̤ng",
        "qbfind": "討",
        "unprotectthispage": "改變茲蜀頁其保護狀態",
        "newpage": "新頁",
        "talkpage": "討論茲頁",
-       "talkpagelinktext": "tō̤-lâung",
+       "talkpagelinktext": "páng-gōng",
        "specialpage": "特殊頁",
        "personaltools": "Gó̤-ìng gì gă-sĭ-huă",
        "articlepage": "覷蜀覷內容頁面",
        "pool-timeout": "等待鎖定其時間遘了",
        "pool-queuefull": "隊列池已經滿了",
        "pool-errorunknown": "𣍐曉什乇綻咯",
+       "poolcounter-usage-error": "Ê̤ṳng-huák chó̤-nguô: $1",
        "aboutsite": "Guăng-ṳ̀ {{SITENAME}}",
        "aboutpage": "Project:Guăng-ṳ̀",
        "copyright": "內容會使敆$1下底會使獲得遘,若無會給出其它提示。",
        "disclaimers": "Mò̤-hô-cáik sĭng-mìng",
        "disclaimerpage": "Project:Mò̤-hô-cáik sĭng-mìng",
        "edithelp": "修改保護",
+       "helppage-top-gethelp": "Bŏng-cô",
        "mainpage": "Tàu Hiĕk",
        "mainpage-description": "Tàu Hiĕk",
        "policy-url": "Project:政策",
        "content-model-text": "純文本",
        "content-model-javascript": "JavaScript",
        "content-model-css": "CSS",
-       "undo-summary": "取消[[Special:Contributions/$2|$2]]([[User talk:$2|Tō̤-lâung]])其$1修改",
+       "undo-summary": "Chṳ̄-siĕu [[Special:Contributions/$2|$2]]([[User talk:$2|Páng-gōng]])sū có̤ gì siŭ-gāi $1",
        "viewpagelogs": "看茲頁其歷史",
        "nohistory": "茲頁無修改歷史。",
        "currentrev": "最新版本",
index ed030ec..81380ce 100644 (file)
        "about": "Heqa cı de",
        "article": "Pela zerreki",
        "newwindow": "(pençereyê newey de beno a)",
-       "cancel": "Bıtexelne",
+       "cancel": "Bıterkın",
        "moredotdotdot": "Vêşi...",
        "morenotlisted": "Vêşi lista nêbi...",
        "mypage": "Pele",
        "specialpage": "Perra bağsi",
        "personaltools": "Hacetê şexsiy",
        "articlepage": "Pera zerreki bıvin",
-       "talk": "Werênayış",
+       "talk": "Vaten",
        "views": "Asayışi",
        "toolbox": "Haceti",
        "userpage": "Pela karberi bıvêne",
        "summary": "Xulasa:",
        "subject": "Mewzu:",
        "minoredit": "Vurriyayışo werdiyo",
-       "watchthis": "Na pele seyr ke",
+       "watchthis": "Perrer bıpaw",
        "savearticle": "Qeyd ke",
        "savechanges": "Vurnayışan qeyd ke",
        "publishpage": "Perer bıhesırne",
        "viewprevnext": "($1 {{int:pipe-separator}} $2) ($3) bıvênên",
        "searchmenu-exists": "''Ena 'Wikipediya de ser \"[[:$1]]\" yew pel esto'''",
        "searchmenu-new": "<strong>Na wiki de pela \"[[:$1]]\" vıraze!</strong> {{PLURAL:$2|0=|Sewbina pela ke şıma geyrayê cı aye bıvênê.|Yew zi neticanê cıgeyrayışê xo bıvênê.}}",
-       "searchprofile-articles": "Zerrekê pelan",
+       "searchprofile-articles": "Perrê muhteway",
        "searchprofile-images": "Zafınmedya",
        "searchprofile-everything": "Pêro çi",
        "searchprofile-advanced": "Herayen",
        "prefs-labs": "Xacetê labs",
        "prefs-user-pages": "Pelê karberi",
        "prefs-personal": "Pela karberi",
-       "prefs-rc": "Vurriyayışê peyêni",
+       "prefs-rc": "Vırnayışë newey",
        "prefs-watchlist": "Lista seyrkerdışi",
        "prefs-editwatchlist": "Lista seyrkerdışi bıvurne",
        "prefs-editwatchlist-label": "Listey serkerdışanê cıkewtışi timar kerê",
        "nchanges": "$1 {{PLURAL:$1|vurnayış|vurnayışi}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ziyaretê peyêni ra nata}}",
        "enhancedrc-history": "tarix",
-       "recentchanges": "Vurriyayışê peyêni",
+       "recentchanges": "Vırnayışë newey",
        "recentchanges-legend": "Tercihê vurnayışanê peyênan",
        "recentchanges-summary": "Wiki sero vurriyayışê peyêni asenê.",
        "recentchanges-noresult": "Goreyê kriteranê kıfşkerdeyan ra qet yew vurnayış nêvêniya.",
        "randomredirect": "Serçarnayışo rastameye",
        "randomredirect-nopages": "Cayê nameyê \"$1\" de serşıkıtışi çıniyê.",
        "statistics": "İstatistiki",
-       "statistics-header-pages": "İstatistikê pele",
+       "statistics-header-pages": "İstatıstıkê perrer",
        "statistics-header-edits": "İstatistikê vurnayışan",
        "statistics-header-users": "İstatistikê karberi",
        "statistics-header-hooks": "Yewbina istatistiki",
-       "statistics-articles": "Pelê zerreki",
+       "statistics-articles": "Meqaley",
        "statistics-pages": "Peli",
        "statistics-pages-desc": "Wiki de peley pêro, kategoriy, hetenayışi wesaire...",
        "statistics-files": "Dosyayê bar biye",
index 7dd59f3..02def5d 100644 (file)
@@ -14,7 +14,7 @@
        "tog-hideminor": "अहिलका मामूली सम्पादनलाई लुकाउन्या",
        "tog-hidepatrolled": "गस्ती(patrolled)सम्पादनलाई लुकाउन्या",
        "tog-newpageshidepatrolled": "गस्ती गरिया पानानलाई नयाँ पाना  सूचीबठेई लुकाउन्या",
-       "tog-hidecategorization": "पà¥\83षà¥\8dठहरà¥\82à¤\95à¥\8b à¤¶à¥\8dरà¥\87णà¥\80à¤\95रण à¤¹à¤\9fाया",
+       "tog-hidecategorization": "पनà¥\8dनाà¤\85नà¥\8b à¤¶à¥\8dरà¥\87णà¥\80à¤\95रण à¤²à¥\81à¤\95ाऽ",
        "tog-extendwatchlist": "निगरानी सूचीलाई सबै परिवर्तन धेकुन्या गरी बढुन्या , ऐईलका बाहेक",
        "tog-usenewrc": "पानाका अहिलका  परिवर्तन र अवलोकन सूचीका आधारमी सामूहिक परिवर्तनहरू",
        "tog-numberheadings": "शीर्षकहरूलाई स्वत:अङ्कित गर",
@@ -46,7 +46,7 @@
        "tog-watchlistreloadautomatically": "जज्ज्याँलै फिल्टर बदेलिन्छ इच्छासूची आफुइ रिलोड अर: (जावास्क्रिप्ट चायीन्छ)",
        "tog-watchlisthideanons": "अज्ञात प्रयोगकर्ताहरूबाट गरिएको सम्पादन ध्यान सूचीबठेई लुकाउन्या",
        "tog-watchlisthidepatrolled": "बोट सम्पादनहरू ध्यान सूचीबठेई लुकाउन्या",
-       "tog-watchlisthidecategorization": "पà¥\83षà¥\8dठहरà¥\82à¤\95à¥\8b à¤¶à¥\8dरà¥\87णà¥\80à¤\95रण à¤²à¥\81à¤\95à¥\8cनà¥\8dया",
+       "tog-watchlisthidecategorization": "पनà¥\8dनाà¤\85नà¥\8b à¤¶à¥\8dरà¥\87णà¥\80à¤\95रण à¤²à¥\81à¤\95ाऽ",
        "tog-ccmeonemails": "मुईले अन्य प्रयोगकर्ताहरूलाई पठाउन्या इ-मेलको प्रतिलिपि मुईलाई पठाउन्या",
        "tog-diffonly": "तलका पानाहरुको भिन्नहरू सामग्री नदेखाउन्या",
        "tog-showhiddencats": "लुकाइएका श्रेणीहरू धेखाउन्या",
        "createacct-yourpasswordagain-ph": "आँजि पासवर्ड भरऽ",
        "userlogin-remembermypassword": "मुलाई अघाडी झान्या काम गराइराख्या",
        "userlogin-signwithsecure": "सुक्षित जडान प्रयोग गद्द्या",
-       "cannotlogin-title": "à¤\85à¤\88ल à¤­à¤¿à¤¤à¤° à¤\9dान à¤¨à¤¾à¤\87à¤\81 à¤ªà¤¾à¤\88नो",
+       "cannotlogin-title": "भितर à¤\9dान à¤¨à¤¾à¤\87à¤\81सà¤\95ियो",
        "cannotlogin-text": "येइमी लगइन सम्भव नाइथिन।",
        "cannotloginnow-title": "अईल भितर झान नाइँ पाईनो",
        "cannotloginnow-text": "भितर जान असंभव छ जब प्रयोग $1|",
        "continue-editing": "सम्पादन क्षेत्रमी जाओ",
        "editing": "$1 सम्पादन अरीन्नाछ़",
        "creating": "$1 बनाइँदै",
-       "editingsection": "$1 (à¤\96णà¥\8dड) à¤¸à¤®à¥\8dपादन à¤\97रिदà¥\88",
+       "editingsection": "$1 (à¤\96णà¥\8dड) à¤¸à¤®à¥\8dपादन à¤\85रà¥\80नà¥\8dनाà¤\9b़",
        "editingcomment": "$1 सम्पादन गर्दै(नयाँ खण्ड)",
        "editconflict": "सम्पादन बाँझ्यो: $1",
        "yourtext": "तमरा पाठहरू",
        "grouppage-user": "{{ns:project}}:प्रयोगकर्ताहरू",
        "grouppage-autoconfirmed": "{{ns:project}}:स्वतःपुष्टि भयाऽ प्रयोगकर्ताअन",
        "grouppage-bot": "{{ns:project}}:बोटअन",
-       "grouppage-sysop": "{{ns:project}}:पà¥\8dरबनà¥\8dधà¤\95हरà¥\82",
+       "grouppage-sysop": "{{ns:project}}:वà¥\8dयवसà¥\8dथापà¤\95à¤\85न",
        "grouppage-bureaucrat": "{{ns:project}}:प्रशासकअन",
        "grouppage-suppress": "{{ns:project}}:लुकौन्या",
        "right-read": "पृष्ठहरू पढ",
        "import-logentry-upload-detail": "$1 {{PLURAL:$1|संशोधन|संशोधनहरू}} आयात भयो",
        "tooltip-pt-userpage": "{{GENDER:|तमरो प्रयोगकर्ता}} पान्नो",
        "tooltip-pt-anonuserpage": "तमी जो IP ठेगानाको रुपमी सम्पादन गद्दै छौ , त्यैको प्रयोगकर्ता पानो निम्न छ :",
-       "tooltip-pt-mytalk": "{{GENDER:|तमरà¥\8b}} à¤\95à¥\81रडà¥\80à¤\95ानà¥\80 à¤ªà¤¾नो",
+       "tooltip-pt-mytalk": "{{GENDER:|तमरà¥\8b}} à¤\95à¥\81रणिà¤\95ाà¤\86नà¥\80 à¤ªà¤¾à¤¨à¥\8dनो",
        "tooltip-pt-preferences": "{{GENDER:|तमरी}} अभिरुचि",
        "tooltip-pt-watchlist": "पृष्ठहरूको सूची जैका फेरबदलहरुलाई तमले पहरा गरिराखेका छौ ।",
        "tooltip-pt-mycontris": "{{GENDER:|तमरा}} योगदानअनऐ सूची",
index e338987..f43b50c 100644 (file)
        "badsig": "Erōr int la fîrma mìa standard, verifichêr i tag HTML.",
        "badsiglength": "La fîrma siēlta l'é trôp lònga, l'an dēv mìa andêr d'ed sōver di $1 {{PLURAL:$1|carâter}}.",
        "yourgender": "Cme arfêres a té?",
-       "gender-unknown": "Indiferèint",
+       "gender-unknown": "Al progrâma, int al numinêret e tōti 'l vôlti ch' al pōl, al druvarà dal parôli sèinsa gèner.",
        "gender-male": "L'é registrê in sém a {{SITENAME}}",
        "gender-female": "L'é registrêda in sém a {{SITENAME}}",
        "prefs-help-gender": "L'impustasiòun ed cla preferèinsa ché l'é a siēlta. Al progrâma al drōva cól valōr ché per parlêr cun tè e numinêret cun chiêter cun al druvêr al gèner ed gramâtica gióst. Cl'infurmasiòun ché la srà póblica.",
        "userrights": "Gestiòun di permès relatîv a j utèint",
        "userrights-lookup-user": "Gestiòun di gróp utèint",
        "userrights-user-editname": "Mèt dèinter al nòm utèint:",
-       "editusergroup": "Mudéfica gróp utèint",
-       "editinguser": "Mudéfica i dirét utèint ed l' utèint <strong>[[User:$1|$1]]</strong> $2",
+       "editusergroup": "Mudéfica i gróp {{GENDER:$1|utèint}}",
+       "editinguser": "Mudéfica i dirét utèint ed j {{GENDER:$1|utèint}}<strong>[[User:$1|$1]]</strong> $2",
        "userrights-editusergroup": "Mudéfica gróp utèint",
-       "saveusergroups": "Sêlva gróp utèint",
+       "saveusergroups": "Sêlva i gróp{{GENDER:$1|utèint}}",
        "userrights-groupsmember": "Al fà pêrt {{PLURAL:$1|al gróp|ai gróp}}:",
        "userrights-groupsmember-auto": "Al fà pêrt ed sicûr a:",
        "userrights-groups-help": "L'é pusébil mudifichêr i gróp in dó fà pêrt l'utèint. \n*'Na caşèla sernîda la sègna a che gróp al fà pêrt l'utèint. \n*'Na caşèla mìa serrnîda la sègna che l'utèin al fà mìa pêrt al gróp. \n*Al sègn * al sègna ch' an n'é m'a pusébil scanşlêr che l'utèin al fà pêrt al gróp dōp avèirel sgnê (o invicivêrsa).",
        "userrights-changeable-col": "Gróp ch'es pōlen mudifichêr.",
        "userrights-unchangeable-col": "Gróp ch'an 's pōlen mìa mudifichêr.",
        "userrights-conflict": "Cuntrâst ed mudéfica di dirét utèint! Cuntròla e cunfērma al tó mudéfichi.",
-       "userrights-removed-self": "T'é tôt via cun sucès i tō dirét. E dòunca, an 't prê pió andêr dèinter a cla pàgina ché.",
+       "userrights-removed-self": "T'é tôt via i tō dirét. E dòunca, an 't prê pió andêr dèinter a cla pàgina ché.",
        "group": "Gróp:",
        "group-user": "Utèint",
        "group-autoconfirmed": "Utèint cunvalidê da per ló",
index 67e6491..b3781c2 100644 (file)
        "talk": "Discussion",
        "views": "Views",
        "toolbox": "Tools",
+       "tool-link-userrights": "Change {{GENDER:$1|user}} groups",
+       "tool-link-emailuser": "Email this {{GENDER:$1|user}}",
        "userpage": "View user page",
        "projectpage": "View project page",
        "imagepage": "View file page",
index f7eea23..29707f2 100644 (file)
        "prevn-title": "{{PLURAL:$1|Antaŭa $1 rezulto|Antaŭaj $1 rezultoj}}",
        "nextn-title": "{{PLURAL:$1|Posta $1 rezulto|Postaj $1 rezultoj}}",
        "shown-title": "Montri {{PLURAL:$1|$1 rezulton|$1 rezultojn}} en paĝo",
-       "viewprevnext": "Montri ($1 {{int:pipe-separator}} $2) ($3).",
+       "viewprevnext": "Montri ($1 {{int:pipe-separator}} $2) ($3)",
        "searchmenu-exists": "'''Estas paĝo nomita \"[[:$1]]\" en ĉi tiu vikio'''",
        "searchmenu-new": "<strong>Krei la paĝon \"[[:$1]]\" en ĉi tiu vikio!</strong>{{PLURAL:$2|0=|Vidu ankaŭ la paĝon trovitan per via serĉo.|Vidu ankaŭ la trovitajn serĉrezultojn.}}",
        "searchprofile-articles": "Enhavaj paĝoj",
        "isredirect": "alidirektilo",
        "istemplate": "inkludo",
        "isimage": "ligilo al dosiero",
-       "whatlinkshere-prev": "{{PLURAL:$1|antaŭa|antaŭaj $1}}",
-       "whatlinkshere-next": "{{PLURAL:$1|posta|postaj $1}}",
+       "whatlinkshere-prev": "{{PLURAL:$1|antaŭan|antaŭajn $1}}",
+       "whatlinkshere-next": "{{PLURAL:$1|postan|postajn $1}}",
        "whatlinkshere-links": "← ligiloj",
        "whatlinkshere-hideredirs": "$1 alidirektilojn",
-       "whatlinkshere-hidetrans": "$1 transinkluzivaĵojn",
+       "whatlinkshere-hidetrans": "$1 inkludojn",
        "whatlinkshere-hidelinks": "$1 ligilojn",
        "whatlinkshere-hideimages": "$1 dosieraj ligoj",
        "whatlinkshere-filters": "Filtriloj",
index e9885dd..28843a4 100644 (file)
@@ -61,7 +61,7 @@
        "tog-enotifwatchlistpages": "לשלוח אליי דוא\"ל כאשר משתנה דף או קובץ ברשימת המעקב שלי",
        "tog-enotifusertalkpages": "לשלוח אליי דוא\"ל כאשר נעשה שינוי בדף שיחת המשתמש שלי",
        "tog-enotifminoredits": "לשלוח אליי דוא\"ל גם על עריכות משניות בדפים וקבצים",
-       "tog-enotifrevealaddr": "×\97ש×\99פת כתובת הדוא\"ל שלי בהתראות דוא\"ל",
+       "tog-enotifrevealaddr": "×\9c×\97ש×\95×£ ×\90ת כתובת הדוא\"ל שלי בהתראות דוא\"ל",
        "tog-shownumberswatching": "הצגת מספר המשתמשים העוקבים",
        "tog-oldsig": "החתימה הנוכחית שלך:",
        "tog-fancysig": "התייחסות לחתימה כקוד ויקי (ללא קישור אוטומטי)",
        "actions": "פעולות",
        "namespaces": "מרחבי שם",
        "variants": "גרסאות שפה",
-       "navigation-heading": "תפר×\99×\98 ×\94× ×\99×\95×\95×\98",
+       "navigation-heading": "תפריט ניווט",
        "errorpagetitle": "שגיאה",
        "returnto": "חזרה לדף $1.",
        "tagline": "מתוך {{SITENAME}}",
        "updatedmarker": "עודכן מאז ביקורך האחרון",
        "printableversion": "גרסה להדפסה",
        "permalink": "קישור קבוע",
-       "print": "×\92רס×\94 ×\9c×\94×\93פס×\94",
+       "print": "הדפסה",
        "view": "צפייה",
        "view-foreign": "הצגה ב{{GRAMMAR:תחילית|$1}}",
        "edit": "עריכה",
index 71c2dd4..71e1b0c 100644 (file)
@@ -47,7 +47,7 @@
        "tog-enotifminoredits": "Испраќај ми е-пошта и за ситни промени во страниците и податотеките",
        "tog-enotifrevealaddr": "Откриј ја мојата е-поштенска адреса во пораките за известување",
        "tog-shownumberswatching": "Прикажи го бројот на корисници кои набљудуваат",
-       "tog-oldsig": "Ð\9fостоечки потпис:",
+       "tog-oldsig": "Ð\92аÑ\88иоÑ\82 Ð¿остоечки потпис:",
        "tog-fancysig": "Сметај го потписот за викитекст (без автоматска врска)",
        "tog-uselivepreview": "Користи преглед во живо",
        "tog-forceeditsummary": "Извести ме кога нема опис на промените",
        "newwindow": "(се отвора во нов прозорец)",
        "cancel": "Откажи",
        "moredotdotdot": "Повеќе...",
-       "morenotlisted": "Ð\9eвоÑ\98 Ñ\81пиÑ\81ок Ð½Ðµ Ðµ целосен.",
+       "morenotlisted": "Ð\9eвоÑ\98 Ñ\81пиÑ\81ок Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ðµ Ð½Ðµцелосен.",
        "mypage": "Страница",
        "mytalk": "разговор",
        "anontalk": "Разговор",
index b2f84c0..e2b8e1b 100644 (file)
@@ -41,6 +41,8 @@
        "tog-watchdefault": "ကျွန်ုပ် တည်းဖြတ်ခဲ့သည့် စာမျက်နှာများနှင့် ဖိုင်များကို စောင့်ကြည့်စာရင်းသို့  ပေါင်းထည့်ပါ။",
        "tog-watchmoves": "ကျွန်ုပ်ရွှေ့လိုက်သော စာမျက်နှာများနှင့် ဖိုင်များကို စောင့်ကြည့်စာရင်းသို့ ပေါင်းထည့်ရန်",
        "tog-watchdeletion": "ဖျက်လိုက်သောစာမျက်နှာများနှင့် ဖိုင်များကို စောင့်ကြည့်စာရင်သို့ ပေါင်းထည့်ရန်",
+       "tog-watchuploads": "ကျွန်ုပ်တင်လိုက်သော ဖိုင်အသစ်များအား ကျွန်ုပ်၏ စောင့်ကြည့်စာရင်းသို့ ပေါင်းထည့်ရန်",
+       "tog-watchrollback": "နောက်ပြန်ပြင်ခြင်း ဆောင်ရွက်လိုက်သည့် စာမျက်နှာများအား ကျွန်ုပ်၏ စောင့်ကြည့်စာရင်းသို့ ပေါင်းထည့်ရန်",
        "tog-minordefault": "တည်းဖြတ်မှုအားလုံးသည် အရေးမကြီးသော တည်းဖြတ်မှုဟု ပုံသေသတ်မှတ်ရန်",
        "tog-previewontop": "တည်းဖြတ်သည့်အကွက်မတိုင်မီ နမူနာကို ပြရန်",
        "tog-previewonfirst": "ပထမတည်းဖြတ်မှုတွင် နမူနာကို ပြရန်",
@@ -49,7 +51,7 @@
        "tog-enotifminoredits": "စာမျက်နှာများနှင့် ဖိုင်များ၏ အရေးမကြီးသော တည်းဖြတ်မှုများကိုလည်း အီးမေးပို့ရန်",
        "tog-enotifrevealaddr": " အသိပေးချက်အီးမေးများတွင် ကျွန်ုပ်၏ အီးမေးလိပ်စာကို ဖော်ပြရန်",
        "tog-shownumberswatching": "စောင့်ကြည့်နေသော အသုံးပြုသူအရေအတွက်ကို ပြရန်",
-       "tog-oldsig": "á\80\9bá\80¾á\80­á\80\94á\80¾á\80\84á\80·á\80ºá\80\95á\80¼á\80®á\80¸á\80\9eá\80¬á\80¸ á\80\9cá\80\80á\80ºá\80\99á\80¾á\80\90á\80º -",
+       "tog-oldsig": "á\80\9eá\80\84á\80ºá\81\8f á\80\9bá\80¾á\80­á\80\94á\80¾á\80\84á\80·á\80ºá\80\95á\80¼á\80®á\80¸á\80\9eá\80¬á\80¸ á\80\9cá\80\80á\80ºá\80\99á\80¾á\80\90á\80º:",
        "tog-fancysig": "လက်မှတ်ကို ဝီကီလင့်အဖြစ် သတ်မှတ်ရန် (အလိုအလျောက်လင့်မပါဘဲနှင့်)",
        "tog-forceeditsummary": "တည်းဖြတ်အတိုချုပ် ဗလာဖြစ်နေလျှင် သတိပေးရန်",
        "tog-watchlisthideown": "ကျွန်ုပ်၏ တည်းဖြတ်မှုများကို စောင့်ကြည့်စာရင်းမှ ဝှက်ထားရန်",
@@ -63,7 +65,7 @@
        "tog-diffonly": "ကွဲပြားမှုများအောက်ရှိ စာမျက်နှာတွင်ပါဝင်သည်များကို မပြပါနှင့်",
        "tog-showhiddencats": "ဝှက်ထားသော ကဏ္ဍများကို ပြရန်",
        "tog-useeditwarning": "မသိမ်းရသေးသော ပြောင်းလဲမှုများ နှင့် တည်းဖြတ်ဆဲစာမျက်နှာမှ ထွက်သွားလျှင် သတိပေးပါ",
-       "tog-prefershttps": "log in ဝင်တိုင်း လုံခြုံသော ဆက်သွယ်မှုကို အသုံးပြုရန်",
+       "tog-prefershttps": "လော့ဂ်အင်ဝင်ချိန်တွင် လုံခြုံသော ဆက်သွယ်မှုကို အမြဲတမ်း အသုံးပြုရန်",
        "underline-always": "အမြဲ",
        "underline-never": "ဘယ်သောအခါမျှ",
        "underline-default": "ဘရောက်ဆာ သို့ Skin default အတိုင်း",
        "category-file-count-limited": "အောက်ပါ {{PLURAL:$1|စာမျက်နှာ|$1 စာမျက်နှာများ}} သည် လက်ရှိစာမျက်နှာတွင် ရှိသည်။",
        "listingcontinuesabbrev": "ပံ့ပိုး",
        "index-category": "အက္ခရာစဉ် စာမျက်နှာများ",
-       "noindex-category": "á\80¡á\80\80á\80¹á\80\81á\80\9bá\80¬á\80\85á\80\89á\80º á\80\85á\80¬á\80\99á\80»á\80\80á\80ºá\80\94á\80¾á\80¬á\80\99á\80»á\80¬á\80¸á\80\99á\80\9bá\80¾á\80­",
+       "noindex-category": "á\80¡á\80\80á\80¹á\80\81á\80\9bá\80¬á\80\99á\80\85á\80\89á\80ºá\80\91á\80¬á\80¸á\80\9eá\80±á\80¬ á\80\85á\80¬á\80\99á\80»á\80\80á\80ºá\80\94á\80¾á\80¬á\80\99á\80»á\80¬á\80¸",
        "broken-file-category": "ကျိုးပျက်နေသော ဖိုင်လင့်များပါသည့် စာမျက်နှာများ",
        "about": "အကြောင်း",
        "article": "စာမျက်နှာ",
        "newwindow": "(ဝင်းဒိုးအသစ်တခုကိုဖွင့်ရန်)",
        "cancel": "မ​လုပ်​တော့​",
        "moredotdotdot": "နောက်ထပ်...",
-       "morenotlisted": "ဤစာရင်းမှာ မပြည့်စုံပါ။",
+       "morenotlisted": "á\80¤á\80\85á\80¬á\80\9bá\80\84á\80ºá\80¸á\80\99á\80¾á\80¬ á\80\99á\80\95á\80¼á\80\8aá\80·á\80ºá\80\85á\80¯á\80¶á\80\94á\80­á\80¯á\80\84á\80ºá\80\95á\80«á\81\8b",
        "mypage": "စာမျက်နှာ",
        "mytalk": "ဆွေးနွေးချက်",
        "anontalk": "ဆွေးနွေးရန်",
        "directorycreateerror": "လမ်းညွှန် \"$1\" ကို ဖန်တီးမရနိုင်ပါ။",
        "filenotfound": "ဖိုင် \"$1\" ကို ရှာမတွေ့ပါ။",
        "formerror": "အမှား - ဖောင်သွင်းနိုင်ခြင်းမရှိပါ",
+       "badarticleerror": "ဤလုပ်ဆောင်မှုအား ဤစာမျက်နှာတွင် လုပ်ဆောင်၍ မရနိုင်ပါ။",
        "cannotdelete": "\"$1\" စာမျက်နှာ သို့မဟုတ် ဖိုင်ကို ဖျက်၍ မရပါ။\nတစ်စုံတစ်ဦးမှ ဖျက်နှင့်ပြီး ဖြစ်နိုင်ပါသည်။",
        "cannotdelete-title": "\"$1\" စာမျက်နှာကို ဖျက်၍ မရပါ",
+       "delete-hook-aborted": "ရှင်းလင်းပြချက် မပေးထားပါ။",
        "badtitle": "ညံ့ဖျင်းသော ခေါင်းစဉ်",
        "badtitletext": "တောင်းဆိုထားသော စာမျက်နှာ ခေါင်းစဉ်သည် တရားမဝင်ပါ (သို့) ဗလာဖြစ်နေသည် (သို့) အခြားဘာသာများ(inter-language or inter-wiki title)သို့ မှားယွင်းစွာ လင့်ချိတ်ထားသည်။",
        "viewsource": "ရင်းမြစ်ကို ကြည့်ရန်",
        "viewsource-title": "$1၏ ရင်းမြစ်ကို ကြည့်ရန်",
        "protectedpagetext": "ဤစာမျက်နှာအား တည်းဖြတ်ခြင်းနှင့် အခြားလုပ်ဆောင်မှုများ မလုပ်ဆောင်နိုင်အောင် ကာကွယ်ထားသည်။",
+       "viewsourcetext": "ဤစာမျက်နှာ၏ ရင်းမြစ်ကို ကြည့်ရှု၍ ကူးယူနိုင်သည်။",
+       "viewyourtext": "ဤစာမျက်နှာရှိ <strong>သင့်တည်းဖြတ်မှုများ</strong>၏ ရင်းမြစ်ကို ကြည့်ရှုပြီး ကူးယူနိုင်သည်။",
        "namespaceprotected": "'''$1''' စာညွှန်းဖြင့် စာမျက်နှာကို တည်းဖြတ်ရန် ခွင့်ပြုချက် မရှိပါ။",
        "mycustomcssprotected": "ဤ CSS စာမျက်နှာကို သင်တည်းဖြတ်ပြင်ဆင်ခွင့် မရှိပါ။",
        "mycustomjsprotected": "ဤ JavaScript စာမျက်နှာကို သင်တည်းဖြတ်ပြင်ဆင်ခွင့် မရှိပါ။",
        "others": "အခြား",
        "pageinfo-language": "စာမျက်နှာ စာကိုယ် ဘာသာစကား",
        "pageinfo-toolboxlink": "စာမျက်နှာ အချက်အလက်များ",
+       "markaspatrolleddiff": "စောင့်ကြပ်စစ်ဆေးပြီးကြောင်း မှတ်သားရန်",
+       "markaspatrolledtext": "ဤစာမျက်နှာအား စောင့်ကြပ်စစ်ဆေးပြီးကြောင်း မှတ်သားရန်",
        "filedeleteerror-short": "ဖိုင်ဖျက်ရာတွင် အမှားအယွင်း - $1",
        "previousdiff": "← တည်းဖြတ်မူ အဟောင်း",
        "nextdiff": "ပိုသစ်သော တည်းဖြတ်မှု",
index 163b613..4ec5cec 100644 (file)
        "talk": "Used as display name for the tab to all {{msg-mw|Talk}} pages. These pages accompany all content pages and can be used for discussing the content page. Example: [[Talk:Example]].\n\nSee also:\n* {{msg-mw|Talk}}\n* {{msg-mw|Accesskey-ca-talk}}\n* {{msg-mw|Tooltip-ca-talk}}\n{{Identical|Discussion}}",
        "views": "Subtitle for the list of available views, for the current page. In \"monobook\" skin the list of views are shown as tabs, so this sub-title is not shown. For an example, see [{{canonicalurl:Main_Page|useskin=simple}} Main Page using simple skin].\n\n'''Note:''' This is \"views\" as in \"appearances\"/\"representations\", '''not''' as in \"visits\"/\"accesses\".\n{{Identical|View}}",
        "toolbox": "The title of the toolbox below the search menu.\n{{Identical|Tool}}",
+       "tool-link-userrights": "Link to [[Special:UserRights]] (user rights management) in the sidebar toolbox.\n\nParameters:\n* $1 - Name of user who would have their rights changed",
+       "tool-link-emailuser": "Link to [[Special:EmailUser]] (email user tool) in the sidebar toolbox.\n\nParameters:\n* $1 - Name of user who would receive the email\n\nSee also:\n* {{msg-mw|Emailuser-title-target}}",
        "userpage": "Used in user talk pages as the text of the link to the user page, with the Cologne Blue skin.",
        "projectpage": "Used as link text in Talk page of project page with the Cologne Blue skin.",
        "imagepage": "Used as link text in Talk page of file page.",
index be3713b..7d136f6 100644 (file)
        "tog-enotifminoredits": "Уведомлять даже при незначительных изменениях страниц и файлов",
        "tog-enotifrevealaddr": "Показывать мой почтовый адрес в сообщениях оповещения",
        "tog-shownumberswatching": "Показывать число участников, включивших страницу в свой список наблюдения",
-       "tog-oldsig": "Текущая подпись:",
+       "tog-oldsig": "Ð\92аÑ\88а Ñ\82екущая подпись:",
        "tog-fancysig": "Собственная вики-разметка подписи (без автоматической ссылки)",
        "tog-uselivepreview": "Использовать быстрый предварительный просмотр",
        "tog-forceeditsummary": "Предупреждать, когда не заполнено поле описания правки",
        "newwindow": "&nbsp;(в новом окне)",
        "cancel": "Отменить",
        "moredotdotdot": "Далее…",
-       "morenotlisted": "ЭÑ\82оÑ\82 Ñ\81пиÑ\81ок Ð½ÐµÐ¿Ð¾Ð»Ð¾Ð½.",
+       "morenotlisted": "ЭÑ\82оÑ\82 Ñ\81пиÑ\81ок Ð¼Ð¾Ð¶ÐµÑ\82 Ð±Ñ\8bÑ\82Ñ\8c Ð½ÐµÐ¿Ð¾Ð»Ð½Ñ\8bм.",
        "mypage": "Страница",
        "mytalk": "Обсуждение",
        "anontalk": "Обсуждение",
index 88791bc..791e6e4 100644 (file)
        "protect": "محفوظ",
        "protect_change": "تبدیل کرو",
        "protectthispage": "اس صفحےکومحفوظ کریں",
-       "unprotect": "تحÙ\81ظ میں تبدیلی",
+       "unprotect": "Ø­Ù\81اظت میں تبدیلی",
        "unprotectthispage": "اِسے صفحے کی تحفظ تبدیل کریں",
        "newpage": "نیا صفحہ",
        "talkpage": "اس صفحہ پر تبادلۂ خیال کریں",
        "nowiki_sample": "غیرشکلبندشدہ متن یہاں درج کریں",
        "nowiki_tip": "ویکی شکلبندی نظرانداز کریں",
        "image_tip": "پیوستہ ملف",
-       "media_tip": "ربطِ ملف",
+       "media_tip": "فائل کا ربط",
        "sig_tip": "آپکا دستخط بمع مہرِوقت",
        "hr_tip": "اُفقی لکیر (زیادہ استعمال نہ کریں)",
        "summary": "خلاصہ:",
        "mergehistory-go": "ضم پذیر ترامیم دِکھاؤ",
        "mergehistory-submit": "نظرثانیاں ضم کرو",
        "mergehistory-empty": "نظرثانیاں ضم نہیں کی جاسکتیں.",
+       "mergehistory-done": "$1 کے $3 {{PLURAL:$3|نسخے|نسخوں}} کو [[:$2]] ضم کر دیا گیا۔",
+       "mergehistory-fail": "ضم تاریخچہ ممکن نہیں، براہ کرم صفحہ اور وقت کے پیرامیٹر کو دوبارہ جانچ لیں۔",
        "mergehistory-fail-bad-timestamp": "وقت کی مہر نادرست ہے۔",
        "mergehistory-fail-invalid-source": "ماخذ درست نہیں۔",
        "mergehistory-fail-invalid-dest": "مقصود صفحہ درست نہیں۔",
+       "mergehistory-fail-no-change": "ضم تاریخچہ نے کسی بھی نسخے کو ضم نہیں کیا۔ براہ کرم صفحہ اور وقت کے پیرامیٹر کو دوبارہ جانچ لیں۔",
        "mergehistory-fail-permission": "ناکافی اختیارات برائے ضم تاریخچہ۔",
        "mergehistory-fail-self-merge": "ماخذ و مقصود صفحات یکساں ہیں۔",
        "mergehistory-no-source": "مآخذ صفحہ $1 موجود نہیں.",
        "search-relatedarticle": "متعلقہ",
        "searchrelated": "متعلقہ",
        "searchall": "تمام",
+       "search-showingresults": "{{PLURAL:$4|نتائج <strong>$1</strong> از <strong>$3</strong>|نتائج <strong>$1 - $2</strong> از <strong>$3</strong>}}",
        "search-nonefound": "استفسار کے مطابق کوئی نتیجہ برآمد نہیں ہوا۔",
        "search-nonefound-thiswiki": "اس سائٹ پر استفسار کے مطابق کوئی نتیجہ برآمد نہیں ہوا۔",
        "powersearch-legend": "پیشرفتہ تلاش",
        "recentchanges-label-bot": "اس ترمیم کو ایک روبہ نے انجام دیا ہے",
        "recentchanges-label-unpatrolled": "اس ترمیم کی اب تک مراجعت نہیں کی گئی",
        "recentchanges-label-plusminus": "صفحہ کا حجم تبدیل شدہ بلحاظ بائٹ مقدار",
-       "recentchanges-legend-heading": "<strong>اختیارات</strong>",
+       "recentchanges-legend-heading": "<strong>اختصارات:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (نیز [[Special:NewPages|جدید صفحات کی فہرست]]) ملاحظہ فرمائیں",
        "recentchanges-submit": "دکھائیں",
        "rcnotefrom": "ذیل میں <strong>$2</strong> سے کی گئی {{PLURAL:$5|تبدیلی|تبدیلیاں}} <strong>$1</strong> تک دکھائی جا رہی ہیں۔",
        "rcshowhidebots-show": "دکھائیں",
        "rcshowhidebots-hide": "چھپائیں",
        "rcshowhideliu": "داخل شدہ صارف $1",
-       "rcshowhideliu-show": "دکھاؤ",
+       "rcshowhideliu-show": "دکھائÛ\8cÚº",
        "rcshowhideliu-hide": "چھپائیں",
        "rcshowhideanons": "گمنام صارف $1",
-       "rcshowhideanons-show": "دکھاؤ",
+       "rcshowhideanons-show": "دکھائÛ\8cÚº",
        "rcshowhideanons-hide": "چھپائیں",
        "rcshowhidepatr": "$1 مراجعت شدہ ترامیم",
        "rcshowhidepatr-show": "دکھاؤ",
        "rcshowhidepatr-hide": "چھپائيں",
        "rcshowhidemine": "ذاتی ترامیم $1",
-       "rcshowhidemine-show": "دکھاؤ",
+       "rcshowhidemine-show": "دکھائÛ\8cÚº",
        "rcshowhidemine-hide": "چھپائیں",
        "rcshowhidecategorization": "صفحاتی زمرہ بندی $1",
        "rcshowhidecategorization-show": "دکھائیں",
        "diff": "فرق",
        "hist": "تاریخچہ",
        "hide": "چھـپائیں",
-       "show": "دکھاؤ",
+       "show": "دکھائÛ\8cÚº",
        "minoreditletter": "م",
        "newpageletter": "نیا ..",
        "boteditletter": " خودکار",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] زمرے سے ہٹا دیا گیا ہے، [[Special:WhatLinksHere/$1|یہ صفحہ دیگر صفحات میں بھی موجود ہے]]",
        "autochange-username": "میڈیاویکی خودکار تبدیلیاں",
        "upload": "اپلوڈ",
-       "uploadbtn": "زبراثقال ملف (اپ لوڈ فائل)",
+       "uploadbtn": "فائل اپلوڈ کریں",
        "reuploaddesc": "زبراثقال ورقہ (فارم) کیجانب واپس۔",
        "upload-tryagain": "فائل کی تبدیل شدہ وضاحت روانہ کریں",
        "uploadnologin": "آپ داخل شدہ حالت میں نہیں",
        "uploadstash-thumbnail": "تھمب نیل دیکھیں",
        "invalid-chunk-offset": "آفسیٹ کا قطعہ نادرست ہے",
        "img-auth-accessdenied": "رسائی معطل",
+       "img-auth-nofile": "فائل «$1» موجود نہیں ہے۔",
        "http-invalid-url": "نادرست یوآرایل: $1",
+       "http-request-error": "ایچ ٹی ٹی پی کی درخواست کسی نامعلوم نقص کی بنا پر ناکام ہوگئی۔",
        "http-read-error": "HTTP خواندگی میں نقص۔",
        "http-timed-out": "HTTP درخواست کی مہلت ختم ہو گئی۔",
        "http-curl-error": "یوآرایل $1 کو اخذ کرنے کے دوران میں نقص",
        "filerevert": "$1 کا استرجع کریں",
        "filerevert-legend": "فائل کا استرجع کریں",
        "filerevert-comment": "وجہ:",
+       "filerevert-defaultcomment": "مورخہ $1 $2 بجے ($3) کے نسخے کی جانب واپس پھیر دیا گیا",
        "filerevert-submit": "استرجع کریں",
        "filedelete": "$1 کو حذف کریں",
        "filedelete-legend": "فائل حذف کریں",
        "doubleredirects": "دوہرے متبادل ربط",
        "double-redirect-fixed-move": "[[$1]] کو منتقل کر دیا گیا۔\nیہ از خود تازہ ہو گیا اور اب [[$2]] سے رجوع مکرر ہے۔",
        "brokenredirects": "نامکمل متبادل ربط",
+       "brokenredirectstext": "ذیل کے رجوع مکررات غیر موجود صفحات سے مربوط ہیں:",
        "brokenredirects-edit": "ترمیم کریں",
        "brokenredirects-delete": "حذف",
        "withoutinterwiki": "صفحات بدون بین الویکی روابط",
+       "withoutinterwiki-summary": "درج ذیل صفحات دوسری زبان کے صفحات سے مربوط نہیں ہیں۔",
        "withoutinterwiki-legend": "سابقہ",
        "withoutinterwiki-submit": "دکھائیں",
        "fewestrevisions": "کم نظرِ ثانی شدہ مضامین",
        "apisandbox-jsonly": "اے پی آئی کے تختۂ مشق کو استعمال کرنے کے لیے جاوا اسکرپٹ درکار ہے۔",
        "apisandbox-api-disabled": "اس سائٹ پر اے پی آئی غیر فعال ہے۔",
        "apisandbox-fullscreen": "پینل کو وسیع کریں",
+       "apisandbox-fullscreen-tooltip": "براؤزر کے دریچے کا مکمل احاطہ کرنے کے لیے تختۂ مشق کے پینل کو وسیع کریں۔",
        "apisandbox-unfullscreen": "صفحہ دکھائیں",
        "apisandbox-unfullscreen-tooltip": "تختہ مشق کا پینل چھوٹا کریں تاکہ میڈیاویکی کے روابطِ رہنمائی دسترس میں ہوں۔",
        "apisandbox-submit": "بنانے کی درخواست",
        "rollbacklinkcount-morethan": "$1 {{PLURAL:$1|ترمیم|ترامیم}} سے زیادہ کا استرجع",
        "rollbackfailed": "سابقہ حالت پر واپسی ناکام",
        "rollback-missingparam": "درخواست میں ضروری پیرامیٹر موجود نہیں۔",
+       "rollback-missingrevision": "نسخہ کی معلومات لوڈ نہیں ہو سکتی۔",
        "cantrollback": "تدوین ثانی کا اعادہ نہیں کیا جاسکتا؛ کیونکہ اس میں آخری بار حصہ لینے والا ہی اس صفحہ کا واحد کاتب ہے۔",
+       "editcomment": "خلاصہ ترمیم یہ تھا: <em>«$1»</em>.",
+       "revertpage": "[[خاص:شراکتیں/$2|$2]] ([[تبادلۂ خیال:$2|تبادلۂ خیال]]) کی ترامیم [[صارف:$1|$1]] کی گذشتہ ترمیم کی جانب واپس پھیر دی گئیں۔",
+       "revertpage-nouser": "(حذف شدہ صارف نام) کی ترامیم {{GENDER:$1|[[User:$1|$1]]}} کی گذشتہ ترمیم کی جانب واپس پھیر دی گئیں",
+       "rollback-success": "$1 کی ترامیم واپس پھیر دی گئیں؛\nصفحہ واپس $2 کی آخری ترمیم کی جانب منتقل کر دیا گیا۔",
+       "rollback-success-notify": "$1 کی ترامیم واپس پھیر دی گئیں؛\nصفحہ واپس $2 کی آخری ترمیم کی جانب منتقل کر دیا گیا۔ [$3 تبدیلیاں دکھائیں]",
+       "sessionfailure-title": "نشست میں خامی",
+       "changecontentmodel": "صفحہ کے مواد کے ماڈل میں تبدیلی کریں",
+       "changecontentmodel-legend": "مواد کے ماڈل کو تبدیل کریں",
        "changecontentmodel-title-label": "صفحہ کا عنوان",
        "changecontentmodel-model-label": "نیا مواد ماڈل",
        "changecontentmodel-reason-label": "وجہ:",
        "changecontentmodel-submit": "تبدیلی",
+       "changecontentmodel-success-title": "مواد کا ماڈل تبدیل کر دیا گیا ہے",
+       "changecontentmodel-success-text": "[[:$1]] کے مواد کی نوعیت تبدیل کر دی گئی۔",
+       "changecontentmodel-cannot-convert": "[[:$1]] میں موجود مواد کی نوعیت کو $2 میں تبدیل نہیں کیا جا سکتا۔",
+       "changecontentmodel-nodirectediting": "$1 کے مواد کا ماڈل راست ترمیم کاری کو معاونت فراہم نہیں کرتا",
+       "changecontentmodel-emptymodels-title": "مواد کا کوئی ماڈل دستیاب نہیں",
+       "changecontentmodel-emptymodels-text": "[[:$1]] میں موجود مواد کی نوعیت کو تبدیل نہیں کیا جا سکتا۔",
        "log-name-contentmodel": "نوشتہ تبدیلی نمونہ مواد",
+       "log-description-contentmodel": "صفحہ کے مواد کے ماڈل سے متعلق واقعات",
        "logentry-contentmodel-change": "$1 نے صفحہ $3 کے مواد کی ساخت کو \"$4\" سے \"$5\" میں {{GENDER:$2|تبدیل کیا}}",
        "logentry-contentmodel-change-revertlink": "استرجع",
        "logentry-contentmodel-change-revert": "استرجع",
        "protectlogpage": "نوشتۂ محفوظ شدگی",
+       "protectlogtext": "ذیل میں صفحات کے درجہ حفاظت کی تبدیلیوں کی فہرست درج ہے۔\nموجودہ محفوظ صفحات کی فہرست دیکھنے کے لیے [[Special:ProtectedPages|محفوظ صفحات کی فہرست]] ملاحظہ فرمائیں۔",
        "protectedarticle": "\"[[$1]]\" کومحفوظ کردیا",
-       "unprotectedarticle": "\"[[$1]]\" کوغیر محفوظ کیا",
+       "modifiedarticleprotection": "«[[$1]]» کا درجہ حفاظت تبدیل کیا",
+       "unprotectedarticle": "«[[$1]]» کو غیر محفوظ کیا",
        "movedarticleprotection": "نے \"[[$2]]\" کا درجہ حفاظت \"[[$1]]\" کی جانب منتقل کیا",
+       "protect-title": "«$1» کا درجہ حفاظت تبدیل کریں",
+       "protect-title-notallowed": "«$1» کا درجہ حفاظت دیکھیں",
        "prot_1movedto2": "[[$1]] بجانب [[$2]] منتقل",
+       "protect-badnamespace-title": "ناقابل حفاظت نام فضا",
+       "protect-badnamespace-text": "اس نام فضا میں موجود صفحات کو محفوظ نہیں کیا جا سکتا۔",
+       "protect-norestrictiontypes-title": "ناقابل حفاظت صفحہ",
        "protect-legend": "تحفظ کی تصدیق کریں",
        "protectcomment": "وجہ:",
        "protectexpiry": "زاید میعاد:",
-       "protect-default": "تمام صارفین کو اہل بناؤ",
+       "protect_expiry_invalid": "وقت اختتام نادرست ہے۔",
+       "protect_expiry_old": "وقت اختتام گزر چکا ہے۔",
+       "protect-unchain-permissions": "مزید اختیارات حفاظت کو غیر مقفل کریں",
+       "protect-text": "یہاں آپ <strong>$1</strong> کا درجۂ حفاظت دیکھ اور تبدیل کر سکتے ہیں۔",
+       "protect-locked-blocked": "پابندی کے دوران میں آپ درجہ حفاظت میں تبدیلی نہیں کر سکتے۔\nصفحہ <strong>$1</strong> کی حالیہ ترتیبات یہاں دیکھی جا سکتی ہیں:",
+       "protect-locked-dblock": "ڈیٹابیس مقفل ہونے کی وجہ سے درجہ حفاظت کو تبدیل نہیں کیا جا سکتا۔\nصفحہ <strong>$1</strong> کی حالیہ ترتیبات یہاں دیکھی جا سکتی ہیں:",
+       "protect-locked-access": "آپ کو درجہ حفاظت تبدیل کرنے کا اختیار حاصل نہیں ہے۔\nصفحہ <strong>$1</strong> کی حالیہ ترتیبات یہاں دیکھی جا سکتی ہیں:",
+       "protect-cascadeon": "یہ صفحہ محفوظ ہے کیونکہ یہ درج ذیل {{PLURAL:$1|صفحہ|صفحات}} میں شامل ہے جہاں آبشاری حفاظت فعال ہے۔\nآپ اس صفحہ کے درجۂ حفاظت میں تبدیلی کرسکتے ہیں، لیکن یہ آبشاری حفاظت پر اثر انداز نہیں ہوگی۔",
+       "protect-default": "تمام صارفین کو اجازت ہے",
+       "protect-fallback": "محض «$1» کا اختیار رکھنے والے صارفین کو اجازت ہے",
+       "protect-level-autoconfirmed": "محض خود توثیق شدہ صارفین کو اجازت ہے",
        "protect-level-sysop": "صرف منتظمین کو اجازت ہے",
        "protect-summary-cascade": "آبشاری",
        "protect-expiring": "مدت خاتمہ  $1 (یو ٹی سی)",
        "protect-expiring-local": "مدت خاتمہ  $1",
        "protect-expiry-indefinite": "لا محدود",
+       "protect-cascade": "اس صفحہ میں شامل صفحات کو محفوظ کریں (آبشاری حفاظت)",
+       "protect-cantedit": "آپ اس صفحہ کے درجہ حفاظت میں تبدیلی نہیں کر سکتے کیونکہ آپ کو اس میں ترمیم کرنے کی اجازت نہیں ہے۔",
        "protect-othertime": "دیگر وقت:",
        "protect-othertime-op": "دیگر وقت",
+       "protect-existing-expiry": "موجودہ وقت اختتام: $3، $2",
+       "protect-existing-expiry-infinity": "موجودہ وقت اختتام: لامحدود",
+       "protect-otherreason": "دوسری/اضافی وجہ:",
        "protect-otherreason-op": "دیگر وجہ",
+       "protect-dropdown": "* عمومی وجوہات حفاظت\n** مسلسل تخریب کاری\n** مسلسل فاضل کاری\n** غیر مفید ترمیمی جنگ\n** زیادہ آمد و رفت صفحہ",
+       "protect-edit-reasonlist": "وجوہات حفاظت میں ترمیم کریں",
        "protect-expiry-options": "1 hour:1 hour,1 day:1 day,1 week:1 week,2 weeks:2 weeks,1 month:1 month,3 months:3 months,6 months:6 months,1 year:1 year,infinite:infinite",
        "restriction-type": "اجازت:",
+       "restriction-level": "درجہ پابندی:",
        "minimum-size": "کم از کم سائز",
        "maximum-size": "زیادہ سے زیادہ سائز:",
        "pagesize": "(بائیٹ)",
-       "restriction-edit": "تحرÛ\8cر Ù\88 ØªØ±Ù\85Û\8cÙ\85",
+       "restriction-edit": "ترمیم",
        "restriction-move": "منتقل",
        "restriction-create": "تخلیق",
        "restriction-upload": "اپلوڈ",
        "nolinkshere": "'''[[:$1]]''' سے کوئی روابط نہیں۔",
        "isredirect": "لوٹایا گیا صفحہ",
        "istemplate": "شامل شدہ",
-       "isimage": "ربطِ ملف",
+       "isimage": "فائل کا ربط",
        "whatlinkshere-prev": "{{PLURAL:$1|پچھلا|پچھلے $1}}",
        "whatlinkshere-next": "{{PLURAL:$1|اگلا|اگلے $1}}",
        "whatlinkshere-links": "روابط ←",
        "whatlinkshere-hideredirs": "رجوع مکررات $1",
        "whatlinkshere-hidetrans": "$1 استعمالات",
        "whatlinkshere-hidelinks": "روابط $1",
-       "whatlinkshere-hideimages": "رÙ\88ابطÙ\90 ØªØµØ§Ù\88Û\8cر $1",
+       "whatlinkshere-hideimages": "تصÙ\88Û\8cر Ú©Û\92 Ø±Ù\88ابط $1",
        "whatlinkshere-filters": "فلٹرذ",
        "whatlinkshere-submit": "ٹھیک",
        "block": "صارف مسدود کریں",
+       "unblock": "صارف سے پابندی ہٹائیں",
        "blockip": "داخلہ ممنوع برائے صارف",
        "blockip-legend": "ممنوع کردہ صارفین",
        "ipaddressorusername": "آئی پی پتہ یا صارف نام:",
+       "ipbexpiry": "وقت اختتام:",
        "ipbreason": "وجہ:",
+       "ipbreason-dropdown": "* عمومی وجوہات پابندی\n** غلط معلومات کا اندراج\n** صفحات سے متن کا مٹانا\n** بیرونی روابط میں بے کار روابط کی فاضل کاری\n** صفحات میں لغو چیزوں کا اندراج\n** بدتمیزی/بداخلاقی\n** متعدد کھاتوں کا استعمال\n** ناقابلِ قبول اسمِ صارف",
+       "ipb-hardblock": "اس آئی پی پتے سے داخل شدہ صارفین کو ترمیم کاری سے باز رکھیں",
+       "ipbcreateaccount": "کھاتہ سازی سے باز رکھیں",
+       "ipbemailban": "برقی خط بھیجنے سے باز رکھیں",
        "ipbsubmit": "اس صارف کا داخلہ ممنوع کریں",
        "ipbother": "دیگر وقت:",
        "ipboptions": "2 گھنٹے:2 hours,1 یوم:1 day,3 ایام:3 days,1 ہفتہ:1 week,2 ہفتے:2 weeks,1 مہینہ:1 month,3 مہینے:3 months,6 مہینے:6 months,1 سال:1 year,لامحدود:infinite",
+       "ipbhidename": "ترامیم اور فہرستوں سے صارف نام کو چھپائیں",
+       "ipbwatchuser": "اس صارف کے صارف اور تبادلۂ خیال صفحات کو زیر نظر کریں",
+       "ipb-disableusertalk": "بحالت پابندی اس صارف کو اپنے ذاتی تبادلۂ خیال صفحہ میں ترمیم کرنے سے باز رکھیں",
+       "ipb-change-block": "ان ترتیبات کے ساتھ اس صارف پر دوبارہ پابندی لگائیں",
+       "ipb-confirm": "پابندی کی تصدیق کریں",
+       "badipaddress": "نادرست آئی پی پتا",
+       "blockipsuccesssub": "پابندی لگا دی گئی",
+       "blockipsuccesstext": "[[Special:Contributions/$1|$1]] پر پابندی لگادی گئی۔<br />\nپابندیوں پر نظر ثانی کے لیے [[Special:BlockList|فہرست پابندی]] دیکھیں۔",
+       "ipb-blockingself": "آپ اپنے آپ پر پابندی لگانے جا رہے ہیں! کیا آپ واقعی ایسا کرنا چاہتے ہیں؟",
+       "ipb-edit-dropdown": "وجوہات پابندی میں ترمیم کریں",
+       "ipb-unblock-addr": "$1 سے پابندی ہٹائیں",
+       "ipb-unblock": "صارف نام یا آئی پی پتے سے پابندی ہٹائیں",
+       "ipb-blocklist": "موجودہ پابندیاں دیکھیں",
+       "ipb-blocklist-contribs": "{{GENDER:$1|$1}} کی شراکتیں",
+       "ipb-blocklist-duration-left": "$1 باقی ہے",
+       "unblockip": "صارف سے پابندی ہٹائیں",
+       "unblockiptext": "گزشتہ ممنوع صارف یا آئی پی پتے کی تحریری دسترس بحال کرنے کے لیے درج ذیل فارم استعمال کریں۔",
+       "ipusubmit": "اس پابندی کو ہٹائیں",
+       "unblocked": "[[User:$1|$1]] سے پابندی ہٹا دی گئی۔",
+       "unblocked-range": "$1 سے پابندی ہٹا دی گئی۔",
+       "unblocked-id": "پابندی نمبر $1 سے پابندی ہٹا دی گئی۔",
+       "unblocked-ip": "[[Special:Contributions/$1|$1]] سے پابندی ہٹا دی گئی۔",
        "blocklist": "ممنوع صارفین",
        "ipblocklist": "ممنوع صارفین",
+       "ipblocklist-legend": "ممنوع صارف کو تلاش کریں",
+       "blocklist-userblocks": "کھاتے کی پابندیاں چھپائیں",
+       "blocklist-tempblocks": "عارضی پابندیاں چھپائیں",
+       "blocklist-addressblocks": "تنہا آئی پی پابندیوں کو چھپائیں",
+       "blocklist-rangeblocks": "رینج پابندیاں چھپائیں",
+       "blocklist-timestamp": "وقت کی مہر",
        "blocklist-target": "ہدف",
+       "blocklist-expiry": "وقت اختتام",
+       "blocklist-params": "پابندی کے پیرامیٹر",
        "blocklist-reason": "وجہ",
        "ipblocklist-submit": "تلاش",
-       "infiniteblock": "مستقل",
+       "ipblocklist-localblock": "مقامی پابندی",
+       "ipblocklist-otherblocks": "دیگر {{PLURAL:$1|پابندی|پابندیاں}}",
+       "infiniteblock": "لا محدود",
+       "expiringblock": "مورخہ $1 بوقت $2 بجے اختتام پزیر ہوگی",
+       "anononlyblock": "محض گمنام صارف",
+       "noautoblockblock": "خودکار پابندی غیر فعال",
+       "createaccountblock": "کھاتہ سازی غیر فعال",
+       "emailblock": "برقی خط غیر فعال",
+       "blocklist-nousertalk": "اپنے ذاتی تبادلۂ خیال میں ترمیم نہیں کر سکتا",
+       "ipblocklist-empty": "پابندیوں کی فہرست خالی ہے۔",
+       "ipblocklist-no-results": "درخواست شدہ آئی پی پتے یا صارف نام پر پابندی عائد نہیں ہے",
        "blocklink": "پابندی لگائیں",
        "unblocklink": "پابندی ختم",
        "change-blocklink": "پابندی میں تبدیلی",
        "contribslink": "شراکتیں",
        "emaillink": "ای میل بھیجیں",
        "blocklogpage": "نوشتۂ پابندی",
+       "block-log-flags-anononly": "محض نامعلوم صارفین",
        "block-log-flags-nocreate": "کھاتے کی تخلیق غیرفعال",
+       "block-log-flags-noautoblock": "خودکار پابندی غیر فعال",
+       "block-log-flags-noemail": "برقی خط غیر فعال",
+       "block-log-flags-nousertalk": "اپنے ذاتی تبادلۂ خیال میں ترمیم نہیں کر سکتا",
+       "block-log-flags-angry-autoblock": "پیشرفتہ خودکار پابندی فعال",
+       "block-log-flags-hiddenname": "صارف نام پوشیدہ ہے",
+       "ipb_expiry_invalid": "وقت اختتام نادرست ہے۔",
+       "ipb_expiry_old": "وقت اختتام گزر چکا ہے۔",
+       "ipb_already_blocked": "«$1» پر پہلے ہی پابندی لگا دی گئی ہے۔",
+       "ipb-needreblock": "«$1» پر پہلے ہی پابندی لگا دی گئی ہے۔ کیا آپ ان ترتیبات کو تبدیل کرنا چاہتے ہیں؟",
+       "ipb-otherblocks-header": "دیگر {{PLURAL:$1|پابندی|پابندیاں}}",
+       "unblock-hideuser": "چونکہ اس صارف کا نام پوشیدہ ہے لہذا آپ اس صارف سے پابندی نہیں ہٹا سکتے۔",
+       "ipbblocked": "آپ دیگر صارفین پر پابندی لگا یا ہٹا نہیں سکتے کیونکہ خود آپ پر پابندی عائد کی گئی ہے۔",
+       "ipbnounblockself": "آپ کو اپنی ذات سے پابندی ہٹانے کی اجازت نہیں ہے۔",
+       "lockdb": "ڈیٹابیس مقفل کریں",
+       "unlockdb": "ڈیٹابیس غیر مقفل کریں",
+       "lockconfirm": "ہاں، میں واقعی ڈیٹابیس کو مقفل کرنا چاہتا ہوں۔",
+       "unlockconfirm": "ہاں، میں واقعی ڈیٹابیس کو غیر مقفل کرنا چاہتا ہوں۔",
+       "lockbtn": "ڈیٹابیس مقفل کریں",
+       "unlockbtn": "ڈیٹابیس غیر مقفل کریں",
+       "locknoconfirm": "آپ نے تصدیقی خانے پر نشان زد نہیں کیا ہے۔",
+       "lockdbsuccesssub": "ڈیٹابیس کو مقفل کر دیا گیا",
+       "unlockdbsuccesssub": "ڈیٹابیس کو غیر مقفل کر دیا گیا",
+       "lockdbsuccesstext": "ڈیٹابیس مقفل کر دیا گیا۔<br />\nنگہداشت مکمل ہو جانے کے بعد ڈیٹابیس کو [[Special:UnlockDB|غیر مقفل کرنا]] نہ بھولیں۔",
+       "unlockdbsuccesstext": "ڈیٹابیس کو غیر مقفل کر دیا گیا۔",
+       "databaselocked": "ڈیٹابیس پہلے سے مقفل ہے۔",
+       "databasenotlocked": "ڈیٹابیس مقفل نہیں ہے۔",
+       "lockedbyandtime": "(بذریعہ {{GENDER:$1|$1}} مورخہ $2 بوقت $3 بجے)",
        "move-page": "منتقلی $1",
        "move-page-legend": "منتقلئ صفحہ",
-       "movepagetext": "درج ذیل فارم کے ذریعہ صفحہ کو نیا نام دیا جاسکتا ہے، اس کے ساتھ صفحہ کا تاریخچہ بھی منتقل ہو جائے گا اور\nنئے عنوان کے جانب قدیم عنوان کو رجوع مکرر کردیا جائے گا۔\n\nاس بات کا یقین کر لیں کہ [[Special:DoubleRedirects|دوہرے]] یا [[Special:BrokenRedirects|شکستہ رجوع مکررات]] موجود نہ ہوں۔\n\nنیز آپ اس بات کو بھی یقینی بنانے کے ذمہ دار ہیں کہ روابط انہیں جگہوں سے مربوط رہیں جہاں ہونا چاہیے۔\n\nخیال رہے کہ یہ صفحہ منتقل '''نہیں''' ہوگا اگر نئے عنوان کے ساتھ صفحہ پہلے سے موجود ہو، ہاں اگر صفحہ خالی ہو اور اس کا گذشتہ ترمیمی تاریخچہ موجود نہ ہو تو منتقل کیا جا سکتا ہے۔\nاس کا مطلب ہے آپ سے اگر غلطی ہوجائے تو آپ صفحہ کو اسی جگہ لوٹا سکتے ہیں، تاہم موجود صفحہ پر برتحریر (overwrite) نہیں کرسکتے۔\n\n'''انتباہ!'''\nکسی اہم اور مقبول صفحہ کی منتقلی، غیرمتوقع اور پریشان کن بھی ہی ہوسکتی ہے اس لیے \nمنتقلی سے قبل براہ کرم یقین کرلیں کہ آپ اس کے منطقی نتائج سے باخبر ہیں۔",
-       "movepagetext-noredirectfixer": "درج ذیل ورقہ کے ذریعہ صفحہ کو نیا نام دیا جاسکتا ہے، اس کے ساتھ صفحہ کا تاریخچہ بھی منتقل ہوجائیگا۔\nنئے عنوان کے جانب قدیم عنوان کو رجوع مکرر کردیا جائیگا۔\n\nیقین کرلیں کہ [[Special:DoubleRedirects|مکرر]] یا [[Special:BrokenRedirects|شکستہ رجوع مکررات]] موجود نہیں ہیں۔\nآپ اس بات کو یقینی بنانے کے ذمہ دار ہیں کہ روابط انہیں جگہوں سے مربوط ہیں جن کو فرض کیا گیا ہے۔\n\nخیال رہے کہ یہ صفحہ منتقل '''نہیں''' ہوگا اگر نئے عنوان کے ساتھ صفحہ پہلے سے موجود ہو، سوائے اس کے کہ صفحہ خالی ہو اور اس کا گذشتہ ترمیمی تاریخچہ موجود نہ ہو۔\nاس کا مطلب ہے آپ سے اگر غلطی ہوجائے تو آپ صفحہ کو اسی جگہ لوٹا سکتے ہیں، تاہم موجود صفحہ پر برتحریر (overwrite) نہیں کرسکتے۔\n\n'''انتباہ!'''\nکسی اہم اور مقبول صفحہ کی منتقلی، غیرمتوقع اور پریشان کن بھی ہی ہوسکتی ہے اس لیۓ؛ \nمنتقلی سے قبل براہ کرم یقین کرلیجۓ کہ آپ اسکے منطقی نتائج سے باخبر ہیں۔",
+       "movepagetext": "درج ذیل فارم کے ذریعہ صفحہ کو نیا نام دیا جاسکتا ہے، اس کے ساتھ صفحہ کا تاریخچہ بھی منتقل ہو جائے گا اور نئے عنوان کے جانب قدیم عنوان کو رجوع مکرر کردیا جائے گا۔\n\nاس بات کا یقین کر لیں کہ [[Special:DoubleRedirects|دوہرے]] یا [[Special:BrokenRedirects|شکستہ رجوع مکررات]] موجود نہ ہوں۔\n\nنیز آپ اس بات کے بھی ذمہ دار ہیں کہ روابط انہیں جگہوں سے مربوط رہیں جہاں سے ابھی ہیں۔\n\nخیال رہے کہ اگر نئے عنوان سے کوئی صفحہ پہلے سے موجود ہو تو یہ صفحہ منتقل '''نہیں''' ہوگا، ہاں اگر صفحہ خالی ہو اور اس کا گذشتہ ترمیمی تاریخچہ موجود نہ ہو تو منتقل کیا جا سکتا ہے۔\nاس کا مطلب یہ ہے کہ آپ سے اگر غلطی ہوجائے تو آپ صفحہ کو اسی جگہ لوٹا سکتے ہیں، تاہم موجود صفحہ پر برتحریر (overwrite) نہیں کرسکتے۔\n\n<strong>اطلاع:</strong>\nکسی اہم اور مقبول صفحہ کی منتقلی، غیرمتوقع اور پریشان کن بھی ہی ہوسکتی ہے اس لیے منتقلی سے قبل یقین کرلیں کہ آپ اس کے منطقی نتائج سے باخبر ہیں۔",
+       "movepagetext-noredirectfixer": "درج ذیل فارم کے ذریعہ صفحہ کو نیا نام دیا جاسکتا ہے، اس کے ساتھ صفحہ کا تاریخچہ بھی منتقل ہو جائے گا اور نئے عنوان کے جانب قدیم عنوان کو رجوع مکرر کردیا جائے گا۔\n\nاس بات کا یقین کر لیں کہ [[Special:DoubleRedirects|دوہرے]] یا [[Special:BrokenRedirects|شکستہ رجوع مکررات]] موجود نہ ہوں۔\n\nنیز آپ اس بات کے بھی ذمہ دار ہیں کہ روابط انہیں جگہوں سے مربوط رہیں جہاں سے ابھی ہیں۔\n\nخیال رہے کہ اگر نئے عنوان سے کوئی صفحہ پہلے سے موجود ہو تو یہ صفحہ منتقل '''نہیں''' ہوگا، ہاں اگر صفحہ خالی ہو اور اس کا گذشتہ ترمیمی تاریخچہ موجود نہ ہو تو منتقل کیا جا سکتا ہے۔\nاس کا مطلب یہ ہے کہ آپ سے اگر غلطی ہوجائے تو آپ صفحہ کو اسی جگہ لوٹا سکتے ہیں، تاہم موجود صفحہ پر برتحریر (overwrite) نہیں کرسکتے۔\n\n<strong>اطلاع:</strong>\nکسی اہم اور مقبول صفحہ کی منتقلی، غیرمتوقع اور پریشان کن بھی ہی ہوسکتی ہے اس لیے منتقلی سے قبل یقین کرلیں کہ آپ اس کے منطقی نتائج سے باخبر ہیں۔",
+       "movepagetalktext": "اگر آپ اس خانے کو نشان زد کریں تو ملحقہ تبادلہ خیال صفحہ بھی نئے عنوان کی جانب خودکار طور پر منتقل ہو جائے گا اگر اس عنوان کے تحت پہلے سے کوئی تبادلۂ خیال صفحہ موجود نہ ہو۔\n\nاس صورت میں آپ کو دستی طور پر اس صفحہ کو منتقل ضم کرنا ہوگا۔",
+       "moveuserpage-warning": "<strong>انتباہ:</strong> آپ صارف صفحہ کو منتقل کر رہے ہیں۔ واضح رہے کہ اس منتقلی کے بعد صارف کا محض صفحہ منتقل ہوگا، اس کا صارف نام تبدیل <em>نہیں</em> ہوگا۔",
+       "movecategorypage-warning": "<strong>انتباہ:</strong> آپ زمرہ منتقل کر رہے ہیں۔ واضح رہے کہ منتقلی کے بعد اس زمرے میں موجود صفحات نئے زمرے میں منتقل <em>نہیں</em> ہونگے۔",
+       "movenologintext": "صفحہ کو منتقل کرنے کے لیے آپ کو اپنے کھاتے میں [[Special:UserLogin|داخل ہونا]] ضروری ہے۔",
+       "movenotallowed": "آپ کو صفحات منتقل کرنے کی اجازت نہیں ہے۔",
+       "movenotallowedfile": "آپ کو فائلیں منتقل کرنے کی اجازت نہیں ہے۔",
+       "cant-move-user-page": "آپ کو صارف صفحات منتقل کرنے کی اجازت نہیں ہے (ذیلی صفحات اس سے مستثنی ہیں)۔",
+       "cant-move-to-user-page": "کسی صفحہ کو کسی صارف صفحہ میں منتقل کرنے کی اجازت نہیں ہے (صارف کا ذیلی صفحہ اس سے مستثنی ہے)۔",
+       "cant-move-category-page": "آپ کو زمرہ جات منتقل کرنے کی اجازت نہیں ہے۔",
+       "cant-move-to-category-page": "کسی صفحہ کو زمرے میں منتقل کرنے کی اجازت نہیں ہے۔",
        "newtitle": "نـیــا عـنــوان:",
-       "move-watch": "صÙ\81Ø­Û\81 Ø²Û\8cر Ù\86ظر",
+       "move-watch": "اصÙ\84 Ø§Ù\88ر Û\81دÙ\81 ØµÙ\81Ø­Û\81 Ú©Ù\88 Ø²Û\8cر Ù\86ظر Ú©Ø±Û\8cÚº",
        "movepagebtn": "مـنـتـقـل",
        "pagemovedsub": "انتقال کامیاب",
        "movepage-moved": "<strong>\"$1\" کو \"$2\" کی جانب منتقل کر دیا گیا</strong>",
        "movepage-moved-redirect": "رجوع مکرر تخلیق کر دیا گیا۔",
        "movepage-moved-noredirect": "رجوع مکرر کو بننے سے روک دیا گیا ہے۔",
        "articleexists": "اس عنوان سے کوئی صفحہ پہلے ہی موجود ہے، یا آپکا منتخب کردہ نام مستعمل نہیں۔ براۓ مہربانی دوسرا نام منتخب کیجیۓ۔",
+       "movetalk": "ملحقہ تبادلۂ خیال صفحہ بھی منتقل کریں",
+       "move-subpages": "ذیلی صفحات منتقل کریں ($1 سے زیادہ)",
+       "move-talk-subpages": "تبادلۂ خیال صفحہ کے ذیلی صفحات منتقل کریں ($1 سے زیادہ)",
+       "movepage-page-exists": "صفحہ $1 پہلے سے موجود ہے اور خودکار طور پر برتحریر نہیں کیا جا سکتا۔",
        "movepage-page-moved": "صفحہ $1 کو $2 کی جانب منتقل کر دیا گیا۔",
+       "movepage-page-unmoved": "صفحہ $1 کو $2 کی جانب منتقل نہیں کیا جا سکا۔",
+       "movepage-max-pages": "$1 کی زیادہ سے زیادہ تعداد تک {{PLURAL:$1|صفحہ منتقل کر دیا گیا ہے|صفحات منتقل کر دیے گئے ہیں}}، اب خودکار طور پر مزید صفحے منتقل نہیں کیے جا سکتے۔",
        "movelogpage": "نوشتۂ منتقلی",
+       "movelogpagetext": "ذیل میں ان تمام صفحات کی فہرست درج ہے جو منتقل کیے گئے ہیں۔",
+       "movesubpage": "{{PLURAL:$1|ذیلی صفحہ|ذیلی صفحات}}",
+       "movesubpagetext": "ذیل میں اس صفحہ {{PLURAL:$1|کا|کے}} $1 {{PLURAL:$1|ذیلی صفحہ موجود ہے|ذیلی صفحات موجود ہیں}}۔",
+       "movenosubpage": "اس صفحہ کے ذیلی صفحات موجود نہیں ہیں۔",
        "movereason": "وجہ:",
        "revertmove": "رجوع",
-       "delete_and_move_text": "==حذف شدگی لازم==\n\nمنتقلی کے سلسلے میں انتخاب کردہ مضمون \"[[:$1]]\" پہلے ہی موجود ہے۔ کیا آپ اسے حذف کرکے منتقلی کیلیۓ راستہ بنانا چاہتے ہیں؟",
+       "delete_and_move_text": "منتقلی کے سلسلے میں منتخب شدہ مضمون «[[:$1]]» پہلے سے موجود ہے۔ کیا آپ اسے حذف کرکے منتقلی کے لیے راستہ بنانا چاہتے ہیں؟",
        "delete_and_move_confirm": "ہاں، صفحہ حذف کر دیا جائے",
        "delete_and_move_reason": "[[$1]] سے منتقلی کے سلسلے میں حذف",
+       "selfmove": "اصل اور ہدف صفحے کے عناوین یکساں ہیں؛\nصفحہ کو اسی جگہ پر منتقل نہیں کیا جا سکتا۔",
+       "immobile-source-namespace": "«$1» نام فضا میں صفحات منتقل نہیں کیے جا سکتے۔",
+       "immobile-target-namespace": "«$1» نام فضا میں صفحات منتقل نہیں کیے جا سکتے۔",
+       "immobile-target-namespace-iw": "صفحہ منتقل کرنے کے لیے بین الویکی ربط درست ہدف نہیں ہے۔",
+       "immobile-source-page": "اس صفحہ کو منتقل نہیں کیا جا سکتا۔",
+       "immobile-target-page": "اس ہدف عنوان کی جانب منتقل نہیں کیا جا سکتا۔",
+       "imagenocrossnamespace": "فائل کو غیر فائل نام فضا میں منتقل نہیں کیا جا سکتا۔",
+       "nonfile-cannot-move-to-file": "غیر فائل کو فائل نام فضا میں منتقل نہیں کیا جا سکتا۔",
+       "imagetypemismatch": "نئی فائل کی توسیع اس کی نوعیت کے مطابق نہیں ہے۔",
+       "imageinvalidfilename": "ہدف فائل کا نام نادرست ہے۔",
+       "fix-double-redirects": "اصل عنوان کی جانب موجود تمام رجوع مکررات کو بھی تازہ کریں",
+       "move-leave-redirect": "پیچھے رجوع مکرر بنائیں",
        "protectedpagemovewarning": "<strong>انتباہ:</strong> اس صفحہ کو محفوظ کر دیا گیا ہے اور اب محض منتظمین ہی اسے منتقل کر سکتے ہیں۔\nحوالہ کے لیے نوشتہ کا جدید اندراج ذیل میں درج ہے:",
+       "semiprotectedpagemovewarning": "<strong>اطلاع:</strong> یہ صفحہ نیم محفوظ ہے اور اسے محض مندرج صارفین ہی منتقل کر سکتے ہیں۔\nذیل میں حوالہ کے لیے نوشتہ کا تازہ ترین اندراج موجود ہے:",
        "export": "برآمد صفحات",
+       "exportall": "تمام صفحات برآمد کریں",
+       "exportcuronly": "مکمل تاریخچہ کی بجائے محض موجودہ نسخہ کو شامل کریں",
+       "exportnohistory": "----\n<strong>اطلاع:</strong> اس فارم کے ذریعہ صفحات کے مکمل تاریخچہ کی برآمد کو بوجوہ غیر فعال کر دیا گیا ہے۔",
+       "exportlistauthors": "ہر صفحہ کے مشارکت کنندگان کی مکمل فہرست شامل کریں",
+       "export-submit": "برآمد کریں",
+       "export-addcattext": "اس زمرہ سے صفحات شامل کریں:",
+       "export-addcat": "شامل کریں",
+       "export-addnstext": "اس نام فضا سے صفحات شامل کریں:",
+       "export-addns": "شامل کریں",
+       "export-download": "فائل کے طور پر محفوظ کریں",
+       "export-templates": "سانچے شامل کریں",
+       "export-manual": "صفحات کو دستی طور پر شامل کریں:",
        "allmessages": "نظامی پیغامات",
        "allmessagesname": "نام",
        "allmessagesdefault": "طے شدہ متن",
        "allmessagescurrent": "موجودہ متن",
-       "allmessagestext": "یہ میڈیاویکی: جاۓ نام میں دستیاب نظامی پیغامات کی فہرست ہے۔",
+       "allmessagestext": "ذیل میں میڈیاویکی نام فضا میں دستیاب نظامی پیغامات کی فہرست موجود ہے۔\nاگر آپ میڈیاویکی کا ترجمہ کرنا چاہتے ہیں تو [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation میڈیاویکی مقامیت کاری] اور [https://translatewiki.net translatewiki.net] ملاحظہ فرمائیں۔",
+       "allmessagesnotsupportedDB": "اس صفحہ کو استعمال نہیں کیا جا سکتا کیونکہ <strong>$wgUseDatabaseMessages</strong> کو غیر فعال کر دیا گیا ہے۔",
+       "allmessages-filter-legend": "مقطار",
        "allmessages-filter": "تلاش بلحاظ:",
+       "allmessages-filter-unmodified": "غیر تبدیل شدہ",
        "allmessages-filter-all": "تمام",
        "allmessages-filter-modified": "تبدیل شدہ",
        "allmessages-prefix": "تلاش بلحاظ سابقہ:",
        "allmessages-filter-submit": "ٹھیک",
        "allmessages-filter-translate": "ترجمہ",
        "thumbnail-more": "چوڑا کریں",
+       "filemissing": "فائل غیر موجود ہے",
+       "thumbnail_error": "تھمب نیل بنانے کے دوران میں نقص: $1",
+       "thumbnail_error_remote": "$1 کی جانب سے پیغام نقص:\n$2",
+       "djvu_page_error": "DjVu صفحہ رینج سے باہر ہے",
+       "djvu_no_xml": "DjVu فائل کے لیے XML حاصل نہیں کیا جا سکتا",
+       "thumbnail-temp-create": "تھمب نیل کی عارضی فائل نہیں بنائی جا سکتی",
+       "thumbnail-dest-create": "تھمب نیل کو ہدف جگہ پر محفوظ نہیں کیا جا سکتا۔",
+       "thumbnail_invalid_params": "تھمب نیل کے پیرامیٹر نادرست ہیں",
+       "thumbnail_image-type": "تصویر کی نوعیت معاونت یافتہ نہیں ہے",
+       "thumbnail_image-missing": "معلوم ہوتا ہے کہ یہ فائل موجود نہیں: $1",
        "import": "درآمد صفحات",
+       "importinterwiki": "دوسرے ویکی سے درآمد کریں",
+       "import-interwiki-text": "درآمد کرنے کے لیے ویکی اور صفحہ کا عنوان منتخب کریں۔\nنسخوں کی تاریخ اور نسخہ نویسوں کے نام محفوظ رکھے جائیں گے۔\nدوسری ویکیوں سے درآمد کردہ ہر چیز کو [[Special:Log/import|نوشتہ درآمد]] میں درج کیا جاتا ہے۔",
+       "import-interwiki-sourcewiki": "اصل ویکی:",
+       "import-interwiki-sourcepage": "اصل صفحہ:",
+       "import-interwiki-history": "اس صفحہ کے تاریخچے کے تمام نسخوں کو نقل کریں",
+       "import-interwiki-templates": "تمام سانچے شامل کریں",
+       "import-interwiki-submit": "درآمد کریں",
+       "import-mapping-default": "طے شدہ جگہوں پر درآمد کریں",
+       "import-mapping-namespace": "کسی نام فضا میں درآمد کریں:",
+       "import-mapping-subpage": "درج ذیل صفحہ کے ذیلی صفحات کے طور پر درآمد کریں:",
+       "import-upload-filename": "فائل کا نام:",
+       "import-comment": "تبصرہ:",
+       "importstart": "صفحات درآمد کیے جا رہے ہیں۔۔۔",
+       "import-revision-count": "$1 {{PLURAL:$1|نسخہ|نسخے}}",
+       "importnopages": "درآمد کرنے کے لیے کوئی صفحہ نہیں ہے۔",
+       "imported-log-entries": "درآمد کردہ $1 {{PLURAL:$1|اندراج نوشتہ|اندراجات نوشتہ}}۔",
+       "importfailed": "درآمد ناکام: <nowiki>$1</nowiki>",
+       "importcantopen": "درآمد فائل کھل نہیں سکی",
+       "importbadinterwiki": "غلط بین الویکی ربط",
+       "importsuccess": "درآمد مکمل!",
+       "importnofile": "کسی درآمد فائل کو اپلوڈ نہیں کیا گیا۔",
+       "import-noarticle": "درآمد کرنے کے لیے کوئی صفحہ موجود نہیں!",
+       "importlogpage": "نوشتہ درآمد",
+       "import-logentry-upload-detail": "$1 {{PLURAL:$1|نسخہ|نسخے}} درآمد {{PLURAL:$1|کیا گیا|کیے گئے}}",
+       "import-logentry-interwiki-detail": "$2 سے $1 {{PLURAL:$1|نسخہ|نسخے}} درآمد {{PLURAL:$1|کیا گیا|کیے گئے}}",
+       "javascripttest": "جاوا اسکرپٹ کی آزمائش",
        "tooltip-pt-userpage": "آپ کا صارف صفحہ",
        "tooltip-pt-mytalk": "آپ کا تبادلہ خیال صفحہ",
        "tooltip-pt-preferences": "آپ کی ترجیحات",
        "tooltip-pt-watchlist": "اُن صفحات کی فہرست جن کی تبدیلیاں آپ کی زیرِنظر ہیں",
        "tooltip-pt-mycontris": "آپ کی شراکتوں کی فہرست",
+       "tooltip-pt-anoncontribs": "اس آئی پی پتے سے انجام دی جانے والی تمام ترامیم کی فہرست",
        "tooltip-pt-login": "آپ کیلئے داخلِ نوشتہ ہونا اچھا ہے؛ تاہم، یہ ضروری نہیں",
        "tooltip-pt-logout": "خارجِ نوشتہ ہوجائیں",
        "tooltip-pt-createaccount": "آپ کو مدعو کیا جاتا ہے کہ کھاتہ بنائیں۔تاہم کھاتہ بنانا لازم نہیں۔",
        "tooltip-ca-viewsource": "یہ ایک محفوظ شدہ صفحہ ہے.\nآپ اِس کا مآخذ دیکھ سکتے ہیں",
        "tooltip-ca-history": "صفحۂ ہٰذا کی سابقہ نظرثانی",
        "tooltip-ca-protect": "یہ صفحہ محفوظ کیجئے",
+       "tooltip-ca-unprotect": "اس صفحہ کی حفاظت میں تبدیلی کریں",
        "tooltip-ca-delete": "یہ صفحہ حذف کریں",
        "tooltip-ca-move": "یہ صفحہ منتقل کریں",
        "tooltip-ca-watch": "اِس صفحہ کو اپنی زیرِنظرفہرست میں شامل کریں",
        "tooltip-t-recentchangeslinked": "اِس صفحہ سے مربوط صفحات میں حالیہ تبدیلیاں",
        "tooltip-feed-rss": "اِس صفحہ کیلئے اسس خورد",
        "tooltip-feed-atom": "اِس صفحہ کیلئے اٹوم خورد",
-       "tooltip-t-contributions": "نئی تدوین →",
-       "tooltip-t-emailuser": "اِس صارف کو برقی خط ارسال کریں",
+       "tooltip-t-contributions": "{{GENDER:$1|اس صارف}} کی شراکتوں کی فہرست",
+       "tooltip-t-emailuser": "{{GENDER:$1|اس صارف}} کو برقی خط بھیجیں",
+       "tooltip-t-info": "اس صفحہ کے بارے میں مزید معلومات",
        "tooltip-t-upload": "زبراثقالِ ملفات",
        "tooltip-t-specialpages": "تمام خاص صفحات کی فہرست",
        "tooltip-t-print": "اِس صفحہ کا قابلِ طبعہ نسخہ",
        "tooltip-t-permalink": "صفحہ کے موجودہ نظرثانی کا مستقل ربط",
        "tooltip-ca-nstab-main": "صفحۂ مضمون دیکھئے",
        "tooltip-ca-nstab-user": "اِس صارف کے مساہمات کی فہرست دیکھئے",
+       "tooltip-ca-nstab-media": "میڈیا کا صفحہ دیکھیں",
        "tooltip-ca-nstab-special": "ہم معذرت خواہ ہیں! آپ اس [[ویکیپیڈیا:نام فضا|نام فضا]] میں ترمیم کا اختیار نہیں رکھتے۔",
        "tooltip-ca-nstab-project": "صفحۂ صارف دیکھئے",
        "tooltip-ca-nstab-image": "صفحۂ ملف دیکھئے",
+       "tooltip-ca-nstab-mediawiki": "نظامی پیغام دیکھیں",
        "tooltip-ca-nstab-template": "سانچہ دیکھئے",
+       "tooltip-ca-nstab-help": "صفحۂ معاونت دیکھیں",
        "tooltip-ca-nstab-category": "زمرہ‌جاتی صفحہ دیکھئے",
        "tooltip-minoredit": "اِس تدوین کو بطورِ معمولی ترمیم نشانزد کیجئے",
        "tooltip-save": "تبدیلیاں محفوظ کیجئے",
+       "tooltip-publish": "اپنی تبدیلیاں شائع کریں",
        "tooltip-preview": "برائے مہربانی! محفوظ کرنے سے پہلے تبدیلیوں کا پیش منظر دیکھيے",
        "tooltip-diff": "دیکھئے کہ اپنے متن میں کیا تبدیلیاں کیں",
        "tooltip-compareselectedversions": "اِس صفحہ کی دو منتخب نظرثانیوں میں فرق دیکھئے",
        "tooltip-watch": "اِس صفحہ کو اپنی زیرِنظرفہرست میں شامل کریں",
+       "tooltip-watchlistedit-normal-submit": "عناوین حذف کریں",
+       "tooltip-watchlistedit-raw-submit": "زیرنظر فہرست کی تجدید کریں",
+       "tooltip-upload": "اپلوڈ کریں",
        "tooltip-rollback": "پچھلے صارف کی کی گئی اِس صفحے پر استرجع شدہ ترامیم کو ایک کلِک میں واپس کریں",
        "tooltip-undo": "''استرجع'' اس ترمیم کو پچھلی ترمیم کے جانب واپس کردیگا اور نمائشی انداز میں خانہ ترمیم کھول دے گا۔ آپ مختصراً سبب بیان کرنے کے بھی مجاز ہونگے۔",
+       "tooltip-preferences-save": "ترجیحات محفوظ کریں",
        "tooltip-summary": "مختصر خلاصہ درج کریں",
        "common.css": "body,\ntextarea {\n    font-family: Amiri;\n}",
-       "anonymous": "{{SITENAME}} گمنام صارف",
+       "anonymous": "{{SITENAME}} {{PLURAL:$1|کا|کے}} گمنام {{PLURAL:$1|صارف|صارفین}}",
+       "siteuser": "{SITENAME}} کا صارف، $1",
+       "anonuser": "{SITENAME}} کا گمنام صارف، $1",
+       "lastmodifiedatby": "مورخہ $1 کو $2 بجے $3 نے اس صفحہ میں آخری بار تبدیلی کی۔",
+       "othercontribs": "$1 کے کام کے مطابق۔",
        "others": "دیگر",
-       "pageinfo-visiting-watchers": "حالیہ تبدیلیوں پر آنے والے ناظرین کی تعداد",
+       "siteusers": "{{SITENAME}} {{PLURAL:$2|کا|کے}} {{PLURAL:$2|{{GENDER:$1|صارف}}|صارفین}} $1",
+       "anonusers": "{{SITENAME}} {{PLURAL:$2|کا|کے}} گمنام {{PLURAL:$2|{{GENDER:$1|صارف}}|صارفین}} $1",
+       "pageinfo-title": "«$1» کی معلومات",
+       "pageinfo-not-current": "معذرت، پرانی ترامیم کی ان معلومات کو فراہم کرنا ناممکن ہے۔",
+       "pageinfo-header-basic": "بنیادی معلومات",
+       "pageinfo-header-edits": "تاریخچۂ ترمیم",
+       "pageinfo-header-restrictions": "صفحہ کی حفاظت",
+       "pageinfo-header-properties": "صفحہ کی خاصیتیں",
+       "pageinfo-display-title": "عنوان",
+       "pageinfo-default-sort": "کلید برائے ابتدائی ترتیب",
+       "pageinfo-length": "صفحہ کا حجم (بائٹ میں)",
+       "pageinfo-article-id": "صفحہ کی شناخت",
+       "pageinfo-language": "زبان",
+       "pageinfo-content-model": "انداز متن",
+       "pageinfo-content-model-change": "تبدیل کریں",
+       "pageinfo-robot-policy": "روبوں کی فہرست سازی",
+       "pageinfo-robot-index": "مجاز",
+       "pageinfo-robot-noindex": "ممنوع",
+       "pageinfo-watchers": "تعداد ناظرین",
+       "pageinfo-visiting-watchers": "حالیہ تبدیلیاں دیکھنے والے ناظرین کی تعداد",
+       "pageinfo-few-watchers": "$1 سے کم {{PLURAL:$1|ناظر|ناظرین}}",
+       "pageinfo-redirects-name": "رجوع مکررات کی تعداد",
+       "pageinfo-subpages-name": "اس صفحہ کے ذیلی صفحات کی تعداد",
+       "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|رجوع مکرر|رجوع مکررات}}؛ $3 {{PLURAL:$3|غیر رجوع مکرر|غیر رجوع مکررات}})",
+       "pageinfo-firstuser": "صفحہ ساز",
+       "pageinfo-firsttime": "صفحہ سازی کی تاریخ",
+       "pageinfo-lastuser": "آخری ترمیم کنندہ",
+       "pageinfo-lasttime": "آخری ترمیم کی تاریخ",
+       "pageinfo-edits": "ترامیم کی مجموعی تعداد",
+       "pageinfo-authors": "مختلف مصنفین کی مجموعی تعداد",
+       "pageinfo-recent-edits": "حالیہ ترامیم کی تعداد (گزشتہ $1 میں)",
+       "pageinfo-recent-authors": "مختلف مصنفین کی حالیہ تعداد",
+       "pageinfo-magic-words": "جادوئی {{PLURAL:$1|لفظ|الفاظ}} ($1)",
        "pageinfo-hidden-categories": "پوشیدہ {{PLURAL:$1|زمرہ|زمرہ جات}} ($1)",
+       "pageinfo-templates": "زیر استعمال {{PLURAL:$1|سانچہ|سانچے}} ($1)",
+       "pageinfo-transclusions": "($1) میں زیر استعمال {{PLURAL:$1|صفحہ|صفحات}}",
        "pageinfo-toolboxlink": "معلومات صفحہ",
+       "pageinfo-redirectsto": "رجوع مکررات برائے",
+       "pageinfo-redirectsto-info": "معلومات",
+       "pageinfo-contentpage": "شمار بطور صفحہ",
+       "pageinfo-contentpage-yes": "ہاں",
+       "pageinfo-protect-cascading-yes": "ہاں",
        "pageinfo-category-info": "زمرے کی معلومات",
+       "pageinfo-category-total": "اراکین کی مجموعی تعداد",
        "pageinfo-category-pages": "تعداد صفحات",
        "pageinfo-category-subcats": "تعداد ذیلی زمرہ جات",
        "pageinfo-category-files": "تعداد املاف",
+       "markaspatrolleddiff": "بطور مراجعت شدہ نشان زد کریں",
        "markaspatrolledtext": "اس صفحہ کو بطور مراجعت شدہ نشان زد کریں",
+       "markaspatrolledtext-file": "فائل کے اس نسخے کو مراجعت شدہ نشان زد کریں",
+       "markedaspatrolled": "مراجعت شدہ نشان زد کر دیا گیا",
        "markedaspatrollederrornotify": "بطور مراجعت نشان زد نہیں کیا جا سکا۔",
        "deletedrevision": "حذف شدہ پرانی ترمیم $1۔",
        "previousdiff": "← پُرانی تدوین",
        "newimages": "نئی فائلوں کی گیلری",
        "ilsubmit": "تلاش",
        "bydate": "بالحاظ تاریخ",
+       "seconds": "{{PLURAL:$1|$1 سیکنڈ}}",
+       "minutes": "{{PLURAL:$1|$1 منٹ}}",
+       "hours": "{{PLURAL:$1|گھنٹہ|گھنٹے}}",
+       "days": "{{PLURAL:$1|دن}}",
        "weeks": "{{PLURAL:$1|$1ہفتہ| $1  ہفتے}}",
+       "months": "{{PLURAL:$1|مہینہ|مہینے}}",
+       "years": "{{PLURAL:$1|$1 سال|$1 برس}}",
        "ago": "$1 قبل",
-       "minutes-ago": "$1 {{PLURAL:$1|منٹ|منٹ}} قبل",
-       "seconds-ago": "$1 {{PLURAL:$1|سیکنڈ|سیکنڈ}} قبل",
+       "just-now": "بس ابھی",
+       "hours-ago": "$1 {{PLURAL:$1|گھنٹہ|گھنٹے}} قبل",
+       "minutes-ago": "$1 {{PLURAL:$1|منٹ}} قبل",
+       "seconds-ago": "$1 {{PLURAL:$1|سیکنڈ}} قبل",
+       "monday-at": "پیر بوقت $1",
+       "tuesday-at": "منگل بوقت $1",
+       "wednesday-at": "بدھ بوقت $1",
+       "thursday-at": "جمعرات بوقت $1",
+       "friday-at": "جمعہ بوقت $1",
+       "saturday-at": "سنیچر بوقت $1",
+       "sunday-at": "اتوار بوقت $1",
+       "yesterday-at": "گزشتہ کل بوقت $1",
        "bad_image_list": "شکلبند درج ذیل ہے:\n\nصرف فہرستی عناصر (* سے شروع ہونے والی لکیری) شامل کی جاتی ہیں۔\nکسی لکیر میں پہلا ربط کوئی خراب ملف کا ہونا چاہئے۔\nاُسی لکیر میں باقی آنے والے ربط کو مستثنیٰ قرار دیا جاتا ہے، مثلاً صفحات جہاں ملف لکیر کے وسط میں آسکتا ہے۔",
        "metadata": "میٹا ڈیٹا",
        "metadata-help": "اِس ملف میں اِضافی معلومات شامل ہیں، جو کہ شاید اُس رقمی کیمرے یا سکینر سے آئے ہیں جس کے ذریعے یہ ملف بنائی گئی تھی۔\nاگر ملف اپنی اصل حالت میں نہیں رہی ہے تو کچھ تفاصیل ترمیم شدہ ملف کی مکمل طور پر عکاسی نہیں کرپائیں گے۔",
+       "metadata-expand": "تفصیلی معلومات دکھائیں",
        "metadata-collapse": "طویل تفاصیل چھپاؤ",
        "metadata-fields": "تصویر کے میٹاڈیٹا کے وہ خانے جو اس پیغام میں درج ہیں وہ تصویر کے صفحے پر شامل ہوتے ہیں نیز یہ اس وقت ظاہر ہوتے ہیں جب میٹاڈیٹا کو وسیع کیا جائے۔\nالبتہ دیگر خانے ابتدائی طور پر پوشیدہ ہوتے ہیں۔\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+       "exif-imagewidth": "چوڑائی",
+       "exif-imagelength": "لمبائی",
        "exif-orientation": "پیشکش",
        "exif-xresolution": "چھوڑاوی دکھاوت",
        "exif-yresolution": "لمباوی دکھاوت",
        "exif-datetime": "ملف کے تبدیلی کا تاریخ او وقت",
+       "exif-imagedescription": "تصویر کا عنوان",
        "exif-make": "کیمرے کا صانع",
        "exif-model": "کیمرے کا ماڈل",
        "exif-software": "سافٹویئر استعمال",
+       "exif-artist": "مصنف",
+       "exif-copyright": "کاپی رائٹ کا حامل",
        "exif-exifversion": "اکزیف ورژن",
        "exif-colorspace": "رنگ فضا",
+       "exif-pixelxdimension": "تصویر کی چوڑائی",
+       "exif-pixelydimension": "تصویر کی لمبائی",
+       "exif-usercomment": "صارف کے تبصرے",
        "exif-datetimeoriginal": "ڈیٹا بنانے کا تاریخ اور وقت",
        "exif-datetimedigitized": "معددی کا تاریخ اور وقت",
+       "exif-exposuretime-format": "$1 سیکنڈ ($2)",
+       "exif-fnumber": "ایف نمبر",
+       "exif-filesource": "فائل کا ماخذ",
+       "exif-gpslatitude": "عرض البلد",
        "exif-writer": "مصنف",
        "exif-languagecode": "زبان",
        "exif-iimcategory": "زمرہ",
        "feedback-thanks-title": "شکریہ!",
        "searchsuggest-search": "تلاش",
        "searchsuggest-containing": "نتائج...",
+       "duration-days": "$1 {{PLURAL:$1|دن}}",
        "expandtemplates": "سانچے کو وسیع کریں",
        "expand_templates_input": "ان پٹ متن:",
        "expand_templates_output": "نتیجہ",
index b278e98..2287559 100644 (file)
@@ -29,6 +29,8 @@ require_once __DIR__ . '/Maintenance.php';
  * @ingroup Maintenance
  */
 class RebuildFileCache extends Maintenance {
+       private $enabled = true;
+
        public function __construct() {
                parent::__construct();
                $this->addDescription( 'Build file cache for content pages' );
@@ -39,23 +41,27 @@ class RebuildFileCache extends Maintenance {
        }
 
        public function finalSetup() {
-               global $wgDebugToolbar;
+               global $wgDebugToolbar, $wgUseFileCache, $wgReadOnly;
 
+               $this->enabled = $wgUseFileCache;
+               // Script will handle capturing output and saving it itself
+               $wgUseFileCache = false;
                // Debug toolbar makes content uncacheable so we disable it.
                // Has to be done before Setup.php initialize MWDebug
                $wgDebugToolbar = false;
+               //  Avoid DB writes (like enotif/counters)
+               $wgReadOnly = 'Building cache'; // avoid DB writes (like enotif/counters)
+
                parent::finalSetup();
        }
 
        public function execute() {
-               global $wgUseFileCache, $wgReadOnly, $wgRequestTime;
-               global $wgOut;
-               if ( !$wgUseFileCache ) {
+               global $wgRequestTime;
+
+               if ( !$this->enabled ) {
                        $this->error( "Nothing to do -- \$wgUseFileCache is disabled.", true );
                }
 
-               $wgReadOnly = 'Building cache'; // avoid DB writes (like enotif/counters)
-
                $start = $this->getOption( 'start', "0" );
                if ( !ctype_digit( $start ) ) {
                        $this->error( "Invalid value for start parameter.", true );
@@ -90,6 +96,7 @@ class RebuildFileCache extends Maintenance {
                $blockEnd = $start + $this->mBatchSize - 1;
 
                $dbw = $this->getDB( DB_MASTER );
+               $mainContext = RequestContext::getMain();
                // Go through each page and save the output
                while ( $blockEnd <= $end ) {
                        // Get the pages
@@ -104,7 +111,6 @@ class RebuildFileCache extends Maintenance {
                        $this->beginTransaction( $dbw, __METHOD__ ); // for any changes
                        foreach ( $res as $row ) {
                                $rebuilt = false;
-                               $wgRequestTime = microtime( true ); # bug 22852
 
                                $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
                                if ( null == $title ) {
@@ -112,39 +118,52 @@ class RebuildFileCache extends Maintenance {
                                        continue; // broken title?
                                }
 
-                               $context = new RequestContext;
+                               $context = new RequestContext();
                                $context->setTitle( $title );
                                $article = Article::newFromTitle( $title, $context );
                                $context->setWikiPage( $article->getPage() );
 
-                               $wgOut = $context->getOutput(); // set display title
-
                                // If the article is cacheable, then load it
-                               if ( $article->isFileCacheable() ) {
-                                       $cache = new HTMLFileCache( $title, 'view' );
-                                       if ( $cache->isCacheGood() ) {
+                               if ( $article->isFileCacheable( HTMLFileCache::MODE_REBUILD ) ) {
+                                       $viewCache = new HTMLFileCache( $title, 'view' );
+                                       $historyCache = new HTMLFileCache( $title, 'history' );
+                                       if ( $viewCache->isCacheGood() && $historyCache->isCacheGood() ) {
                                                if ( $overwrite ) {
                                                        $rebuilt = true;
                                                } else {
-                                                       $this->output( "Page {$row->page_id} already cached\n" );
+                                                       $this->output( "Page '$title' (id {$row->page_id}) already cached\n" );
                                                        continue; // done already!
                                                }
                                        }
-                                       ob_start( [ &$cache, 'saveToFileCache' ] ); // save on ob_end_clean()
-                                       $wgUseFileCache = false; // hack, we don't want $article fiddling with filecache
-                                       $article->view();
+
                                        MediaWiki\suppressWarnings(); // header notices
-                                       $wgOut->output();
+                                       // Cache ?action=view
+                                       $wgRequestTime = microtime( true ); # bug 22852
+                                       ob_start();
+                                       $article->view();
+                                       $context->getOutput()->output();
+                                       $context->getOutput()->clearHTML();
+                                       $viewHtml = ob_get_clean();
+                                       $viewCache->saveToFileCache( $viewHtml );
+                                       // Cache ?action=history
+                                       $wgRequestTime = microtime( true ); # bug 22852
+                                       ob_start();
+                                       Action::factory( 'history', $article, $context )->show();
+                                       $context->getOutput()->output();
+                                       $context->getOutput()->clearHTML();
+                                       $historyHtml = ob_get_clean();
+                                       $historyCache->saveToFileCache( $historyHtml );
                                        MediaWiki\restoreWarnings();
-                                       $wgUseFileCache = true;
-                                       ob_end_clean(); // clear buffer
+
                                        if ( $rebuilt ) {
-                                               $this->output( "Re-cached page {$row->page_id}\n" );
+                                               $this->output( "Re-cached page '$title' (id {$row->page_id})..." );
                                        } else {
-                                               $this->output( "Cached page {$row->page_id}\n" );
+                                               $this->output( "Cached page '$title' (id {$row->page_id})..." );
                                        }
+                                       $this->output( "[view: " . strlen( $viewHtml ) . " bytes; " .
+                                               "history: " . strlen( $historyHtml ) . " bytes]\n" );
                                } else {
-                                       $this->output( "Page {$row->page_id} not cacheable\n" );
+                                       $this->output( "Page '$title' (id {$row->page_id}) not cacheable\n" );
                                }
                        }
                        $this->commitTransaction( $dbw, __METHOD__ ); // commit any changes (just for sanity)
index f29897c..3cc94b8 100644 (file)
@@ -23,7 +23,7 @@
                height: auto;
                margin: 0 0.1em 0 0;
                padding: 0;
-               border: 1px solid @colorFieldBorder;
+               border: 1px solid @colorGray7;
                cursor: pointer;
        }
 }
@@ -61,7 +61,7 @@
 
 .button-colors( @bgColor, @highlightColor, @activeColor ) when ( lightness( @bgColor ) >= 70% ) {
        color: @colorButtonText;
-       border: 1px solid @colorGray12;
+       border: 1px solid @colorFieldBorder;
 
        &:hover,
        &:active,
 .button-colors-quiet( @textColor, @highlightColor, @activeColor ) {
        // Quiet buttons all start gray, and reveal
        // constructive/progressive/destructive color on hover and active.
-       color: @colorButtonText;
+       color: @textColor;
 
-       &:hover,
-       &:focus {
+       &:hover {
                background-color: transparent;
-               color: @textColor;
+               color: @highlightColor;
        }
 
        &:active,
                color: @activeColor;
        }
 
+       &:focus {
+               background-color: transparent;
+               color: @textColor;
+       }
+
        &:disabled {
                color: @colorDisabledText;
        }
index b6f6568..77e80b0 100644 (file)
@@ -2,13 +2,13 @@
 
 // Although this defines many shades, be parsimonious in your own use of grays. Prefer
 // colors already in use in MediaWiki. Prefer semantic color names such as "@colorText".
-@colorGray1: #111; // darkest
+@colorGray1: #000; // darkest
 @colorGray2: #222;
 @colorGray3: #333;
 @colorGray4: #444;
 @colorGray5: #555;
 @colorGray6: #666;
-@colorGray7: #777;
+@colorGray7: #72777d;
 @colorGray8: #888;
 @colorGray9: #999;
 @colorGray10: #aaa;
 @colorGray12: #ccc;
 @colorGray13: #ddd;
 @colorGray14: #eee;
-@colorGray15: #f9f9f9; // lightest
+@colorGray15: #f8f9fa; // lightest
 
 // Semantic background colors
 // Blue; for contextual use of a continuing action
-@colorProgressive: #347bff;
-@colorProgressiveHighlight: #2962cc;
-@colorProgressiveActive: #2962cc;
-// Green; for contextual use of a positive finalizing action
-@colorConstructive: #00af89;
-@colorConstructiveHighlight: #008c6d;
-@colorConstructiveActive: #008c6d;
+@colorProgressive: #36c;
+@colorProgressiveHighlight: #447ff5;
+@colorProgressiveActive: #2a4b8d;
 // Orange; for contextual use of returning to a past action
 @colorRegressive: #ff5d00;
 // Red; for contextual use of a negative action of high severity
-@colorDestructive: #d11d13;
-@colorDestructiveHighlight: #a7170f;
-@colorDestructiveActive: #a7170f;
+@colorDestructive: #c33;
+@colorDestructiveHighlight: #e53939;
+@colorDestructiveActive: #873636;
 // Orange; for contextual use of a potentially negative action of medium severity
 @colorMediumSevere: #ff5d00;
 // Yellow; for contextual use of a potentially negative action of low severity
-@colorLowSevere: #ffb50d;
+@colorLowSevere: #fc3;
 
 // Used in mixins to darken contextual colors by the same amount (eg. focus)
 @colorDarkenPercentage: 13.5%;
 // Text colors
 @colorText: @colorGray2;
 @colorTextLight: @colorGray6;
-@colorButtonText: @colorGray5;
-@colorButtonTextHighlight: @colorGray7;
-@colorButtonTextActive: @colorGray7;
+@colorButtonText: @colorGray2;
+@colorButtonTextHighlight: @colorGray4;
+@colorButtonTextActive: @colorGray1;
 @colorDisabledText: @colorGray12;
 @colorErrorText: #c00;
 @colorWarningText: #705000;
 
 // UI colors
-@colorFieldBorder: @colorGray12;
+@colorFieldBorder: #9aa0a7;
 @colorShadow: @colorGray14;
 @colorPlaceholder: @colorGray10;
 @colorNeutral: @colorGray7;
 
-// The following rules are deprecated
-@colorWhite: #fff;
-@colorOffWhite: #fafafa;
-@colorGrayDark: #898989;
-@colorGrayLight: #ccc;
-@colorGrayLighter: #ddd;
-@colorGrayLightest: #eee;
-
 // Global border radius to be used to buttons and inputs
 @borderRadius: 2px;
 
 // Form input sizes
 @checkboxSize: 2em;
 @radioSize: 2em;
+
+// The following rules are deprecated
+@colorWhite: #fff;
+@colorOffWhite: #fafafa;
+@colorGrayDark: #898989;
+@colorGrayLight: #ccc;
+@colorGrayLighter: #ddd;
+@colorGrayLightest: #eee;
+// Green; for contextual use of a positive finalizing action
+@colorConstructive: #00af89;
+@colorConstructiveHighlight: #1c6665;
+@colorConstructiveActive: #134645;
+
index 753f774..cf77a96 100644 (file)
 
 /* Login Button, following `ButtonWidget (progressive)‎` from OOjs UI */
 #mw-createaccount-join {
-       color: #347bff;
+       background-color: #f8f9fa;
+       color: #36c;
 }
 #mw-createaccount-join:hover {
-       background-color: #ebf2ff; /* rgba( 52, 123, 255, 0.1 ); */
+       background-color: #fff;
        border-color: #859ecc;
        box-shadow: none;
 }
 #mw-createaccount-join:active {
-       background-color: #ebf2ff;
-       color: #1f4999;
-       border-color: #1f4999;
+       background-color: #eff3fa;
+       color: #2a4b8d;
+       border-color: #2a4b8d;
 }
 #mw-createaccount-join:focus {
-       background-color: #fff;
-       color: #1f4999;
-       border-color: #1f4999;
-       box-shadow: inset 0 0 0 1px #1f4999;
-}
-#mw-createaccount-join:active:focus {
-       background-color: #ebf2ff;
+       border-color: #36c;
+       box-shadow: inset 0 0 0 1px #36c;
 }
index 9d30eb8..4d90496 100644 (file)
 
 .mw-widget-calendarWidget:focus {
        outline: none;
-       box-shadow: inset 0 0 0 2px #347bff;
+       box-shadow: inset 0 0 0 2px #36c;
 }
 
 .mw-widget-calendarWidget-day {
index 86018a4..46e6b62 100644 (file)
 
        &.oo-ui-widget-enabled {
                .mw-widget-dateInputWidget-handle:hover {
-                       border-color: #347bff;
+                       border-color: #36c;
                }
        }
 
index 68062d0..03df086 100644 (file)
@@ -30,6 +30,6 @@
 }
 
 .mw-upload-bookletLayout-filePreview .oo-ui-progressBarWidget-bar {
-       background-color: #347bff;
+       background-color: #36c;
        height: 0.5em;
 }
\ No newline at end of file
index 39e90c2..5358f29 100644 (file)
@@ -9,11 +9,12 @@ class ApiOpenSearchTest extends MediaWikiTestCase {
                        ->method( 'getSearchTypes' )
                        ->will( $this->returnValue( [ 'the one ring' ] ) );
 
+               $api = $this->createApi();
                $engine = $this->replaceSearchEngine();
                $engine->expects( $this->any() )
                        ->method( 'getProfiles' )
                        ->will( $this->returnValueMap( [
-                               [ SearchEngine::COMPLETION_PROFILE_TYPE, [
+                               [ SearchEngine::COMPLETION_PROFILE_TYPE, $api->getUser(), [
                                        [
                                                'name' => 'normal',
                                                'desc-message' => 'normal-message',
@@ -26,7 +27,6 @@ class ApiOpenSearchTest extends MediaWikiTestCase {
                                ] ],
                        ] ) );
 
-               $api = $this->createApi();
                $params = $api->getAllowedParams();
 
                $this->assertArrayNotHasKey( 'offset', $params );
index 7c0063d..48472cf 100644 (file)
@@ -1323,350 +1323,6 @@ class ApiResultTest extends MediaWikiTestCase {
                ], ApiResult::addMetadataToResultVars( $arr ) );
        }
 
-       /**
-        * @covers ApiResult
-        */
-       public function testDeprecatedFunctions() {
-               // Ignore ApiResult deprecation warnings during this test
-               set_error_handler( function ( $errno, $errstr ) use ( &$warnings ) {
-                       if ( preg_match( '/Use of ApiResult::\S+ was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
-                               return true;
-                       }
-                       if ( preg_match( '/Use of ApiMain to ApiResult::__construct ' .
-                               'was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
-                               return true;
-                       }
-                       return false;
-               } );
-               $reset = new ScopedCallback( 'restore_error_handler' );
-
-               $context = new DerivativeContext( RequestContext::getMain() );
-               $context->setConfig( new HashConfig( [
-                       'APIModules' => [],
-                       'APIFormatModules' => [],
-                       'APIMaxResultSize' => 42,
-               ] ) );
-               $main = new ApiMain( $context );
-               $result = TestingAccessWrapper::newFromObject( new ApiResult( $main ) );
-               $this->assertSame( 42, $result->maxSize );
-               $this->assertSame( $main->getErrorFormatter(), $result->errorFormatter );
-               $this->assertSame( $main, $result->mainForContinuation );
-
-               $result = new ApiResult( 8388608 );
-
-               $result->addContentValue( null, 'test', 'content' );
-               $result->addContentValue( [ 'foo', 'bar' ], 'test', 'content' );
-               $result->addIndexedTagName( null, 'itn' );
-               $result->addSubelementsList( null, [ 'sub' ] );
-               $this->assertSame( [
-                       'foo' => [
-                               'bar' => [
-                                       '*' => 'content',
-                               ],
-                       ],
-                       '*' => 'content',
-               ], $result->getData() );
-
-               $arr = [];
-               ApiResult::setContent( $arr, 'value' );
-               ApiResult::setContent( $arr, 'value2', 'foobar' );
-               $this->assertSame( [
-                       ApiResult::META_CONTENT => 'content',
-                       'content' => 'value',
-                       'foobar' => [
-                               ApiResult::META_CONTENT => 'content',
-                               'content' => 'value2',
-                       ],
-               ], $arr );
-
-               $result = new ApiResult( 3 );
-               $formatter = new ApiErrorFormatter_BackCompat( $result );
-               $result->setErrorFormatter( $formatter );
-               $result->disableSizeCheck();
-               $this->assertTrue( $result->addValue( null, 'foo', '1234567890' ) );
-               $result->enableSizeCheck();
-               $this->assertSame( 0, $result->getSize() );
-               $this->assertFalse( $result->addValue( null, 'foo', '1234567890' ) );
-
-               $arr = [ 'foo' => [ 'bar' => 1 ] ];
-               $result->setIndexedTagName_recursive( $arr, 'itn' );
-               $this->assertSame( [
-                       'foo' => [
-                               'bar' => 1,
-                               ApiResult::META_INDEXED_TAG_NAME => 'itn'
-                       ],
-               ], $arr );
-
-               $status = Status::newGood();
-               $status->fatal( 'parentheses', '1' );
-               $status->fatal( 'parentheses', '2' );
-               $status->warning( 'parentheses', '3' );
-               $status->warning( 'parentheses', '4' );
-               $this->assertSame( [
-                       [
-                               'type' => 'error',
-                               'message' => 'parentheses',
-                               'params' => [
-                                       0 => '1',
-                                       ApiResult::META_INDEXED_TAG_NAME => 'param',
-                               ],
-                       ],
-                       [
-                               'type' => 'error',
-                               'message' => 'parentheses',
-                               'params' => [
-                                       0 => '2',
-                                       ApiResult::META_INDEXED_TAG_NAME => 'param',
-                               ],
-                       ],
-                       ApiResult::META_INDEXED_TAG_NAME => 'error',
-               ], $result->convertStatusToArray( $status, 'error' ) );
-               $this->assertSame( [
-                       [
-                               'type' => 'warning',
-                               'message' => 'parentheses',
-                               'params' => [
-                                       0 => '3',
-                                       ApiResult::META_INDEXED_TAG_NAME => 'param',
-                               ],
-                       ],
-                       [
-                               'type' => 'warning',
-                               'message' => 'parentheses',
-                               'params' => [
-                                       0 => '4',
-                                       ApiResult::META_INDEXED_TAG_NAME => 'param',
-                               ],
-                       ],
-                       ApiResult::META_INDEXED_TAG_NAME => 'warning',
-               ], $result->convertStatusToArray( $status, 'warning' ) );
-       }
-
-       /**
-        * @covers ApiResult
-        */
-       public function testDeprecatedContinuation() {
-               // Ignore ApiResult deprecation warnings during this test
-               set_error_handler( function ( $errno, $errstr ) use ( &$warnings ) {
-                       if ( preg_match( '/Use of ApiResult::\S+ was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
-                               return true;
-                       }
-                       return false;
-               } );
-
-               $reset = new ScopedCallback( 'restore_error_handler' );
-               $allModules = [
-                       new MockApiQueryBase( 'mock1' ),
-                       new MockApiQueryBase( 'mock2' ),
-                       new MockApiQueryBase( 'mocklist' ),
-               ];
-               $generator = new MockApiQueryBase( 'generator' );
-
-               $main = new ApiMain( RequestContext::getMain() );
-               $result = new ApiResult( 8388608 );
-               $result->setMainForContinuation( $main );
-               $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
-               $this->assertSame( [ false, $allModules ], $ret );
-               $result->setContinueParam( $allModules[0], 'm1continue', [ 1, 2 ] );
-               $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
-               $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 );
-               $result->endContinuation( 'raw' );
-               $result->endContinuation( 'standard' );
-               $this->assertSame( [
-                       'mlcontinue' => 2,
-                       'm1continue' => '1|2',
-                       'continue' => '||mock2',
-               ], $result->getResultData( 'continue' ) );
-               $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
-               $this->assertSame( [
-                       'mock1' => [ 'm1continue' => '1|2' ],
-                       'mocklist' => [ 'mlcontinue' => 2 ],
-                       'generator' => [ 'gcontinue' => 3 ],
-               ], $result->getResultData( 'query-continue' ) );
-               $main->setContinuationManager( null );
-
-               $result = new ApiResult( 8388608 );
-               $result->setMainForContinuation( $main );
-               $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
-               $this->assertSame( [ false, $allModules ], $ret );
-               $result->setContinueParam( $allModules[0], 'm1continue', [ 1, 2 ] );
-               $result->setGeneratorContinueParam( $generator, 'gcontinue', [ 3, 4 ] );
-               $result->endContinuation( 'raw' );
-               $result->endContinuation( 'standard' );
-               $this->assertSame( [
-                       'm1continue' => '1|2',
-                       'continue' => '||mock2|mocklist',
-               ], $result->getResultData( 'continue' ) );
-               $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
-               $this->assertSame( [
-                       'mock1' => [ 'm1continue' => '1|2' ],
-                       'generator' => [ 'gcontinue' => '3|4' ],
-               ], $result->getResultData( 'query-continue' ) );
-               $main->setContinuationManager( null );
-
-               $result = new ApiResult( 8388608 );
-               $result->setMainForContinuation( $main );
-               $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
-               $this->assertSame( [ false, $allModules ], $ret );
-               $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
-               $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 );
-               $result->endContinuation( 'raw' );
-               $result->endContinuation( 'standard' );
-               $this->assertSame( [
-                       'mlcontinue' => 2,
-                       'gcontinue' => 3,
-                       'continue' => 'gcontinue||',
-               ], $result->getResultData( 'continue' ) );
-               $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
-               $this->assertSame( [
-                       'mocklist' => [ 'mlcontinue' => 2 ],
-                       'generator' => [ 'gcontinue' => 3 ],
-               ], $result->getResultData( 'query-continue' ) );
-               $main->setContinuationManager( null );
-
-               $result = new ApiResult( 8388608 );
-               $result->setMainForContinuation( $main );
-               $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
-               $this->assertSame( [ false, $allModules ], $ret );
-               $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 );
-               $result->endContinuation( 'raw' );
-               $result->endContinuation( 'standard' );
-               $this->assertSame( [
-                       'gcontinue' => 3,
-                       'continue' => 'gcontinue||mocklist',
-               ], $result->getResultData( 'continue' ) );
-               $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
-               $this->assertSame( [
-                       'generator' => [ 'gcontinue' => 3 ],
-               ], $result->getResultData( 'query-continue' ) );
-               $main->setContinuationManager( null );
-
-               $result = new ApiResult( 8388608 );
-               $result->setMainForContinuation( $main );
-               $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
-               $this->assertSame( [ false, $allModules ], $ret );
-               $result->setContinueParam( $allModules[0], 'm1continue', [ 1, 2 ] );
-               $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
-               $result->endContinuation( 'raw' );
-               $result->endContinuation( 'standard' );
-               $this->assertSame( [
-                       'mlcontinue' => 2,
-                       'm1continue' => '1|2',
-                       'continue' => '||mock2',
-               ], $result->getResultData( 'continue' ) );
-               $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
-               $this->assertSame( [
-                       'mock1' => [ 'm1continue' => '1|2' ],
-                       'mocklist' => [ 'mlcontinue' => 2 ],
-               ], $result->getResultData( 'query-continue' ) );
-               $main->setContinuationManager( null );
-
-               $result = new ApiResult( 8388608 );
-               $result->setMainForContinuation( $main );
-               $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
-               $this->assertSame( [ false, $allModules ], $ret );
-               $result->setContinueParam( $allModules[0], 'm1continue', [ 1, 2 ] );
-               $result->endContinuation( 'raw' );
-               $result->endContinuation( 'standard' );
-               $this->assertSame( [
-                       'm1continue' => '1|2',
-                       'continue' => '||mock2|mocklist',
-               ], $result->getResultData( 'continue' ) );
-               $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
-               $this->assertSame( [
-                       'mock1' => [ 'm1continue' => '1|2' ],
-               ], $result->getResultData( 'query-continue' ) );
-               $main->setContinuationManager( null );
-
-               $result = new ApiResult( 8388608 );
-               $result->setMainForContinuation( $main );
-               $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
-               $this->assertSame( [ false, $allModules ], $ret );
-               $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
-               $result->endContinuation( 'raw' );
-               $result->endContinuation( 'standard' );
-               $this->assertSame( [
-                       'mlcontinue' => 2,
-                       'continue' => '-||mock1|mock2',
-               ], $result->getResultData( 'continue' ) );
-               $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
-               $this->assertSame( [
-                       'mocklist' => [ 'mlcontinue' => 2 ],
-               ], $result->getResultData( 'query-continue' ) );
-               $main->setContinuationManager( null );
-
-               $result = new ApiResult( 8388608 );
-               $result->setMainForContinuation( $main );
-               $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
-               $this->assertSame( [ false, $allModules ], $ret );
-               $result->endContinuation( 'raw' );
-               $result->endContinuation( 'standard' );
-               $this->assertSame( null, $result->getResultData( 'continue' ) );
-               $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
-               $this->assertSame( null, $result->getResultData( 'query-continue' ) );
-               $main->setContinuationManager( null );
-
-               $result = new ApiResult( 8388608 );
-               $result->setMainForContinuation( $main );
-               $ret = $result->beginContinuation( '||mock2', $allModules, [ 'mock1', 'mock2' ] );
-               $this->assertSame(
-                       [ false, array_values( array_diff_key( $allModules, [ 1 => 1 ] ) ) ],
-                       $ret
-               );
-               $main->setContinuationManager( null );
-
-               $result = new ApiResult( 8388608 );
-               $result->setMainForContinuation( $main );
-               $ret = $result->beginContinuation( '-||', $allModules, [ 'mock1', 'mock2' ] );
-               $this->assertSame(
-                       [ true, array_values( array_diff_key( $allModules, [ 0 => 0, 1 => 1 ] ) ) ],
-                       $ret
-               );
-               $main->setContinuationManager( null );
-
-               $result = new ApiResult( 8388608 );
-               $result->setMainForContinuation( $main );
-               try {
-                       $result->beginContinuation( 'foo', $allModules, [ 'mock1', 'mock2' ] );
-                       $this->fail( 'Expected exception not thrown' );
-               } catch ( UsageException $ex ) {
-                       $this->assertSame(
-                               'Invalid continue param. You should pass the original value returned by the previous query',
-                               $ex->getMessage(),
-                               'Expected exception'
-                       );
-               }
-               $main->setContinuationManager( null );
-
-               $result = new ApiResult( 8388608 );
-               $result->setMainForContinuation( $main );
-               $result->beginContinuation( '||mock2', array_slice( $allModules, 0, 2 ),
-                       [ 'mock1', 'mock2' ] );
-               try {
-                       $result->setContinueParam( $allModules[1], 'm2continue', 1 );
-                       $this->fail( 'Expected exception not thrown' );
-               } catch ( UnexpectedValueException $ex ) {
-                       $this->assertSame(
-                               'Module \'mock2\' was not supposed to have been executed, but it was executed anyway',
-                               $ex->getMessage(),
-                               'Expected exception'
-                       );
-               }
-               try {
-                       $result->setContinueParam( $allModules[2], 'mlcontinue', 1 );
-                       $this->fail( 'Expected exception not thrown' );
-               } catch ( UnexpectedValueException $ex ) {
-                       $this->assertSame(
-                               'Module \'mocklist\' called ApiContinuationManager::addContinueParam ' .
-                                       'but was not passed to ApiContinuationManager::__construct',
-                               $ex->getMessage(),
-                               'Expected exception'
-                       );
-               }
-               $main->setContinuationManager( null );
-
-       }
-
        public function testObjectSerialization() {
                $arr = [];
                ApiResult::setValue( $arr, 'foo', (object)[ 'a' => 1, 'b' => 2 ] );