Merge "Create tooltip for "Page information" link"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 14 Oct 2014 18:31:20 +0000 (18:31 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 14 Oct 2014 18:31:20 +0000 (18:31 +0000)
90 files changed:
RELEASE-NOTES-1.25
docs/hooks.txt
includes/AutoLoader.php
includes/DefaultSettings.php
includes/api/ApiBase.php
includes/api/ApiFormatBase.php
includes/api/ApiFormatDbg.php
includes/api/ApiFormatDump.php
includes/api/ApiFormatJson.php
includes/api/ApiFormatNone.php
includes/api/ApiFormatPhp.php
includes/api/ApiFormatRaw.php
includes/api/ApiFormatTxt.php
includes/api/ApiFormatWddx.php
includes/api/ApiFormatXml.php
includes/api/ApiFormatYaml.php
includes/api/ApiHelp.php
includes/api/ApiMain.php
includes/api/ApiParamInfo.php
includes/api/ApiParse.php
includes/api/ApiQuery.php
includes/api/ApiQueryBase.php
includes/api/ApiResult.php
includes/api/ApiTokens.php
includes/api/ApiWatch.php
includes/api/i18n/en.json [new file with mode: 0644]
includes/api/i18n/qqq.json [new file with mode: 0644]
includes/db/ORMTable.php
includes/installer/i18n/ja.json
includes/installer/i18n/ko.json
includes/specialpage/SpecialPageFactory.php
includes/specials/SpecialApiHelp.php [new file with mode: 0644]
includes/specials/SpecialContributions.php
includes/specials/SpecialDeletedContributions.php
includes/specials/SpecialListfiles.php
includes/specials/SpecialNewpages.php
includes/templates/Usercreate.php
includes/templates/Userlogin.php
languages/i18n/ar.json
languages/i18n/bn.json
languages/i18n/ca.json
languages/i18n/cdo.json
languages/i18n/da.json
languages/i18n/de.json
languages/i18n/diq.json
languages/i18n/en.json
languages/i18n/eo.json
languages/i18n/es.json
languages/i18n/eu.json
languages/i18n/fa.json
languages/i18n/fi.json
languages/i18n/fr.json
languages/i18n/he.json
languages/i18n/hy.json
languages/i18n/ja.json
languages/i18n/kk-cyrl.json
languages/i18n/ko.json
languages/i18n/lrc.json
languages/i18n/mk.json
languages/i18n/mt.json
languages/i18n/nap.json
languages/i18n/nb.json
languages/i18n/pa.json
languages/i18n/pl.json
languages/i18n/pms.json
languages/i18n/qqq.json
languages/i18n/ru.json
languages/i18n/rue.json
languages/i18n/sah.json
languages/i18n/sc.json
languages/i18n/sk.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/sv.json
languages/i18n/uz.json
languages/i18n/wuu.json
languages/i18n/zh-hant.json
languages/messages/MessagesEn.php
resources/Resources.php
resources/src/mediawiki.special/mediawiki.special.changeslist.legend.css
resources/src/mediawiki/mediawiki.apihelp.css [new file with mode: 0644]
resources/src/mediawiki/mediawiki.apipretty.css [new file with mode: 0644]
tests/phpunit/includes/api/ApiMainTest.php
tests/phpunit/includes/api/PrefixUniquenessTest.php
tests/phpunit/includes/api/format/ApiFormatTestBase.php
tests/phpunit/includes/api/query/ApiQueryContinue2Test.php
tests/phpunit/includes/api/query/ApiQueryContinueTest.php
tests/phpunit/includes/db/ORMTableTest.php
tests/phpunit/includes/db/TestORMRowTest.php
tests/phpunit/includes/installer/DatabaseUpdaterTest.php

index 862b132..93f3be8 100644 (file)
@@ -31,8 +31,65 @@ production.
 === Action API changes in 1.25 ===
 * (bug 65403) XML tag highlighting is now only performed for formats
   "xmlfm" and "wddxfm".
+* action=paraminfo supports generalized submodules (modules=query+value),
+  querymodules and formatmodules are deprecated
+* action=paraminfo no longer outputs descriptions and other help text by
+  default. If needed, it may be requested using the new 'helpformat' parameter.
+* action=help has been completely rewritten, and outputs help in HTML
+  rather than plain text.
+* Hitting api.php without specifying an action now displays only the help for
+  the main module, with links to submodule help.
+* API help is no longer displayed on errors.
+* Internationalized messages returned by the API will be in the wiki's content
+  language by default. 'uselang' is now a recognized API parameter;
+  "uselang=user" may be used to select the language from the current user's
+  preferences.
+* Default output format for the API is now jsonfm.
+* Simplified continuation will return a "batchcomplete" property in the result
+  when a batch of pages is complete.
+* Pretty-printed HTML output now has nicer formatting and (if available)
+  better syntax highlighting.
 
 === Action API internal changes in 1.25 ===
+* ApiHelp has been rewritten to support i18n and paginated HTML output.
+  Most existing modules should continue working without changes, but should do
+  the following:
+  * Add an i18n message "apihelp-{$moduleName}-description" to replace getDescription().
+  * Add i18n messages "apihelp-{$moduleName}-param-{$param}" for each parameter
+    to replace getParamDescription(). If necessary, the settings array returned
+    by getParams() can use the new ApiBase::PARAM_HELP_MSG key to override the
+    message.
+  * Implement getExamplesMessages() to replace getExamples().
+* Modules with submodules (like action=query) must have their submodules
+  override ApiBase::getParent() to return the correct parent object.
+* The 'APIGetDescription' and 'APIGetParamDescription' hooks are deprecated,
+  and will have no effect for modules using i18n messages. Use
+  'APIGetDescriptionMessages' and 'APIGetParamDescriptionMessages' instead.
+* Api formatters will no longer be asked to display the help screen on errors.
+* ApiMain::getCredits() was removed. The credits are available in the
+  'api-credits' i18n message.
+* ApiFormatBase has been changed to support i18n and syntax highlighting via
+  extensions with the new 'ApiFormatHighlight' hook. Core syntax highlighting
+  has been removed.
+* ApiFormatBase now always buffers. Output is done when
+  ApiFormatBase::closePrinter is called.
+* The following methods have been deprecated and may be removed in a future
+  release:
+  * ApiBase::getDescription
+  * ApiBase::getParamDescription
+  * ApiBase::getExamples
+  * ApiBase::makeHelpMsg
+  * ApiBase::makeHelpArrayToString
+  * ApiBase::makeHelpMsgParameters
+  * ApiFormatBase::setUnescapeAmps
+  * ApiFormatBase::getWantsHelp
+  * ApiFormatBase::setHelp
+  * ApiFormatBase::formatHTML
+  * ApiFormatBase::setBufferResult
+  * ApiFormatBase::getDescription
+  * ApiMain::setHelp
+  * ApiMain::reallyMakeHelpMsg
+  * ApiMain::makeHelpMsgHeader
 
 === Languages updated in 1.25 ===
 
index d862983..c60cc76 100644 (file)
@@ -379,20 +379,41 @@ $editPage : the EditPage object
 $text : the new text of the article (has yet to be saved)
 &$resultArr : data in this array will be added to the API result
 
+'ApiFormatHighlight': Use to syntax-highlight API pretty-printed output. When
+highlighting, add output to $context->getOutput() and return false.
+$context: An IContextSource.
+$text: Text to be highlighted.
+$mime: MIME type of $text.
+$format: API format code for $text.
+
 'APIGetAllowedParams': Use this hook to modify a module's parameters.
 &$module: ApiBase Module object
 &$params: Array of parameters
 $flags: int zero or OR-ed flags like ApiBase::GET_VALUES_FOR_HELP
 
-'APIGetDescription': Use this hook to modify a module's description.
+'APIGetDescription': DEPRECATED! Use APIGetDescriptionMessages instead.
+Use this hook to modify a module's description.
 &$module: ApiBase Module object
-&$desc: Array of descriptions
+&$desc: String description, or array of description strings
+
+'APIGetDescriptionMessages': Use this hook to modify a module's help message.
+$module: ApiBase Module object
+&$msg: Array of Message objects
 
-'APIGetParamDescription': Use this hook to modify a module's parameter
-descriptions.
+'APIGetParamDescription': DEPRECATED! Use APIGetParamDescriptionMessages instead.
+Use this hook to modify a module's parameter descriptions.
 &$module: ApiBase Module object
 &$desc: Array of parameter descriptions
 
+'APIGetParamDescriptionMessages': Use this hook to modify a module's parameter descriptions.
+$module: ApiBase Module object
+&$msg: Array of arrays of Message objects
+
+'APIHelpModifyOutput': Use this hook to modify an API module's help output.
+$module: ApiBase Module object
+&$help: Array of HTML strings to be joined for the output.
+$options: Array Options passed to ApiHelp::getHelp
+
 'APIQueryAfterExecute': After calling the execute() method of an
 action=query submodule. Use this to extend core API modules.
 &$module: Module object
index 2a45fc3..cd6a8ca 100644 (file)
@@ -1023,6 +1023,7 @@ $wgAutoloadLocalClasses = array(
        'SpecialAllMessages' => 'includes/specials/SpecialAllMessages.php',
        'SpecialAllMyUploads' => 'includes/specials/SpecialMyRedirectPages.php',
        'SpecialAllPages' => 'includes/specials/SpecialAllPages.php',
+       'SpecialApiHelp' => 'includes/specials/SpecialApiHelp.php',
        'SpecialBlankpage' => 'includes/specials/SpecialBlankpage.php',
        'SpecialBlock' => 'includes/specials/SpecialBlock.php',
        'SpecialBlockList' => 'includes/specials/SpecialBlockList.php',
index f2453e8..0cfa8c4 100644 (file)
@@ -6167,6 +6167,7 @@ $wgExtensionMessagesFiles = array();
  */
 $wgMessagesDirs = array(
        'core' => "$IP/languages/i18n",
+       'api' => "$IP/includes/api/i18n",
        'oojs-ui' => "$IP/resources/lib/oojs-ui/i18n",
 );
 
index 7bc3f71..a214f2e 100644 (file)
@@ -64,6 +64,16 @@ abstract class ApiBase extends ContextSource {
        // Boolean, if MIN/MAX are set, enforce (die) these?
        // Only applies if TYPE='integer' Use with extreme caution
        const PARAM_RANGE_ENFORCE = 9;
+       /// @since 1.25
+       // Specify an alternative i18n message for this help parameter.
+       // Value can be a string key, an array giving key and parameters, or a
+       // Message object.
+       const PARAM_HELP_MSG = 10;
+       /// @since 1.25
+       // Specify additional i18n messages to append to the normal message. Value
+       // is an array of any of strings giving the message key, arrays giving key and
+       // parameters, or Message objects.
+       const PARAM_HELP_MSG_APPEND = 11;
 
        const LIMIT_BIG1 = 500; // Fast query, std user limit
        const LIMIT_BIG2 = 5000; // Fast query, bot/sysop limit
@@ -143,27 +153,64 @@ abstract class ApiBase extends ContextSource {
        }
 
        /**
-        * Returns the description string for this module
-        * @return string|array
+        * Returns usage examples for this module.
+        *
+        * Return value has query strings as keys, with values being either strings
+        * (message key), arrays (message key + parameter), or Message objects.
+        *
+        * Do not call this base class implementation when overriding this method.
+        *
+        * @since 1.25
+        * @return array
         */
-       protected function getDescription() {
-               return false;
-       }
+       protected function getExamplesMessages() {
+               // Fall back to old non-localised method
+               $ret = array();
+
+               $examples = $this->getExamples();
+               if ( $examples ) {
+                       if ( !is_array( $examples ) ) {
+                               $examples = array( $examples );
+                       } elseif ( $examples && ( count( $examples ) & 1 ) == 0 &&
+                               array_keys( $examples ) === range( 0, count( $examples ) - 1 ) &&
+                               !preg_match( '/^\s*api\.php\?/', $examples[0] )
+                       ) {
+                               // Fix up the ugly "even numbered elements are description, odd
+                               // numbered elemts are the link" format (see doc for self::getExamples)
+                               $tmp = array();
+                               for ( $i = 0; $i < count( $examples ); $i += 2 ) {
+                                       $tmp[$examples[$i + 1]] = $examples[$i];
+                               }
+                               $examples = $tmp;
+                       }
 
-       /**
-        * Returns usage examples for this module. Return false if no examples are available.
-        * @return bool|string|array
-        */
-       protected function getExamples() {
-               return false;
+                       foreach ( $examples as $k => $v ) {
+                               if ( is_numeric( $k ) ) {
+                                       $qs = $v;
+                                       $msg = '';
+                               } else {
+                                       $qs = $k;
+                                       $msg = self::escapeWikiText( $v );
+                                       if ( is_array( $msg ) ) {
+                                               $msg = join( " ", $msg );
+                                       }
+                               }
+
+                               $qs = preg_replace( '/^\s*api\.php\?/', '', $qs );
+                               $ret[$qs] = $this->msg( 'api-help-fallback-example', array( $msg ) );
+                       }
+               }
+
+               return $ret;
        }
 
        /**
-        * @return bool|string|array Returns a false if the module has no help URL,
-        *   else returns a (array of) string
+        * Return links to more detailed help pages about the module.
+        * @since 1.25, returning boolean false is deprecated
+        * @return string|array
         */
        public function getHelpUrls() {
-               return false;
+               return array();
        }
 
        /**
@@ -176,22 +223,12 @@ abstract class ApiBase extends ContextSource {
         * in the overriding methods. Callers of this method can pass zero or
         * more OR-ed flags like GET_VALUES_FOR_HELP.
         *
-        * @return array|bool
+        * @return array
         */
        protected function getAllowedParams( /* $flags = 0 */ ) {
                // int $flags is not declared because it causes "Strict standards"
                // warning. Most derived classes do not implement it.
-               return false;
-       }
-
-       /**
-        * Returns an array of parameter descriptions.
-        * Don't call this function directly: use getFinalParamDescription() to
-        * allow hooks to modify descriptions as needed.
-        * @return array|bool False on no parameter descriptions
-        */
-       protected function getParamDescription() {
-               return false;
+               return array();
        }
 
        /**
@@ -226,6 +263,24 @@ abstract class ApiBase extends ContextSource {
                return $this->needsToken() !== false;
        }
 
+       /**
+        * Indicates whether this module is deprecated
+        * @since 1.25
+        * @return bool
+        */
+       public function isDeprecated() {
+               return false;
+       }
+
+       /**
+        * Indicates whether this module is "internal" or unstable
+        * @since 1.25
+        * @return bool
+        */
+       public function isInternal() {
+               return false;
+       }
+
        /**
         * Returns the token type this module requires in order to execute.
         *
@@ -234,11 +289,9 @@ abstract class ApiBase extends ContextSource {
         * core types, you must use the ApiQueryTokensRegisterTypes hook to
         * register it.
         *
-        * Returning a non-falsey value here will cause self::getFinalParams() to
-        * return a required string 'token' parameter and
-        * self::getFinalParamDescription() to ensure there is standardized
-        * documentation for it. Also, self::mustBePosted() must return true when
-        * tokens are used.
+        * Returning a non-falsey value here will force the addition of an
+        * appropriate 'token' parameter in self::getFinalParams(). Also,
+        * self::mustBePosted() must return true when tokens are used.
         *
         * In previous versions of MediaWiki, true was a valid return value.
         * Returning true will generate errors indicating that the API module needs
@@ -303,6 +356,73 @@ abstract class ApiBase extends ContextSource {
                return $this === $this->mMainModule;
        }
 
+       /**
+        * Get the parent of this module
+        * @since 1.25
+        * @return ApiBase|null
+        */
+       public function getParent() {
+               return $this->isMain() ? null : $this->getMain();
+       }
+
+       /**
+        * Get the path to this module
+        *
+        * @since 1.25
+        * @return string
+        */
+       public function getModulePath() {
+               if ( $this->isMain() ) {
+                       return 'main';
+               } elseif ( $this->getParent()->isMain() ) {
+                       return $this->getModuleName();
+               } else {
+                       return $this->getParent()->getModulePath() . '+' . $this->getModuleName();
+               }
+       }
+
+       /**
+        * Get a module from its module path
+        *
+        * @since 1.25
+        * @param string $path
+        * @return ApiBase|null
+        * @throws UsageException
+        */
+       public function getModuleFromPath( $path ) {
+               $module = $this->getMain();
+               if ( $path === 'main' ) {
+                       return $module;
+               }
+
+               $parts = explode( '+', $path );
+               if ( count( $parts ) === 1 ) {
+                       // In case the '+' was typed into URL, it resolves as a space
+                       $parts = explode( ' ', $path );
+               }
+
+               $count = count( $parts );
+               for ( $i = 0; $i < $count; $i++ ) {
+                       $parent = $module;
+                       $manager = $parent->getModuleManager();
+                       if ( $manager === null ) {
+                               $errorPath = join( '+', array_slice( $parts, 0, $i ) );
+                               $this->dieUsage( "The module \"$errorPath\" has no submodules", 'badmodule' );
+                       }
+                       $module = $manager->getModule( $parts[$i] );
+
+                       if ( $module === null ) {
+                               $errorPath = $i ? join( '+', array_slice( $parts, 0, $i ) ) : $parent->getModuleName();
+                               $this->dieUsage(
+                                       "The module \"$errorPath\" does not have a submodule \"{$parts[$i]}\"",
+                                       'badmodule'
+                               );
+                       }
+               }
+
+               return $module;
+       }
+
        /**
         * Get the result object
         * @return ApiResult
@@ -339,70 +459,6 @@ abstract class ApiBase extends ContextSource {
                return $this->mSlaveDB;
        }
 
-       /**
-        * Get final module description, after hooks have had a chance to tweak it as
-        * needed.
-        *
-        * @return array|bool False on no parameters
-        */
-       public function getFinalDescription() {
-               $desc = $this->getDescription();
-               wfRunHooks( 'APIGetDescription', array( &$this, &$desc ) );
-
-               return $desc;
-       }
-
-       /**
-        * Get final list of parameters, after hooks have had a chance to
-        * tweak it as needed.
-        *
-        * @param int $flags Zero or more flags like GET_VALUES_FOR_HELP
-        * @return array|bool False on no parameters
-        * @since 1.21 $flags param added
-        */
-       public function getFinalParams( $flags = 0 ) {
-               $params = $this->getAllowedParams( $flags );
-
-               if ( $this->needsToken() ) {
-                       $params['token'] = array(
-                               ApiBase::PARAM_TYPE => 'string',
-                               ApiBase::PARAM_REQUIRED => true,
-                       );
-               }
-
-               wfRunHooks( 'APIGetAllowedParams', array( &$this, &$params, $flags ) );
-
-               return $params;
-       }
-
-       /**
-        * Get final parameter descriptions, after hooks have had a chance to tweak it as
-        * needed.
-        *
-        * @return array|bool False on no parameter descriptions
-        */
-       public function getFinalParamDescription() {
-               $desc = $this->getParamDescription();
-
-               $tokenType = $this->needsToken();
-               if ( $tokenType ) {
-                       if ( !isset( $desc['token'] ) ) {
-                               $desc['token'] = array();
-                       } elseif ( !is_array( $desc['token'] ) ) {
-                               // We ignore a plain-string token, because it's probably an
-                               // extension that is supplying the string for BC.
-                               $desc['token'] = array();
-                       }
-                       array_unshift( $desc['token'],
-                               "A '$tokenType' token retrieved from action=query&meta=tokens"
-                       );
-               }
-
-               wfRunHooks( 'APIGetParamDescription', array( &$this, &$desc ) );
-
-               return $desc;
-       }
-
        /**@}*/
 
        /************************************************************************//**
@@ -1093,6 +1149,55 @@ abstract class ApiBase extends ContextSource {
                return $user;
        }
 
+       /**
+        * A subset of wfEscapeWikiText for BC texts
+        *
+        * @since 1.25
+        * @param string|array $v
+        * @return string|array
+        */
+       private static function escapeWikiText( $v ) {
+               if ( is_array( $v ) ) {
+                       return array_map( 'self::escapeWikiText', $v );
+               } else {
+                       return strtr( $v, array(
+                               '__' => '_&#95;', '{' => '&#123;', '}' => '&#125;',
+                               '[[Category:' => '[[:Category:',
+                               '[[File:' => '[[:File:', '[[Image:' => '[[:Image:',
+                       ) );
+               }
+       }
+
+       /**
+        * Create a Message from a string or array
+        *
+        * A string is used as a message key. An array has the message key as the
+        * first value and message parameters as subsequent values.
+        *
+        * @since 1.25
+        * @param string|array|Message $msg
+        * @param IContextSource $context
+        * @param array $params
+        * @return Message|null
+        */
+       public static function makeMessage( $msg, IContextSource $context, array $params = null ) {
+               if ( is_string( $msg ) ) {
+                       $msg = wfMessage( $msg );
+               } elseif ( is_array( $msg ) ) {
+                       $msg = call_user_func_array( 'wfMessage', $msg );
+               }
+               if ( !$msg instanceof Message ) {
+                       return null;
+               }
+
+               $msg->setContext( $context );
+               if ( $params ) {
+                       $msg->params( $params );
+               }
+
+               return $msg;
+       }
+
        /**@}*/
 
        /************************************************************************//**
@@ -1819,262 +1924,190 @@ abstract class ApiBase extends ContextSource {
         */
 
        /**
-        * Generates help message for this module, or false if there is no description
-        * @return string|bool
+        * Get final module description, after hooks have had a chance to tweak it as
+        * needed.
+        *
+        * @since 1.25, returns Message[] rather than string[]
+        * @return Message[]
         */
-       public function makeHelpMsg() {
-               static $lnPrfx = "\n  ";
+       public function getFinalDescription() {
+               $desc = $this->getDescription();
+               wfRunHooks( 'APIGetDescription', array( &$this, &$desc ) );
+               $desc = self::escapeWikiText( $desc );
+               if ( is_array( $desc ) ) {
+                       $desc = join( "\n", $desc );
+               } else {
+                       $desc = (string)$desc;
+               }
 
-               $msg = $this->getFinalDescription();
+               $msg = $this->msg( "apihelp-{$this->getModulePath()}-description", array(
+                       $this->getModulePrefix(),
+                       $this->getModuleName(),
+                       $this->getModulePath(),
+               ) );
+               if ( !$msg->exists() ) {
+                       $msg = $this->msg( 'api-help-fallback-description', $desc );
+               }
+               $msgs = array( $msg );
 
-               if ( $msg !== false ) {
+               wfRunHooks( 'APIGetDescriptionMessages', array( $this, &$msgs ) );
 
-                       if ( !is_array( $msg ) ) {
-                               $msg = array(
-                                       $msg
-                               );
-                       }
-                       $msg = $lnPrfx . implode( $lnPrfx, $msg ) . "\n";
+               return $msgs;
+       }
 
-                       $msg .= $this->makeHelpArrayToString( $lnPrfx, false, $this->getHelpUrls() );
+       /**
+        * Get final list of parameters, after hooks have had a chance to
+        * tweak it as needed.
+        *
+        * @param int $flags Zero or more flags like GET_VALUES_FOR_HELP
+        * @return array|bool False on no parameters
+        * @since 1.21 $flags param added
+        */
+       public function getFinalParams( $flags = 0 ) {
+               $params = $this->getAllowedParams( $flags );
+               if ( !$params ) {
+                       $params = array();
+               }
 
-                       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->needsToken() ) {
+                       $params['token'] = array(
+                               ApiBase::PARAM_TYPE => 'string',
+                               ApiBase::PARAM_REQUIRED => true,
+                               ApiBase::PARAM_HELP_MSG => array(
+                                       'api-help-param-token',
+                                       $this->needsToken(),
+                               ),
+                       ) + ( isset( $params['token'] ) ? $params['token'] : array() );
+               }
+
+               wfRunHooks( 'APIGetAllowedParams', array( &$this, &$params, $flags ) );
+
+               return $params;
+       }
+
+       /**
+        * Get final parameter descriptions, after hooks have had a chance to tweak it as
+        * needed.
+        *
+        * @since 1.25, returns array of Message[] rather than array of string[]
+        * @return array Keys are parameter names, values are arrays of Message objects
+        */
+       public function getFinalParamDescription() {
+               $desc = $this->getParamDescription();
+               wfRunHooks( 'APIGetParamDescription', array( &$this, &$desc ) );
+
+               if ( !$desc ) {
+                       $desc = array();
+               }
+               $desc = self::escapeWikiText( $desc );
+
+               $params = $this->getFinalParams( ApiBase::GET_VALUES_FOR_HELP );
+               $msgs = array();
+               foreach ( $params as $param => $settings ) {
+                       if ( !is_array( $settings ) ) {
+                               $settings = array();
                        }
-                       if ( $this->isReadMode() || $this->isWriteMode() ||
-                               $this->mustBePosted()
-                       ) {
-                               $msg .= "\n";
+
+                       $d = isset( $desc[$param] ) ? $desc[$param] : '';
+                       if ( is_array( $d ) ) {
+                               // Special handling for prop parameters
+                               $d = array_map( function ( $line ) {
+                                       if ( preg_match( '/^\s+(\S+)\s+-\s+(.+)$/', $line, $m ) ) {
+                                               $line = "\n;{$m[1]}:{$m[2]}";
+                                       }
+                                       return $line;
+                               }, $d );
+                               $d = join( ' ', $d );
                        }
 
-                       // Parameters
-                       $paramsMsg = $this->makeHelpMsgParameters();
-                       if ( $paramsMsg !== false ) {
-                               $msg .= "Parameters:\n$paramsMsg";
+                       if ( isset( $settings[ApiBase::PARAM_HELP_MSG] ) ) {
+                               $msg = $settings[ApiBase::PARAM_HELP_MSG];
+                       } else {
+                               $msg = $this->msg( "apihelp-{$this->getModulePath()}-param-{$param}" );
+                               if ( !$msg->exists() ) {
+                                       $msg = $this->msg( 'api-help-fallback-parameter', $d );
+                               }
+                       }
+                       $msg = ApiBase::makeMessage( $msg, $this->getContext(), array(
+                               $this->getModulePrefix(),
+                               $param,
+                               $this->getModuleName(),
+                               $this->getModulePath(),
+                       ) );
+                       if ( !$msg ) {
+                               $this->dieDebug( __METHOD__,
+                                       'Value in ApiBase::PARAM_HELP_MSG is not valid' );
                        }
+                       $msgs[$param] = array( $msg );
 
-                       $examples = $this->getExamples();
-                       if ( $examples ) {
-                               if ( !is_array( $examples ) ) {
-                                       $examples = array(
-                                               $examples
-                                       );
+                       if ( isset( $settings[ApiBase::PARAM_HELP_MSG_APPEND] ) ) {
+                               if ( !is_array( $settings[ApiBase::PARAM_HELP_MSG_APPEND] ) ) {
+                                       $this->dieDebug( __METHOD__,
+                                               'Value for ApiBase::PARAM_HELP_MSG_APPEND is not an array' );
                                }
-                               $msg .= "Example" . ( count( $examples ) > 1 ? 's' : '' ) . ":\n";
-                               foreach ( $examples as $k => $v ) {
-                                       if ( is_numeric( $k ) ) {
-                                               $msg .= "  $v\n";
+                               foreach ( $settings[ApiBase::PARAM_HELP_MSG_APPEND] as $m ) {
+                                       $m = ApiBase::makeMessage( $m, $this->getContext(), array(
+                                               $this->getModulePrefix(),
+                                               $param,
+                                               $this->getModuleName(),
+                                               $this->getModulePath(),
+                                       ) );
+                                       if ( $m ) {
+                                               $msgs[$param][] = $m;
                                        } else {
-                                               if ( is_array( $v ) ) {
-                                                       $msgExample = implode( "\n", array_map( array( $this, 'indentExampleText' ), $v ) );
-                                               } else {
-                                                       $msgExample = "  $v";
-                                               }
-                                               $msgExample .= ":";
-                                               $msg .= wordwrap( $msgExample, 100, "\n" ) . "\n    $k\n";
+                                               $this->dieDebug( __METHOD__,
+                                                       'Value in ApiBase::PARAM_HELP_MSG_APPEND is not valid' );
                                        }
                                }
                        }
                }
 
-               return $msg;
+               wfRunHooks( 'APIGetParamDescriptionMessages', array( $this, &$msgs ) );
+
+               return $msgs;
        }
 
        /**
-        * @param string $item
-        * @return string
-        */
-       private function indentExampleText( $item ) {
-               return "  " . $item;
-       }
-
-       /**
-        * @param string $prefix Text to split output items
-        * @param string $title What is being output
-        * @param string|array $input
-        * @return string
+        * Generates the list of flags for the help screen and for action=paraminfo
+        *
+        * Corresponding messages: api-help-flag-deprecated,
+        * api-help-flag-internal, api-help-flag-readrights,
+        * api-help-flag-writerights, api-help-flag-mustbeposted
+        *
+        * @return string[]
         */
-       protected function makeHelpArrayToString( $prefix, $title, $input ) {
-               if ( $input === false ) {
-                       return '';
+       protected function getHelpFlags() {
+               $flags = array();
+
+               if ( $this->isDeprecated() ) {
+                       $flags[] = 'deprecated';
                }
-               if ( !is_array( $input ) ) {
-                       $input = array( $input );
+               if ( $this->isInternal() ) {
+                       $flags[] = 'internal';
                }
-
-               if ( count( $input ) > 0 ) {
-                       if ( $title ) {
-                               $msg = $title . ( count( $input ) > 1 ? 's' : '' ) . ":\n  ";
-                       } else {
-                               $msg = '  ';
-                       }
-                       $msg .= implode( $prefix, $input ) . "\n";
-
-                       return $msg;
+               if ( $this->isReadMode() ) {
+                       $flags[] = 'readrights';
+               }
+               if ( $this->isWriteMode() ) {
+                       $flags[] = 'writerights';
+               }
+               if ( $this->mustBePosted() ) {
+                       $flags[] = 'mustbeposted';
                }
 
-               return '';
+               return $flags;
        }
 
        /**
-        * Generates the parameter descriptions for this module, to be displayed in the
-        * module's help.
-        * @return string|bool
+        * Called from ApiHelp before the pieces are joined together and returned.
+        *
+        * This exists mainly for ApiMain to add the Permissions and Credits
+        * sections. Other modules probably don't need it.
+        *
+        * @param string[] &$help Array of help data
+        * @param array $options Options passed to ApiHelp::getHelp
         */
-       public function makeHelpMsgParameters() {
-               $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 = array(
-                                               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' ) {
-                                               $type = $this->getModuleManager()->getNames( $paramName );
-                                               sort( $type );
-                                       }
-                                       if ( is_array( $type ) ) {
-                                               $choices = array();
-                                               $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;
+       public function modifyHelp( array &$help, array $options ) {
        }
 
        /**@}*/
@@ -2365,6 +2398,321 @@ abstract class ApiBase extends ContextSource {
                return array();
        }
 
+       /**
+        * Returns the description string for this module
+        *
+        * Ignored if an i18n message exists for
+        * "apihelp-{$this->getModulePathString()}-description".
+        *
+        * @deprecated since 1.25
+        * @return Message|string|array
+        */
+       protected function getDescription() {
+               return false;
+       }
+
+       /**
+        * Returns an array of parameter descriptions.
+        *
+        * For each parameter, ignored if an i18n message exists for the parameter.
+        * By default that message is
+        * "apihelp-{$this->getModulePathString()}-param-{$param}", but it may be
+        * overridden using ApiBase::PARAM_HELP_MSG in the data returned by
+        * self::getFinalParams().
+        *
+        * @deprecated since 1.25
+        * @return array|bool False on no parameter descriptions
+        */
+       protected function getParamDescription() {
+               return false;
+       }
+
+       /**
+        * Returns usage examples for this module.
+        *
+        * Return value as an array is either:
+        *  - numeric keys with partial URLs ("api.php?" plus a query string) as
+        *    values
+        *  - sequential numeric keys with even-numbered keys being display-text
+        *    and odd-numbered keys being partial urls
+        *  - partial URLs as keys with display-text (string or array-to-be-joined)
+        *    as values
+        * Return value as a string is the same as an array with a numeric key and
+        * that value, and boolean false means "no examples".
+        *
+        * @deprecated since 1.25, use getExamplesMessages() instead
+        * @return bool|string|array
+        */
+       protected function getExamples() {
+               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 = array(
+                                       $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 = array(
+                                               $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( array( $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 = array( $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 = array(
+                                               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' ) {
+                                               $type = $this->getModuleManager()->getNames( $paramName );
+                                               sort( $type );
+                                       }
+                                       if ( is_array( $type ) ) {
+                                               $choices = array();
+                                               $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;
+       }
+
        /**@}*/
 }
 
index 2a57688..7a08ed7 100644 (file)
@@ -30,8 +30,8 @@
  * @ingroup API
  */
 abstract class ApiFormatBase extends ApiBase {
-       private $mIsHtml, $mFormat, $mUnescapeAmps, $mHelp, $mCleared;
-       private $mBufferResult = false, $mBuffer, $mDisabled = false;
+       private $mIsHtml, $mFormat, $mUnescapeAmps, $mHelp;
+       private $mBuffer, $mDisabled = false;
 
        /**
         * If $format ends with 'fm', pretty-print the output in HTML.
@@ -48,12 +48,14 @@ abstract class ApiFormatBase extends ApiBase {
                        $this->mFormat = $format;
                }
                $this->mFormat = strtoupper( $this->mFormat );
-               $this->mCleared = false;
        }
 
        /**
         * Overriding class returns the MIME type that should be sent to the client.
-        * This method is not called if getIsHtml() returns true.
+        *
+        * When getIsHtml() returns true, the return value here is used for syntax
+        * highlighting but the client sees text/html.
+        *
         * @return string
         */
        abstract public function getMimeType();
@@ -74,19 +76,6 @@ abstract class ApiFormatBase extends ApiBase {
                return $this->mFormat;
        }
 
-       /**
-        * 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.
-        *
-        * @param bool $b Whether or not ampersands should be escaped.
-        */
-       public function setUnescapeAmps( $b ) {
-               $this->mUnescapeAmps = $b;
-       }
-
        /**
         * Returns true when the HTML pretty-printer should be used.
         * The default implementation assumes that formats ending with 'fm'
@@ -98,30 +87,27 @@ abstract class ApiFormatBase extends ApiBase {
        }
 
        /**
-        * 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
-        * @return bool
-        */
-       public function getWantsHelp() {
-               return $this->getIsHtml();
-       }
-
-       /**
-        * Disable the formatter completely. This causes calls to initPrinter(),
-        * printText() and closePrinter() to be ignored.
+        * Disable the formatter.
+        *
+        * This causes calls to initPrinter() and closePrinter() to be ignored.
         */
        public function disable() {
                $this->mDisabled = true;
        }
 
+       /**
+        * Whether the printer is disabled
+        * @return bool
+        */
        public function isDisabled() {
                return $this->mDisabled;
        }
 
        /**
-        * Whether this formatter can handle printing API errors. If this returns
-        * false, then on API errors the default printer will be instantiated.
+        * Whether this formatter can handle printing API errors.
+        *
+        * If this returns false, then on API errors the default printer will be
+        * instantiated.
         * @since 1.23
         * @return bool
         */
@@ -130,24 +116,19 @@ abstract class ApiFormatBase extends ApiBase {
        }
 
        /**
-        * Initialize the printer function and prepare the output headers, etc.
-        * This method must be the first outputting method during execution.
-        * A human-targeted notice about available formats is printed for the HTML-based output,
-        * except for help screens (caused by either an error in the API parameters,
-        * the calling of action=help, or requesting the root script api.php).
-        * @param bool $isHelpScreen Whether a help screen is going to be shown
+        * Initialize the printer function and prepare the output headers.
+        * @param bool $unused Always false since 1.25
         */
-       function initPrinter( $isHelpScreen ) {
+       function initPrinter( $unused = false ) {
                if ( $this->mDisabled ) {
                        return;
                }
-               $isHtml = $this->getIsHtml();
-               $mime = $isHtml ? 'text/html' : $this->getMimeType();
-               $script = wfScript( 'api' );
+
+               $mime = $this->getIsHtml() ? 'text/html' : $this->getMimeType();
 
                // Some printers (ex. Feed) do their own header settings,
                // in which case $mime will be set to null
-               if ( is_null( $mime ) ) {
+               if ( $mime === null ) {
                        return; // skip any initialization
                }
 
@@ -158,91 +139,60 @@ abstract class ApiFormatBase extends ApiBase {
                if ( $apiFrameOptions ) {
                        $this->getMain()->getRequest()->response()->header( "X-Frame-Options: $apiFrameOptions" );
                }
-
-               if ( $isHtml ) {
-?>
-<!DOCTYPE HTML>
-<html>
-<head>
-<?php
-                       if ( $this->mUnescapeAmps ) {
-?>     <title>MediaWiki API</title>
-<?php
-                       } else {
-?>     <title>MediaWiki API Result</title>
-<?php
-                       }
-?>
-</head>
-<body>
-<?php
-                       if ( !$isHelpScreen ) {
-// @codingStandardsIgnoreStart Exclude long line from CodeSniffer checks
-?>
-<br />
-<small>
-You are looking at the HTML representation of the <?php echo $this->mFormat; ?> format.<br />
-HTML is good for debugging, but is unsuitable for application use.<br />
-Specify the format parameter to change the output format.<br />
-To see the non HTML representation of the <?php echo $this->mFormat; ?> format, set format=<?php echo strtolower( $this->mFormat ); ?>.<br />
-See the <a href='https://www.mediawiki.org/wiki/API'>complete documentation</a>, or
-<a href='<?php echo $script; ?>'>API help</a> for more information.
-</small>
-<pre style='white-space: pre-wrap;'>
-<?php
-// @codingStandardsIgnoreEnd
-                       // don't wrap the contents of the <pre> for help screens
-                       // because these are actually formatted to rely on
-                       // the monospaced font for layout purposes
-                       } else {
-?>
-<pre>
-<?php
-                       }
-               }
        }
 
        /**
-        * Finish printing. Closes HTML tags.
+        * Finish printing and output buffered data.
         */
        public function closePrinter() {
                if ( $this->mDisabled ) {
                        return;
                }
-               if ( $this->getIsHtml() ) {
-?>
 
-</pre>
-</body>
-</html>
-<?php
+               $mime = $this->getMimeType();
+               if ( $this->getIsHtml() && $mime !== null ) {
+                       $format = $this->getFormat();
+                       $result = $this->getBuffer();
+
+                       $context = new DerivativeContext( $this->getMain() );
+                       $context->setUser( new User ); // anon to avoid caching issues
+                       $context->setSkin( SkinFactory::getDefaultInstance()->makeSkin( 'apioutput' ) );
+                       $out = new OutputPage( $context );
+                       $out->addModules( 'mediawiki.apipretty' );
+                       $out->setPageTitle( $context->msg( 'api-format-title' ) );
+                       $context->setOutput( $out );
+
+                       $header = $context->msg( 'api-format-prettyprint-header' )
+                          ->params( $format, strtolower( $format ) )
+                          ->parseAsBlock();
+                       $out->addHTML(
+                               Html::rawElement( 'div', array( 'class' => 'api-pretty-header' ),
+                                       ApiHelp::fixHelpLinks( $header )
+                               )
+                       );
+
+                       if ( wfRunHooks( 'ApiFormatHighlight', array( $context, $result, $mime, $format ) ) ) {
+                               $out->addHTML(
+                                       Html::element( 'pre', array( 'class' => 'api-pretty-content' ), $result )
+                               );
+                       }
+
+                       $out->output();
+               } else {
+                       // For non-HTML output, clear all errors that might have been
+                       // displayed if display_errors=On
+                       ob_clean();
+
+                       echo $this->getBuffer();
                }
        }
 
        /**
-        * The main format printing function. Call it to output the result
-        * string to the user. This function will automatically output HTML
-        * when format name ends in 'fm'.
+        * Append text to the output buffer.
         * @param string $text
         */
        public function printText( $text ) {
-               if ( $this->mDisabled ) {
-                       return;
-               }
-               if ( $this->mBufferResult ) {
-                       $this->mBuffer = $text;
-               } elseif ( $this->getIsHtml() ) {
-                       echo $this->formatHTML( $text );
-               } else {
-                       // For non-HTML output, clear all errors that might have been
-                       // displayed if display_errors=On
-                       // Do this only once, of course
-                       if ( !$this->mCleared ) {
-                               ob_clean();
-                               $this->mCleared = true;
-                       }
-                       echo $text;
-               }
+               $this->mBuffer .= $text;
        }
 
        /**
@@ -253,29 +203,81 @@ See the <a href='https://www.mediawiki.org/wiki/API'>complete documentation</a>,
                return $this->mBuffer;
        }
 
+       public function getExamplesMessages() {
+               return array(
+                       'action=query&meta=siteinfo&siprop=namespaces&format=' . $this->getModuleName()
+                               => array( 'apihelp-format-example-generic', $this->getFormat() )
+               );
+       }
+
+       public function getHelpUrls() {
+               return 'https://www.mediawiki.org/wiki/API:Data_formats';
+       }
+
        /**
-        * Set the flag to buffer the result instead of printing it.
-        * @param bool $value
+        * To avoid code duplication with the deprecation of dbg, dump, txt, wddx,
+        * and yaml, this method is added to do the necessary work. It should be
+        * removed when those deprecated formats are removed.
         */
-       public function setBufferResult( $value ) {
-               $this->mBufferResult = $value;
+       protected function markDeprecated() {
+               $fm = $this->getIsHtml() ? 'fm' : '';
+               $name = $this->getModuleName();
+               $this->logFeatureUsage( "format=$name" );
+               $this->setWarning( "format=$name has been deprecated. Please use format=json$fm instead." );
+       }
+
+       /************************************************************************//**
+        * @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 );
 
@@ -328,30 +330,26 @@ See the <a href='https://www.mediawiki.org/wiki/API'>complete documentation</a>,
                return $text;
        }
 
-       public function getExamples() {
-               return array(
-                       'api.php?action=query&meta=siteinfo&siprop=namespaces&format=' . $this->getModuleName()
-                               => "Format the query result in the {$this->getModuleName()} format",
-               );
-       }
-
-       public function getHelpUrls() {
-               return 'https://www.mediawiki.org/wiki/API:Data_formats';
-       }
-
+       /**
+        * @see ApiBase::getDescription
+        * @deprecated since 1.25
+        */
        public function getDescription() {
                return $this->getIsHtml() ? ' (pretty-print in HTML)' : '';
        }
 
        /**
-        * To avoid code duplication with the deprecation of dbg, dump, txt, wddx,
-        * and yaml, this method is added to do the necessary work. It should be
-        * removed when those deprecated formats are removed.
+        * Set the flag to buffer the result instead of printing it.
+        * @deprecated since 1.25, output is always buffered
+        * @param bool $value
         */
-       protected function markDeprecated() {
-               $fm = $this->getIsHtml() ? 'fm' : '';
-               $name = $this->getModuleName();
-               $this->logFeatureUsage( "format=$name" );
-               $this->setWarning( "format=$name has been deprecated. Please use format=json$fm instead." );
+       public function setBufferResult( $value ) {
        }
+
+       /**@}*/
 }
+
+/**
+ * For really cool vim folding this needs to be at the end:
+ * vim: foldmarker=@{,@} foldmethod=marker
+ */
index 5ec518b..273e205 100644 (file)
@@ -43,7 +43,7 @@ class ApiFormatDbg extends ApiFormatBase {
                $this->printText( var_export( $this->getResultData(), true ) );
        }
 
-       public function getDescription() {
-               return 'DEPRECATED! Output data in PHP\'s var_export() format' . parent::getDescription();
+       public function isDeprecated() {
+               return true;
        }
 }
index d4c7cab..7ef8960 100644 (file)
@@ -47,7 +47,7 @@ class ApiFormatDump extends ApiFormatBase {
                $this->printText( $result );
        }
 
-       public function getDescription() {
-               return 'DEPRECATED! Output data in PHP\'s var_dump() format' . parent::getDescription();
+       public function isDeprecated() {
+               return true;
        }
 }
index 6c5ad38..ce8656e 100644 (file)
@@ -51,7 +51,11 @@ class ApiFormatJson extends ApiFormatBase {
                return $this->mIsRaw;
        }
 
+       /**
+        * @deprecated since 1.25
+        */
        public function getWantsHelp() {
+               wfDeprecated( __METHOD__, '1.25' );
                // Help is always ugly in JSON
                return false;
        }
@@ -76,25 +80,13 @@ class ApiFormatJson extends ApiFormatBase {
 
        public function getAllowedParams() {
                return array(
-                       'callback' => null,
-                       'utf8' => false,
+                       'callback' => array(
+                               ApiBase::PARAM_HELP_MSG => 'apihelp-json-param-callback',
+                       ),
+                       'utf8' => array(
+                               ApiBase::PARAM_DFLT => false,
+                               ApiBase::PARAM_HELP_MSG => 'apihelp-json-param-utf8',
+                       ),
                );
        }
-
-       public function getParamDescription() {
-               return array(
-                       'callback' => 'If specified, wraps the output into a given function ' .
-                               'call. For safety, all user-specific data will be restricted.',
-                       'utf8' => 'If specified, encodes most (but not all) non-ASCII ' .
-                               'characters as UTF-8 instead of replacing them with hexadecimal escape sequences.',
-               );
-       }
-
-       public function getDescription() {
-               if ( $this->mIsRaw ) {
-                       return 'Output data with the debugging elements in JSON format' . parent::getDescription();
-               }
-
-               return 'Output data in JSON format' . parent::getDescription();
-       }
 }
index 78023af..dc623ac 100644 (file)
@@ -36,8 +36,4 @@ class ApiFormatNone extends ApiFormatBase {
 
        public function execute() {
        }
-
-       public function getDescription() {
-               return 'Output nothing' . parent::getDescription();
-       }
 }
index b2d1f04..ae93812 100644 (file)
@@ -37,8 +37,4 @@ class ApiFormatPhp extends ApiFormatBase {
        public function execute() {
                $this->printText( serialize( $this->getResultData() ) );
        }
-
-       public function getDescription() {
-               return 'Output data in serialized PHP format' . parent::getDescription();
-       }
 }
index 3f5c8b7..235fca1 100644 (file)
  */
 class ApiFormatRaw extends ApiFormatBase {
 
+       private $errorFallback;
+
        /**
         * @param ApiMain $main
         * @param ApiFormatBase $errorFallback Object to fall back on for errors
         */
        public function __construct( ApiMain $main, ApiFormatBase $errorFallback ) {
                parent::__construct( $main, 'raw' );
-               $this->mErrorFallback = $errorFallback;
+               $this->errorFallback = $errorFallback;
        }
 
        public function getMimeType() {
                $data = $this->getResultData();
 
                if ( isset( $data['error'] ) ) {
-                       return $this->mErrorFallback->getMimeType();
+                       return $this->errorFallback->getMimeType();
                }
 
                if ( !isset( $data['mime'] ) ) {
@@ -53,11 +55,28 @@ class ApiFormatRaw extends ApiFormatBase {
                return $data['mime'];
        }
 
-       public function execute() {
+       public function initPrinter( $unused ) {
+               $data = $this->getResultData();
+               if ( isset( $data['error'] ) ) {
+                       $this->errorFallback->initPrinter( $unused );
+               } else {
+                       parent::initPrinter( $unused );
+               }
+       }
+
+       public function closePrinter() {
                $data = $this->getResultData();
                if ( isset( $data['error'] ) ) {
-                       $this->mErrorFallback->execute();
+                       $this->errorFallback->closePrinter();
+               } else {
+                       parent::closePrinter();
+               }
+       }
 
+       public function execute() {
+               $data = $this->getResultData();
+               if ( isset( $data['error'] ) ) {
+                       $this->errorFallback->execute();
                        return;
                }
 
index c451ed7..505b259 100644 (file)
@@ -43,7 +43,7 @@ class ApiFormatTxt extends ApiFormatBase {
                $this->printText( print_r( $this->getResultData(), true ) );
        }
 
-       public function getDescription() {
-               return 'DEPRECATED! Output data in PHP\'s print_r() format' . parent::getDescription();
+       public function isDeprecated() {
+               return true;
        }
 }
index ba90c26..e2d4d61 100644 (file)
@@ -109,7 +109,7 @@ class ApiFormatWddx extends ApiFormatBase {
                }
        }
 
-       public function getDescription() {
-               return 'DEPRECATED! Output data in WDDX format' . parent::getDescription();
+       public function isDeprecated() {
+               return true;
        }
 }
index b3d5937..4ed4944 100644 (file)
@@ -237,20 +237,13 @@ class ApiFormatXml extends ApiFormatBase {
 
        public function getAllowedParams() {
                return array(
-                       'xslt' => null,
-                       'includexmlnamespace' => false,
+                       'xslt' => array(
+                               ApiBase::PARAM_HELP_MSG => 'apihelp-json-param-callback',
+                       ),
+                       'includexmlnamespace' => array(
+                               ApiBase::PARAM_DFLT => false,
+                               ApiBase::PARAM_HELP_MSG => 'apihelp-json-param-callback',
+                       ),
                );
        }
-
-       public function getParamDescription() {
-               return array(
-                       'xslt' => 'If specified, adds <xslt> as stylesheet. This should be a wiki page '
-                               . 'in the MediaWiki namespace whose page name ends with ".xsl"',
-                       'includexmlnamespace' => 'If specified, adds an XML namespace'
-               );
-       }
-
-       public function getDescription() {
-               return 'Output data in XML format' . parent::getDescription();
-       }
 }
index 3798f89..c9089a7 100644 (file)
@@ -40,7 +40,7 @@ class ApiFormatYaml extends ApiFormatJson {
                parent::execute();
        }
 
-       public function getDescription() {
-               return 'DEPRECATED! Output data in YAML format' . ApiFormatBase::getDescription();
+       public function isDeprecated() {
+               return true;
        }
 }
index bcd6c12..0c962d0 100644 (file)
@@ -2,9 +2,9 @@
 /**
  *
  *
- * Created on Sep 6, 2006
+ * Created on Aug 29, 2014
  *
- * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
+ * Copyright © 2014 Brad Jorsch <bjorsch@wikimedia.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  */
 
 /**
- * This is a simple class to handle action=help
+ * Class to output help for an API module
  *
+ * @since 1.25 completely rewritten
  * @ingroup API
  */
 class ApiHelp extends ApiBase {
-       /**
-        * Module for displaying help
-        */
        public function execute() {
-               // Get parameters
+               global $wgContLang;
+
                $params = $this->extractRequestParams();
+               $modules = array();
 
-               if ( !isset( $params['modules'] ) && !isset( $params['querymodules'] ) ) {
-                       $this->dieUsage( '', 'help' );
+               foreach ( $params['modules'] as $path ) {
+                       $modules[] = $this->getModuleFromPath( $path );
                }
 
-               $this->getMain()->setHelp();
-               $result = $this->getResult();
+               // Get the help
+               $context = new DerivativeContext( $this->getMain()->getContext() );
+               $context->setUser( new User ); // anon to avoid caching issues
+               $context->setSkin( SkinFactory::getDefaultInstance()->makeSkin( 'apioutput' ) );
+               $context->setLanguage( $this->getMain()->getLanguage() );
+               $out = new OutputPage( $context );
+               $context->setOutput( $out );
 
-               if ( is_array( $params['modules'] ) ) {
-                       $modules = $params['modules'];
+               self::getHelp( $context, $modules, $params );
+
+               // Grab the output from the skin
+               ob_start();
+               $context->getOutput()->output();
+               $html = ob_get_clean();
+
+               $result = $this->getResult();
+               if ( $params['wrap'] ) {
+                       $data = array(
+                               'mime' => 'text/html',
+                               'help' => $help,
+                       );
+                       $result->setSubelements( $data, 'help' );
+                       $result->addValue( null, $this->getModuleName(), $data );
                } else {
-                       $modules = array();
+                       $result->reset();
+                       $result->addValue( null, 'text', $html, ApiResult::NO_SIZE_CHECK );
+                       $result->addValue( null, 'mime', 'text/html', ApiResult::NO_SIZE_CHECK );
                }
+       }
+
+       /**
+        * Generate help for the specified modules
+        *
+        * Help is placed into the OutputPage object returned by
+        * $context->getOutput().
+        *
+        * Recognized options include:
+        *  - headerlevel: (int) Header tag level
+        *  - nolead: (bool) Skip the inclusion of api-help-lead
+        *  - noheader: (bool) Skip the inclusion of the top-level section headers
+        *  - submodules: (bool) Include help for submodules of the current module
+        *  - recursivesubmodules: (bool) Include help for submodules recursively
+        *  - helptitle: (string) Title to link for additional modules' help. Should contain $1.
+        *
+        * @param IContextSource $context
+        * @param ApiBase[]|ApiBase $modules
+        * @param array $options Formatting options (described above)
+        * @return string
+        */
+       public static function getHelp( IContextSource $context, $modules, array $options ) {
+               global $wgMemc, $wgContLang;
+
+               if ( !is_array( $modules ) ) {
+                       $modules = array( $modules );
+               }
+
+               $out = $context->getOutput();
+               $out->addModules( 'mediawiki.apihelp' );
+               $out->setPageTitle( $context->msg( 'api-help-title' ) );
 
-               if ( is_array( $params['querymodules'] ) ) {
-                       $this->logFeatureUsage( 'action=help&querymodules' );
-                       $queryModules = $params['querymodules'];
-                       foreach ( $queryModules as $m ) {
-                               $modules[] = 'query+' . $m;
+               $cacheKey = null;
+               if ( count( $modules ) == 1 && $modules[0] instanceof ApiMain &&
+                       $options['recursivesubmodules'] && $context->getLanguage() === $wgContLang
+               ) {
+                       $cacheHelpTimeout = $context->getConfig()->get( 'APICacheHelpTimeout' );
+                       if ( $cacheHelpTimeout > 0 ) {
+                               // Get help text from cache if present
+                               $cacheKey = wfMemcKey( 'apihelp', $modules[0]->getModulePath(),
+                                       str_replace( ' ', '_', SpecialVersion::getVersion( 'nodb' ) ) );
+                               $cached = $wgMemc->get( $cacheKey );
+                               if ( $cached ) {
+                                       $out->addHTML( $cached );
+                                       return;
+                               }
                        }
-               } else {
-                       $queryModules = array();
                }
+               if ( $out->getHTML() !== '' ) {
+                       // Don't save to cache, there's someone else's content in the page
+                       // already
+                       $cacheKey = null;
+               }
+
+               $options['recursivesubmodules'] = !empty( $options['recursivesubmodules'] );
+               $options['submodules'] = $options['recursivesubmodules'] || !empty( $options['submodules'] );
 
-               $r = array();
-               foreach ( $modules as $m ) {
-                       // sub-modules could be given in the form of "name[+name[+name...]]"
-                       $subNames = explode( '+', $m );
-                       if ( count( $subNames ) === 1 ) {
-                               // In case the '+' was typed into URL, it resolves as a space
-                               $subNames = explode( ' ', $m );
+               // Prepend lead
+               if ( empty( $options['nolead'] ) ) {
+                       $msg = $context->msg( 'api-help-lead' );
+                       if ( !$msg->isDisabled() ) {
+                               $out->addHTML( $msg->parseAsBlock() );
                        }
+               }
 
-                       $module = $this->getMain();
-                       $subNamesCount = count( $subNames );
-                       for ( $i = 0; $i < $subNamesCount; $i++ ) {
-                               $subs = $module->getModuleManager();
-                               if ( $subs === null ) {
-                                       $module = null;
-                               } else {
-                                       $module = $subs->getModule( $subNames[$i] );
-                               }
+               $haveModules = array();
+               $out->addHTML( self::getHelpInternal( $context, $modules, $options, $haveModules ) );
 
-                               if ( $module === null ) {
-                                       if ( count( $subNames ) === 2
-                                               && $i === 1
-                                               && $subNames[0] === 'query'
-                                               && in_array( $subNames[1], $queryModules )
-                                       ) {
-                                               // Legacy: This is one of the renamed 'querymodule=...' parameters,
-                                               // do not use '+' notation in the output, use submodule's name instead.
-                                               $name = $subNames[1];
-                                       } else {
-                                               $name = implode( '+', array_slice( $subNames, 0, $i + 1 ) );
-                                       }
-                                       $r[] = array( 'name' => $name, 'missing' => '' );
-                                       break;
+               $helptitle = isset( $options['helptitle'] ) ? $options['helptitle'] : null;
+               $html = self::fixHelpLinks( $out->getHTML(), $helptitle, $haveModules );
+               $out->clearHTML();
+               $out->addHTML( $html );
+
+               if ( $cacheKey !== null ) {
+                       $wgMemc->set( $cacheKey, $out->getHTML(), $cacheHelpTimeout );
+               }
+       }
+
+       /**
+        * Replace Special:ApiHelp links with links to api.php
+        *
+        * @param string $html
+        * @param string|null $helptitle Title to link to rather than api.php, must contain '$1'
+        * @param array $localModules Modules to link within the current page
+        * @return string
+        */
+       public static function fixHelpLinks( $html, $helptitle = null, $localModules = array() ) {
+               $formatter = new HtmlFormatter( $html );
+               $doc = $formatter->getDoc();
+               $xpath = new DOMXPath( $doc );
+               $nodes = $xpath->query( '//a[@href][not(contains(@class,\'apihelp-linktrail\'))]' );
+               foreach ( $nodes as $node ) {
+                       $href = $node->getAttribute( 'href' );
+                       do {
+                               $old = $href;
+                               $href = rawurldecode( $href );
+                       } while ( $old !== $href );
+                       if ( preg_match( '!Special:ApiHelp/([^&/|]+)!', $href, $m ) ) {
+                               if ( isset( $localModules[$m[1]] ) ) {
+                                       $href = '#' . $m[1];
+                               } elseif ( $helptitle !== null ) {
+                                       $href = Title::newFromText( str_replace( '$1', $m[1], $helptitle ) )
+                                               ->getFullUrl();
                                } else {
-                                       $type = $subs->getModuleGroup( $subNames[$i] );
+                                       $href = wfAppendQuery( wfScript( 'api' ), array(
+                                               'action' => 'help',
+                                               'modules' => $m[1],
+                                       ) );
                                }
-                       }
-
-                       if ( $module !== null ) {
-                               $r[] = $this->buildModuleHelp( $module, $type );
+                               $node->setAttribute( 'href', $href );
+                               $node->removeAttribute( 'title' );
                        }
                }
 
-               $result->setIndexedTagName( $r, 'module' );
-               $result->addValue( null, $this->getModuleName(), $r );
+               return $formatter->getText();
+       }
+
+       /**
+        * Wrap a message in HTML with a class.
+        *
+        * @param Message $msg
+        * @param string $class
+        * @param string $tag
+        * @return string
+        */
+       private static function wrap( Message $msg, $class, $tag = 'span' ) {
+               return Html::rawElement( $tag, array( 'class' => $class ),
+                       $msg->parse()
+               );
        }
 
        /**
-        * @param ApiBase $module
-        * @param string $type What type of request is this? e.g. action, query, list, prop, meta, format
+        * Recursively-called function to actually construct the help
+        *
+        * @param IContextSource $context
+        * @param ApiBase[] $modules
+        * @param array $options
+        * @param array &$haveModules
         * @return string
         */
-       private function buildModuleHelp( $module, $type ) {
-               $msg = ApiMain::makeHelpMsgHeader( $module, $type );
+       private static function getHelpInternal( IContextSource $context, array $modules,
+               array $options, &$haveModules
+       ) {
+               $out = '';
+
+               $level = min( 6, empty( $options['headerlevel'] ) ? 2 : $options['headerlevel'] );
+               $options['headerlevel'] = $level;
+
+               foreach ( $modules as $module ) {
+                       $haveModules[$module->getModulePath()] = true;
+                       $module->setContext( $context );
+                       $help = array(
+                               'header' => '',
+                               'flags' => '',
+                               'description' => '',
+                               'help-urls' => '',
+                               'parameters' => '',
+                               'examples' => '',
+                               'submodules' => '',
+                       );
+
+                       if ( empty( $options['noheader'] ) ) {
+                               $path = $module->getModulePath();
+                               if ( $module->isMain() ) {
+                                       $header = $context->msg( 'api-help-main-header' )->parse();
+                               } else {
+                                       $name = $module->getModuleName();
+                                       $header = $module->getParent()->getModuleManager()->getModuleGroup( $name ) .
+                                               "=$name";
+                                       if ( $module->getModulePrefix() !== '' ) {
+                                               $header .= ' ' .
+                                                       $context->msg( 'parentheses', $module->getModulePrefix() )->parse();
+                                       }
+                               }
+                               $help['header'] .= Html::element( "h$level",
+                                       array( 'id' => $path, 'class' => 'apihelp-header' ),
+                                       $header
+                               );
+                       }
+
+                       $links = array();
+                       $any = false;
+                       for ( $m = $module; $m !== null; $m = $m->getParent() ) {
+                               $name = $m->getModuleName();
+                               if ( $name === 'main_int' ) {
+                                       $name = 'main';
+                               }
+
+                               if ( count( $modules ) === 1 && $m === $modules[0] &&
+                                       !( !empty( $options['submodules'] ) && $m->getModuleManager() )
+                               ) {
+                                       $link = Html::element( 'b', null, $name );
+                               } else {
+                                       $link = SpecialPage::getTitleFor( 'ApiHelp', $m->getModulePath() )->getLocalURL();
+                                       $link = Html::element( 'a',
+                                               array( 'href' => $link, 'class' => 'apihelp-linktrail' ),
+                                               $name
+                                       );
+                                       $any = true;
+                               }
+                               array_unshift( $links, $link );
+                       }
+                       if ( $any ) {
+                               $help['header'] .= self::wrap(
+                                       $context->msg( 'parentheses' )
+                                               ->rawParams( $context->getLanguage()->pipeList( $links ) ),
+                                       'apihelp-linktrail', 'div'
+                               );
+                       }
+
+                       $flags = $module->getHelpFlags();
+                       if ( $flags ) {
+                               $help['flags'] .= Html::openElement( 'div',
+                                       array( 'class' => 'apihelp-block apihelp-flags' ) );
+                               $msg = $context->msg( 'api-help-flags' );
+                               if ( !$msg->isDisabled() ) {
+                                       $help['flags'] .= self::wrap(
+                                               $msg->numParams( count( $flags ) ), 'apihelp-block-head', 'div'
+                                       );
+                               }
+                               $help['flags'] .= Html::openElement( 'ul' );
+                               foreach ( $flags as $flag ) {
+                                       $help['flags'] .= Html::rawElement( 'li', null,
+                                               self::wrap( $context->msg( "api-help-flag-$flag" ), "apihelp-flag-$flag" )
+                                       );
+                               }
+                               $help['flags'] .= Html::closeElement( 'ul' );
+                               $help['flags'] .= Html::closeElement( 'div' );
+                       }
+
+                       foreach ( $module->getFinalDescription() as $msg ) {
+                               $msg->setContext( $context );
+                               $help['description'] .= $msg->parseAsBlock();
+                       }
+
+                       $urls = $module->getHelpUrls();
+                       if ( $urls ) {
+                               $help['help-urls'] .= Html::openElement( 'div',
+                                       array( 'class' => 'apihelp-block apihelp-help-urls' )
+                               );
+                               $msg = $context->msg( 'api-help-help-urls' );
+                               if ( !$msg->isDisabled() ) {
+                                       $help['help-urls'] .= self::wrap(
+                                               $msg->numParams( count( $urls ) ), 'apihelp-block-head', 'div'
+                                       );
+                               }
+                               if ( !is_array( $urls ) ) {
+                                       $urls = array( $urls );
+                               }
+                               $help['help-urls'] .= Html::openElement( 'ul' );
+                               foreach ( $urls as $url ) {
+                                       $help['help-urls'] .= Html::rawElement( 'li', null,
+                                               Html::element( 'a', array( 'href' => $url ), $url )
+                                       );
+                               }
+                               $help['help-urls'] .= Html::closeElement( 'ul' );
+                               $help['help-urls'] .= Html::closeElement( 'div' );
+                       }
+
+                       $params = $module->getFinalParams( ApiBase::GET_VALUES_FOR_HELP );
+                       $groups = array();
+                       if ( $params ) {
+                               $help['parameters'] .= Html::openElement( 'div',
+                                       array( 'class' => 'apihelp-block apihelp-parameters' )
+                               );
+                               $msg = $context->msg( 'api-help-parameters' );
+                               if ( !$msg->isDisabled() ) {
+                                       $help['parameters'] .= self::wrap(
+                                               $msg->numParams( count( $params ) ), 'apihelp-block-head', 'div'
+                                       );
+                               }
+                               $help['parameters'] .= Html::openElement( 'dl' );
+
+                               $descriptions = $module->getFinalParamDescription();
+
+                               foreach ( $params as $name => $settings ) {
+                                       if ( !is_array( $settings ) ) {
+                                               $settings = array( ApiBase::PARAM_DFLT => $settings );
+                                       }
+
+                                       $help['parameters'] .= Html::element( 'dt', null,
+                                               $module->encodeParamName( $name ) );
+
+                                       // Add description
+                                       $description = array();
+                                       if ( isset( $descriptions[$name] ) ) {
+                                               foreach ( $descriptions[$name] as $msg ) {
+                                                       $msg->setContext( $context );
+                                                       $description[] = $msg->parseAsBlock();
+                                               }
+                                       }
+
+                                       // Add usage info
+                                       $info = array();
+
+                                       // Required?
+                                       if ( !empty( $settings[ApiBase::PARAM_REQUIRED] ) ) {
+                                               $info[] = $context->msg( 'api-help-param-required' )->parse();
+                                       }
+
+                                       // Type documentation
+                                       if ( !isset( $settings[ApiBase::PARAM_TYPE] ) ) {
+                                               $dflt = isset( $settings[ApiBase::PARAM_DFLT] )
+                                                       ? $settings[ApiBase::PARAM_DFLT]
+                                                       : null;
+                                               if ( is_bool( $dflt ) ) {
+                                                       $settings[ApiBase::PARAM_TYPE] = 'boolean';
+                                               } elseif ( is_string( $dflt ) || is_null( $dflt ) ) {
+                                                       $settings[ApiBase::PARAM_TYPE] = 'string';
+                                               } elseif ( is_int( $dflt ) ) {
+                                                       $settings[ApiBase::PARAM_TYPE] = 'integer';
+                                               }
+                                       }
+                                       if ( isset( $settings[ApiBase::PARAM_TYPE] ) ) {
+                                               $type = $settings[ApiBase::PARAM_TYPE];
+                                               $multi = !empty( $settings[ApiBase::PARAM_ISMULTI] );
+                                               $hintPipeSeparated = true;
+                                               $count = ApiBase::LIMIT_SML2 + 1;
+
+                                               if ( is_array( $type ) ) {
+                                                       $count = count( $type );
+                                                       $type = array_map( 'wfEscapeWikiText', $type );
+                                                       $i = array_search( '', $type, true );
+                                                       if ( $i === false ) {
+                                                               $type = $context->getLanguage()->commaList( $type );
+                                                       } else {
+                                                               unset( $type[$i] );
+                                                               $type = $context->msg( 'api-help-param-list-can-be-empty' )
+                                                                       ->numParams( count( $type ) )
+                                                                       ->params( $context->getLanguage()->commaList( $type ) )
+                                                                       ->parse();
+                                                       }
+                                                       $info[] = $context->msg( 'api-help-param-list' )
+                                                               ->params( $multi ? 2 : 1 )
+                                                               ->params( $type )
+                                                               ->parse();
+                                                       $hintPipeSeparated = false;
+                                               } else {
+                                                       switch ( $type ) {
+                                                               case 'submodule':
+                                                                       $groups[] = $name;
+                                                                       $submodules = $module->getModuleManager()->getNames( $name );
+                                                                       $count = count( $submodules );
+                                                                       sort( $submodules );
+                                                                       $prefix = $module->isMain()
+                                                                               ? '' : ( $module->getModulePath() . '+' );
+                                                                       $submodules = array_map( function ( $name ) use ( $prefix ) {
+                                                                               return "[[Special:ApiHelp/{$prefix}{$name}|{$name}]]";
+                                                                       }, $submodules );
+                                                                       $info[] = $context->msg( 'api-help-param-list' )
+                                                                               ->params( $multi ? 2 : 1 )
+                                                                               ->params( $context->getLanguage()->commaList( $submodules ) )
+                                                                               ->parse();
+                                                                       $hintPipeSeparated = false;
+                                                                       break;
+
+                                                               case 'namespace':
+                                                                       $namespaces = MWNamespace::getValidNamespaces();
+                                                                       $count = count( $namespaces );
+                                                                       $info[] = $context->msg( 'api-help-param-list' )
+                                                                               ->params( $multi ? 2 : 1 )
+                                                                               ->params( $context->getLanguage()->commaList( $namespaces ) )
+                                                                               ->parse();
+                                                                       $hintPipeSeparated = false;
+                                                                       break;
+
+                                                               case 'limit':
+                                                                       if ( isset( $settings[ApiBase::PARAM_MAX2] ) ) {
+                                                                               $info[] = $context->msg( 'api-help-param-limit2' )
+                                                                                       ->numParams( $settings[ApiBase::PARAM_MAX] )
+                                                                                       ->numParams( $settings[ApiBase::PARAM_MAX2] )
+                                                                                       ->parse();
+                                                                       } else {
+                                                                               $info[] = $context->msg( 'api-help-param-limit' )
+                                                                                       ->numParams( $settings[ApiBase::PARAM_MAX] )
+                                                                                       ->parse();
+                                                                       }
+                                                                       break;
+
+                                                               case 'integer':
+                                                                       // Possible messages:
+                                                                       // api-help-param-integer-min,
+                                                                       // api-help-param-integer-max,
+                                                                       // api-help-param-integer-minmax
+                                                                       $suffix = '';
+                                                                       $min = $max = 0;
+                                                                       if ( isset( $settings[ApiBase::PARAM_MIN] ) ) {
+                                                                               $suffix .= 'min';
+                                                                               $min = $settings[ApiBase::PARAM_MIN];
+                                                                       }
+                                                                       if ( isset( $settings[ApiBase::PARAM_MAX] ) ) {
+                                                                               $suffix .= 'max';
+                                                                               $max = $settings[ApiBase::PARAM_MAX];
+                                                                       }
+                                                                       if ( $suffix !== '' ) {
+                                                                               $info[] =
+                                                                                       $context->msg( "api-help-param-integer-$suffix" )
+                                                                                               ->params( $multi ? 2 : 1 )
+                                                                                               ->numParams( $min, $max )
+                                                                                               ->parse();
+                                                                       }
+                                                                       break;
+
+                                                               case 'upload':
+                                                                       $info[] = $context->msg( 'api-help-param-upload' )
+                                                                               ->parse();
+                                                                       break;
+                                                       }
+                                               }
+
+                                               if ( $multi ) {
+                                                       $extra = array();
+                                                       if ( $hintPipeSeparated ) {
+                                                               $extra[] = $context->msg( 'api-help-param-multi-separate' )->parse();
+                                                       }
+                                                       if ( $count > ApiBase::LIMIT_SML1 ) {
+                                                               $extra[] = $context->msg( 'api-help-param-multi-max' )
+                                                                       ->numParams( ApiBase::LIMIT_SML1, ApiBase::LIMIT_SML2 )
+                                                                       ->parse();
+                                                       }
+                                                       if ( $extra ) {
+                                                               $info[] = join( ' ', $extra );
+                                                       }
+                                               }
+                                       }
+
+                                       // Add default
+                                       $default = isset( $settings[ApiBase::PARAM_DFLT] )
+                                               ? $settings[ApiBase::PARAM_DFLT]
+                                               : null;
+                                       if ( $default === '' ) {
+                                               $info[] = $context->msg( 'api-help-param-default-empty' )
+                                                       ->parse();
+                                       } elseif ( $default !== null && $default !== false ) {
+                                               $info[] = $context->msg( 'api-help-param-default' )
+                                                       ->params( wfEscapeWikiText( $default ) )
+                                                       ->parse();
+                                       }
+
+                                       if ( !$description && !$info ) {
+                                               $description[] = self::wrap(
+                                                       $context->msg( 'api-help-param-no-description' ),
+                                                       'apihelp-empty'
+                                               );
+                                       }
+
+                                       // Add "deprecated" flag
+                                       if ( !empty( $settings[ApiBase::PARAM_DEPRECATED] ) ) {
+                                               $help['parameters'] .= Html::openElement( 'dd',
+                                                       array( 'class' => 'info' ) );
+                                               $help['parameters'] .= self::wrap(
+                                                       $context->msg( 'api-help-param-deprecated' ),
+                                                       'apihelp-deprecated', 'strong'
+                                               );
+                                               $help['parameters'] .= Html::closeElement( 'dd' );
+                                       }
+
+                                       if ( $description ) {
+                                               $help['parameters'] .= Html::openElement( 'dd',
+                                                       array( 'class' => 'description' ) );
+                                               $help['parameters'] .= join( '', $description );
+                                               $help['parameters'] .= Html::closeElement( 'dd' );
+                                       }
+
+                                       foreach ( $info as $i ) {
+                                               $help['parameters'] .= Html::rawElement( 'dd', array( 'class' => 'info' ), $i );
+                                       }
+                               }
+
+                               $help['parameters'] .= Html::closeElement( 'dl' );
+                               $help['parameters'] .= Html::closeElement( 'div' );
+                       }
+
+                       $examples = $module->getExamplesMessages();
+                       if ( $examples ) {
+                               $help['examples'] .= Html::openElement( 'div',
+                                       array( 'class' => 'apihelp-block apihelp-examples' ) );
+                               $msg = $context->msg( 'api-help-examples' );
+                               if ( !$msg->isDisabled() ) {
+                                       $help['examples'] .= self::wrap(
+                                               $msg->numParams( count( $examples ) ), 'apihelp-block-head', 'div'
+                                       );
+                               }
+
+                               $help['examples'] .= Html::openElement( 'dl' );
+                               foreach ( $examples as $qs => $msg ) {
+                                       $msg = ApiBase::makeMessage( $msg, $context, array(
+                                               $module->getModulePrefix(),
+                                               $module->getModuleName(),
+                                               $module->getModulePath()
+                                       ) );
+
+                                       $link = wfAppendQuery( wfScript( 'api' ), $qs );
+                                       $help['examples'] .= Html::rawElement( 'dt', null, $msg->parse() );
+                                       $help['examples'] .= Html::rawElement( 'dd', null,
+                                               Html::element( 'a', array( 'href' => $link ), "api.php?$qs" )
+                                       );
+                               }
+                               $help['examples'] .= Html::closeElement( 'dl' );
+                               $help['examples'] .= Html::closeElement( 'div' );
+                       }
+
+                       if ( $options['submodules'] && $module->getModuleManager() ) {
+                               $manager = $module->getModuleManager();
+                               $submodules = array();
+                               foreach ( $groups as $group ) {
+                                       $names = $manager->getNames( $group );
+                                       sort( $names );
+                                       foreach ( $names as $name ) {
+                                               $submodules[] = $manager->getModule( $name );
+                                       }
+                               }
+                               $help['submodules'] .= self::getHelpInternal( $context, $submodules, array(
+                                       'submodules' => $options['recursivesubmodules'],
+                                       'headerlevel' => $level + 1,
+                                       'noheader' => false,
+                               ) + $options, $haveModules );
+                       }
+
+                       $module->modifyHelp( $help, $options );
 
-               $msg2 = $module->makeHelpMsg();
-               if ( $msg2 !== false ) {
-                       $msg .= $msg2;
+                       wfRunHooks( 'APIHelpModifyOutput', array( $module, &$help, $options ) );
+
+                       $out .= join( "\n", $help );
                }
 
-               return $msg;
+               return $out;
        }
 
        public function shouldCheckMaxlag() {
@@ -131,39 +606,36 @@ class ApiHelp extends ApiBase {
                return false;
        }
 
+       public function getCustomPrinter() {
+               $params = $this->extractRequestParams();
+               if ( $params['wrap'] ) {
+                       return null;
+               }
+
+               $main = $this->getMain();
+               $errorPrinter = $main->createPrinterByName( $main->getParameter( 'format' ) );
+               return new ApiFormatRaw( $main, $errorPrinter );
+       }
+
        public function getAllowedParams() {
                return array(
                        'modules' => array(
-                               ApiBase::PARAM_ISMULTI => true
-                       ),
-                       'querymodules' => array(
+                               ApiBase::PARAM_DFLT => 'main',
                                ApiBase::PARAM_ISMULTI => true,
-                               ApiBase::PARAM_DEPRECATED => true
                        ),
+                       'submodules' => false,
+                       'recursivesubmodules' => false,
+                       'wrap' => false,
+                       'toc' => false,
                );
        }
 
-       public function getParamDescription() {
-               return array(
-                       'modules' => 'List of module names (value of the action= parameter). ' .
-                               'Can specify submodules with a \'+\'',
-                       'querymodules' => 'Use modules=query+value instead. List of query ' .
-                               'module names (value of prop=, meta= or list= parameter)',
-               );
-       }
-
-       public function getDescription() {
-               return 'Display this help screen. Or the help screen for the specified module.';
-       }
-
-       public function getExamples() {
+       public function getExamplesMessages() {
                return array(
-                       'api.php?action=help' => 'Whole help page',
-                       'api.php?action=help&modules=protect' => 'Module (action) help page',
-                       'api.php?action=help&modules=query+categorymembers'
-                               => 'Help for the query/categorymembers module',
-                       'api.php?action=help&modules=login|query+info'
-                               => 'Help for the login and query/info modules',
+                       'action=help' => 'apihelp-help-example-main',
+                       'action=help&recursivesubmodules=1' => 'apihelp-help-example-recursive',
+                       'action=help&modules=help' => 'apihelp-help-example-help',
+                       'action=help&modules=query+info|query+categorymembers' => 'apihelp-help-example-query',
                );
        }
 
index bd20b14..a759c11 100644 (file)
@@ -42,7 +42,7 @@ class ApiMain extends ApiBase {
        /**
         * When no format parameter is given, this format will be used
         */
-       const API_DEFAULT_FORMAT = 'xmlfm';
+       const API_DEFAULT_FORMAT = 'jsonfm';
 
        /**
         * List of available modules: action name => module class
@@ -121,11 +121,11 @@ class ApiMain extends ApiBase {
         */
        private static $mRights = array(
                'writeapi' => array(
-                       'msg' => 'Use of the write API',
+                       'msg' => 'right-writeapi',
                        'params' => array()
                ),
                'apihighlimits' => array(
-                       'msg' => 'Use higher limits in API queries (Slow queries: $1 results; Fast queries: $2 results). The limits for slow queries also apply to multivalue parameters.',
+                       'msg' => 'api-help-right-apihighlimits',
                        'params' => array( ApiBase::LIMIT_SML2, ApiBase::LIMIT_BIG2 )
                )
        );
@@ -187,6 +187,19 @@ class ApiMain extends ApiBase {
                        }
                }
 
+               $uselang = $this->getParameter( 'uselang' );
+               if ( $uselang === 'user' ) {
+                       $uselang = $this->getUser()->getOption( 'language' );
+                       $uselang = RequestContext::sanitizeLangCode( $uselang );
+                       wfRunHooks( 'UserGetLanguageObject', array( $this->getUser(), &$uselang, $this ) );
+               }
+               $code = RequestContext::sanitizeLangCode( $uselang );
+               $this->getContext()->setLanguage( $code );
+               if ( !$this->mInternalMode ) {
+                       global $wgLang;
+                       $wgLang = RequestContext::getMain()->getLanguage();
+               }
+
                $config = $this->getConfig();
                $this->mModuleMgr = new ApiModuleManager( $this );
                $this->mModuleMgr->addModules( self::$Modules, 'action' );
@@ -290,6 +303,16 @@ class ApiMain extends ApiBase {
                        }
                }
 
+               if ( $mode === 'public' && $this->getParameter( 'uselang' ) === 'user' ) {
+                       // User language is used for i18n, so we don't want to publicly
+                       // cache. Anons are ok, because if they have non-default language
+                       // then there's an appropriate Vary header set by whatever set
+                       // their non-default language.
+                       wfDebug( __METHOD__ . ": downgrading cache mode 'public' to " .
+                          "'anon-public-user-private' due to uselang=user\n" );
+                       $mode = 'anon-public-user-private';
+               }
+
                wfDebug( __METHOD__ . ": setting cache mode $mode\n" );
                $this->mCacheMode = $mode;
        }
@@ -373,10 +396,6 @@ class ApiMain extends ApiBase {
                // avoid sending public cache headers for errors.
                $this->sendCacheHeaders();
 
-               if ( $this->mPrinter->getIsHtml() && !$this->mPrinter->isDisabled() ) {
-                       echo wfReportTime();
-               }
-
                ob_end_flush();
        }
 
@@ -670,13 +689,10 @@ class ApiMain extends ApiBase {
                $config = $this->getConfig();
 
                if ( $e instanceof UsageException ) {
-                       // User entered incorrect parameters - print usage screen
+                       // User entered incorrect parameters - generate error response
                        $errMessage = $e->getMessageArray();
-
-                       // Only print the help message when this is for the developer, not runtime
-                       if ( $this->mPrinter->getWantsHelp() || $this->mAction == 'help' ) {
-                               ApiResult::setContent( $errMessage, $this->makeHelpMsg() );
-                       }
+                       $link = wfExpandUrl( wfScript( 'api' ) );
+                       ApiResult::setContent( $errMessage, "See $link for API usage" );
                } else {
                        // Something is seriously wrong
                        if ( ( $e instanceof DBQueryError ) && !$config->get( 'ShowSQLErrors' ) ) {
@@ -1084,15 +1100,7 @@ class ApiMain extends ApiBase {
                $printer = $this->mPrinter;
                $printer->profileIn();
 
-               /**
-                * If the help message is requested in the default (xmlfm) format,
-                * tell the printer not to escape ampersands so that our links do
-                * not break.
-                */
-               $isHelp = $isError || $this->mAction == 'help';
-               $printer->setUnescapeAmps( $isHelp && $printer->getFormat() == 'XML' && $printer->getIsHtml() );
-
-               $printer->initPrinter( $isHelp );
+               $printer->initPrinter( false );
 
                $printer->execute();
                $printer->closePrinter();
@@ -1112,15 +1120,17 @@ class ApiMain extends ApiBase {
         * @return array
         */
        public function getAllowedParams() {
+               global $wgContLang;
+
                return array(
-                       'format' => array(
-                               ApiBase::PARAM_DFLT => ApiMain::API_DEFAULT_FORMAT,
-                               ApiBase::PARAM_TYPE => 'submodule',
-                       ),
                        'action' => array(
                                ApiBase::PARAM_DFLT => 'help',
                                ApiBase::PARAM_TYPE => 'submodule',
                        ),
+                       'format' => array(
+                               ApiBase::PARAM_DFLT => ApiMain::API_DEFAULT_FORMAT,
+                               ApiBase::PARAM_TYPE => 'submodule',
+                       ),
                        'maxlag' => array(
                                ApiBase::PARAM_TYPE => 'integer'
                        ),
@@ -1139,12 +1149,102 @@ class ApiMain extends ApiBase {
                        'servedby' => false,
                        'curtimestamp' => false,
                        'origin' => null,
+                       'uselang' => array(
+                               ApiBase::PARAM_DFLT => $wgContLang->getCode(),
+                       ),
+               );
+       }
+
+       /** @see ApiBase::getExamplesMessages() */
+       public function getExamplesMessages() {
+               return array(
+                       'action=help' => 'apihelp-help-example-main',
+                       'action=help&recursivesubmodules=1' => 'apihelp-help-example-recursive',
                );
        }
 
+       public function modifyHelp( array &$help, array $options ) {
+               // Wish PHP had an "array_insert_before". Instead, we have to manually
+               // reindex the array to get 'permissions' in the right place.
+               $oldHelp = $help;
+               $help = array();
+               foreach ( $oldHelp as $k => $v ) {
+                       if ( $k === 'submodules' ) {
+                               $help['permissions'] = '';
+                       }
+                       $help[$k] = $v;
+               }
+               $help['credits'] = '';
+
+               // Fill 'permissions'
+               $help['permissions'] .= Html::openElement( 'div',
+                       array( 'class' => 'apihelp-block apihelp-permissions' ) );
+               $m = $this->msg( 'api-help-permissions' );
+               if ( !$m->isDisabled() ) {
+                       $help['permissions'] .= Html::rawElement( 'div', array( 'class' => 'apihelp-block-head' ),
+                               $m->numParams( count( self::$mRights ) )->parse()
+                       );
+               }
+               $help['permissions'] .= Html::openElement( 'dl' );
+               foreach ( self::$mRights as $right => $rightMsg ) {
+                       $help['permissions'] .= Html::element( 'dt', null, $right );
+
+                       $rightMsg = $this->msg( $rightMsg['msg'], $rightMsg['params'] )->parse();
+                       $help['permissions'] .= Html::rawElement( 'dd', null, $rightMsg );
+
+                       $groups = array_map( function ( $group ) {
+                               return $group == '*' ? 'all' : $group;
+                       }, User::getGroupsWithPermission( $right ) );
+
+                       $help['permissions'] .= Html::rawElement( 'dd', null,
+                               $this->msg( 'api-help-permissions-granted-to' )
+                                       ->numParams( count( $groups ) )
+                                       ->params( $this->getLanguage()->commaList( $groups ) )
+                                       ->parse()
+                       );
+               }
+               $help['permissions'] .= Html::closeElement( 'dl' );
+               $help['permissions'] .= Html::closeElement( 'div' );
+
+               // Fill 'credits', if applicable
+               if ( empty( $options['nolead'] ) ) {
+                       $help['credits'] .= Html::element( 'h' . min( 6, $options['headerlevel'] + 1 ),
+                               array( 'id' => '+credits', 'class' => 'apihelp-header' ),
+                               $this->msg( 'api-credits-header' )->parse()
+                       );
+                       $help['credits'] .= $this->msg( 'api-credits' )->useDatabase( false )->parseAsBlock();
+               }
+       }
+
+       private $mCanApiHighLimits = null;
+
        /**
-        * See ApiBase for description.
-        *
+        * Check whether the current user is allowed to use high limits
+        * @return bool
+        */
+       public function canApiHighLimits() {
+               if ( !isset( $this->mCanApiHighLimits ) ) {
+                       $this->mCanApiHighLimits = $this->getUser()->isAllowed( 'apihighlimits' );
+               }
+
+               return $this->mCanApiHighLimits;
+       }
+
+       /**
+        * Overrides to return this instance's module manager.
+        * @return ApiModuleManager
+        */
+       public function getModuleManager() {
+               return $this->mModuleMgr;
+       }
+
+       /************************************************************************//**
+        * @name   Deprecated
+        * @{
+        */
+
+       /**
+        * @deprecated since 1.25
         * @return array
         */
        public function getParamDescription() {
@@ -1180,8 +1280,7 @@ class ApiMain extends ApiBase {
        }
 
        /**
-        * See ApiBase for description.
-        *
+        * @deprecated since 1.25
         * @return array
         */
        public function getDescription() {
@@ -1225,40 +1324,25 @@ class ApiMain extends ApiBase {
                );
        }
 
-       /**
-        * Returns an array of strings with credits for the API
-        * @return array
-        */
-       protected function getCredits() {
-               return array(
-                       'API developers:',
-                       '    Roan Kattouw (lead developer Sep 2007-2009)',
-                       '    Victor Vasiliev',
-                       '    Bryan Tong Minh',
-                       '    Sam Reed',
-                       '    Yuri Astrakhan (creator, lead developer Sep 2006-Sep 2007, 2012-2013)',
-                       '    Brad Jorsch (lead developer 2013-now)',
-                       '',
-                       'Please send your comments, suggestions and questions to mediawiki-api@lists.wikimedia.org',
-                       'or file a bug report at https://bugzilla.wikimedia.org/'
-               );
-       }
-
        /**
         * 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' );
                global $wgMemc;
                $this->setHelp();
                // Get help text from cache if present
@@ -1281,9 +1365,11 @@ class ApiMain extends ApiBase {
        }
 
        /**
+        * @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
@@ -1305,8 +1391,12 @@ class ApiMain extends ApiBase {
 
                $msg .= "\n$astriks Permissions $astriks\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  " . wfMsgReplaceArgs( $rightMsg['msg'], $rightMsg['params'] ) .
+                       $msg .= "* " . $right . " *\n  $rightsMsg" .
                                "\nGranted to:\n  " . str_replace( '*', 'all', implode( ', ', $groups ) ) . "\n\n";
                }
 
@@ -1321,18 +1411,22 @@ class ApiMain extends ApiBase {
                        $msg .= "\n";
                }
 
-               $msg .= "\n*** Credits: ***\n   " . implode( "\n   ", $this->getCredits() ) . "\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) ";
@@ -1341,20 +1435,6 @@ class ApiMain extends ApiBase {
                return "* $paramName={$module->getModuleName()} $modulePrefix*";
        }
 
-       private $mCanApiHighLimits = null;
-
-       /**
-        * Check whether the current user is allowed to use high limits
-        * @return bool
-        */
-       public function canApiHighLimits() {
-               if ( !isset( $this->mCanApiHighLimits ) ) {
-                       $this->mCanApiHighLimits = $this->getUser()->isAllowed( 'apihighlimits' );
-               }
-
-               return $this->mCanApiHighLimits;
-       }
-
        /**
         * Check whether the user wants us to show version information in the API help
         * @return bool
@@ -1366,14 +1446,6 @@ class ApiMain extends ApiBase {
                return false;
        }
 
-       /**
-        * Overrides to return this instance's module manager.
-        * @return ApiModuleManager
-        */
-       public function getModuleManager() {
-               return $this->mModuleMgr;
-       }
-
        /**
         * Add or overwrite a module in this ApiMain instance. Intended for use by extending
         * classes who wish to add their own modules to their lexicon or override the
@@ -1418,11 +1490,13 @@ class ApiMain extends ApiBase {
        public function getFormats() {
                return $this->getModuleManager()->getNamesWithClasses( 'format' );
        }
+
+       /**@}*/
+
 }
 
 /**
  * This exception will be thrown when dieUsage is called to stop module execution.
- * The exception handling code will print a help screen explaining how this API may be used.
  *
  * @ingroup API
  */
@@ -1476,3 +1550,8 @@ class UsageException extends MWException {
                return "{$this->getCodeString()}: {$this->getMessage()}";
        }
 }
+
+/**
+ * For really cool vim folding this needs to be at the end:
+ * vim: foldmarker=@{,@} foldmethod=marker
+ */
index 067b2f5..5965a46 100644 (file)
  */
 class ApiParamInfo extends ApiBase {
 
-       /**
-        * @var ApiQuery
-        */
-       protected $queryObj;
+       private $helpFormat;
+       private $context;
 
        public function __construct( ApiMain $main, $action ) {
                parent::__construct( $main, $action );
-               $this->queryObj = new ApiQuery( $this->getMain(), 'query' );
        }
 
        public function execute() {
+               global $wgContLang;
+
                // Get parameters
                $params = $this->extractRequestParams();
-               $resultObj = $this->getResult();
+
+               $this->helpFormat = $params['helpformat'];
+               $this->context = new RequestContext;
+               $this->context->setUser( new User ); // anon to avoid caching issues
+               $this->context->setLanguage( $this->getMain()->getLanguage() );
+
+               if ( is_array( $params['modules'] ) ) {
+                       $modules = $params['modules'];
+               } else {
+                       $modules = array();
+               }
+
+               if ( is_array( $params['querymodules'] ) ) {
+                       $this->logFeatureUsage( 'action=paraminfo&querymodules' );
+                       $queryModules = $params['querymodules'];
+                       foreach ( $queryModules as $m ) {
+                               $modules[] = 'query+' . $m;
+                       }
+               } else {
+                       $queryModules = array();
+               }
+
+               if ( is_array( $params['formatmodules'] ) ) {
+                       $this->logFeatureUsage( 'action=paraminfo&formatmodules' );
+                       $formatModules = $params['formatmodules'];
+                       foreach ( $formatModules as $m ) {
+                               $modules[] = $m;
+                       }
+               } else {
+                       $formatModules = array();
+               }
 
                $res = array();
 
-               $this->addModulesInfo( $params, 'modules', $res, $resultObj );
+               foreach ( $modules as $m ) {
+                       try {
+                               $module = $this->getModuleFromPath( $m );
+                       } catch ( UsageException $ex ) {
+                               $this->setWarning( $ex->getMessage() );
+                               continue;
+                       }
+                       $key = 'modules';
+
+                       // Back compat
+                       $isBCQuery = false;
+                       if ( $module->getParent() && $module->getParent()->getModuleName() == 'query' &&
+                               in_array( $module->getModuleName(), $queryModules )
+                       ) {
+                               $isBCQuery = true;
+                               $key = 'querymodules';
+                       }
+                       if ( in_array( $module->getModuleName(), $formatModules ) ) {
+                               $key = 'formatmodules';
+                       }
+
+                       $item = $this->getModuleInfo( $module );
+                       if ( $isBCQuery ) {
+                               $item['querytype'] = $item['group'];
+                       }
+                       $res[$key][] = $item;
+               }
+
+               $result = $this->getResult();
+               $result->addValue( array( $this->getModuleName() ), 'helpformat', $this->helpFormat );
 
-               $this->addModulesInfo( $params, 'querymodules', $res, $resultObj );
+               foreach ( $res as $key => $stuff ) {
+                       $result->setIndexedTagName( $res[$key], 'module' );
+               }
 
                if ( $params['mainmodule'] ) {
-                       $res['mainmodule'] = $this->getClassInfo( $this->getMain() );
+                       $this->logFeatureUsage( 'action=paraminfo&mainmodule' );
+                       $res['mainmodule'] = $this->getModuleInfo( $this->getMain() );
                }
 
                if ( $params['pagesetmodule'] ) {
-                       $pageSet = new ApiPageSet( $this->queryObj );
-                       $res['pagesetmodule'] = $this->getClassInfo( $pageSet );
+                       $this->logFeatureUsage( 'action=paraminfo&pagesetmodule' );
+                       $pageSet = new ApiPageSet( $this->getMain()->getModuleManager()->getModule( 'query' ) );
+                       $res['pagesetmodule'] = $this->getModuleInfo( $pageSet );
+                       unset( $res['pagesetmodule']['name'] );
+                       unset( $res['pagesetmodule']['path'] );
+                       unset( $res['pagesetmodule']['group'] );
                }
 
-               $this->addModulesInfo( $params, 'formatmodules', $res, $resultObj );
-
-               $resultObj->addValue( null, $this->getModuleName(), $res );
+               $result->addValue( null, $this->getModuleName(), $res );
        }
 
        /**
-        * If the type is requested in parameters, adds a section to res with module info.
-        * @param array $params User parameters array
-        * @param string $type Parameter name
-        * @param array $res Store results in this array
-        * @param ApiResult $resultObj Results object to set indexed tag.
+        * @param array $res Result array
+        * @param string $key Result key
+        * @param Message[] $msgs
         */
-       private function addModulesInfo( $params, $type, &$res, $resultObj ) {
-               if ( !is_array( $params[$type] ) ) {
-                       return;
-               }
-               $isQuery = ( $type === 'querymodules' );
-               if ( $isQuery ) {
-                       $mgr = $this->queryObj->getModuleManager();
-               } else {
-                       $mgr = $this->getMain()->getModuleManager();
-               }
-               $res[$type] = array();
-               foreach ( $params[$type] as $mod ) {
-                       if ( !$mgr->isDefined( $mod ) ) {
-                               $res[$type][] = array( 'name' => $mod, 'missing' => '' );
-                               continue;
-                       }
-                       $obj = $mgr->getModule( $mod );
-                       $item = $this->getClassInfo( $obj );
-                       $item['name'] = $mod;
-                       if ( $isQuery ) {
-                               $item['querytype'] = $mgr->getModuleGroup( $mod );
-                       }
-                       $res[$type][] = $item;
+       protected function formatHelpMessages( array &$res, $key, array $msgs ) {
+               switch ( $this->helpFormat ) {
+                       case 'none':
+                               break;
+
+                       case 'wikitext':
+                               $ret = array();
+                               foreach ( $msgs as $m ) {
+                                       $ret[] = $m->setContext( $this->context )->text();
+                               }
+                               $res[$key] = join( "\n\n", $ret );
+                               break;
+
+                       case 'html':
+                               $ret = array();
+                               foreach ( $msgs as $m ) {
+                                       $ret[] = $m->setContext( $this->context )->parseAsBlock();
+                               }
+                               $res[$key] = join( "\n", $ret );
+                               break;
+
+                       case 'raw':
+                               $res[$key] = array();
+                               foreach ( $msgs as $m ) {
+                                       $res[$key][] = array(
+                                               'key' => $m->getKey(),
+                                               'params' => $m->getParams(),
+                                       );
+                               }
+                               $this->getResult()->setIndexedTagName( $res[$key], 'msg' );
+                               break;
                }
-               $resultObj->setIndexedTagName( $res[$type], 'module' );
        }
 
        /**
-        * @param ApiBase $obj
+        * @param ApiBase $module
         * @return ApiResult
         */
-       private function getClassInfo( $obj ) {
+       private function getModuleInfo( $module ) {
                $result = $this->getResult();
-               $retval['classname'] = get_class( $obj );
-               $retval['description'] = implode( "\n", (array)$obj->getFinalDescription() );
-               $retval['examples'] = '';
-
-               // version is deprecated since 1.21, but needs to be returned for v1
-               $retval['version'] = '';
-               $retval['prefix'] = $obj->getModulePrefix();
-
-               if ( $obj->isReadMode() ) {
-                       $retval['readrights'] = '';
-               }
-               if ( $obj->isWriteMode() ) {
-                       $retval['writerights'] = '';
-               }
-               if ( $obj->mustBePosted() ) {
-                       $retval['mustbeposted'] = '';
-               }
-               if ( $obj instanceof ApiQueryGeneratorBase ) {
-                       $retval['generator'] = '';
+               $ret = array();
+
+               $ret['name'] = $module->getModuleName();
+               $ret['classname'] = get_class( $module );
+               $ret['path'] = $module->getModulePath();
+               if ( !$module->isMain() ) {
+                       $ret['group'] = $module->getParent()->getModuleManager()->getModuleGroup(
+                               $module->getModuleName()
+                       );
                }
+               $ret['prefix'] = $module->getModulePrefix();
 
-               $allowedParams = $obj->getFinalParams( ApiBase::GET_VALUES_FOR_HELP );
-               if ( !is_array( $allowedParams ) ) {
-                       return $retval;
-               }
+               $this->formatHelpMessages( $ret, 'description', $module->getFinalDescription() );
 
-               $retval['helpurls'] = (array)$obj->getHelpUrls();
-               if ( isset( $retval['helpurls'][0] ) && $retval['helpurls'][0] === false ) {
-                       $retval['helpurls'] = array();
+               foreach ( $module->getHelpFlags() as $flag ) {
+                       $ret[$flag] = '';
                }
-               $result->setIndexedTagName( $retval['helpurls'], 'helpurl' );
 
-               $examples = $obj->getExamples();
-               $retval['allexamples'] = array();
-               if ( $examples !== false ) {
-                       if ( is_string( $examples ) ) {
-                               $examples = array( $examples );
-                       }
-                       foreach ( $examples as $k => $v ) {
-                               if ( strlen( $retval['examples'] ) ) {
-                                       $retval['examples'] .= ' ';
-                               }
-                               $item = array();
-                               if ( is_numeric( $k ) ) {
-                                       $retval['examples'] .= $v;
-                                       ApiResult::setContent( $item, $v );
-                               } else {
-                                       if ( !is_array( $v ) ) {
-                                               $item['description'] = $v;
+               $ret['helpurls'] = (array)$module->getHelpUrls();
+               if ( isset( $ret['helpurls'][0] ) && $ret['helpurls'][0] === false ) {
+                       $ret['helpurls'] = array();
+               }
+               $result->setIndexedTagName( $ret['helpurls'], 'helpurl' );
+
+               if ( $this->helpFormat !== 'none' ) {
+                       $ret['examples'] = array();
+                       $examples = $module->getExamplesMessages();
+                       foreach ( $examples as $qs => $msg ) {
+                               $item = array(
+                                       'query' => $qs
+                               );
+                               $msg = ApiBase::makeMessage( $msg, $this->context, array(
+                                       $module->getModulePrefix(),
+                                       $module->getModuleName(),
+                                       $module->getModulePath()
+                               ) );
+                               $this->formatHelpMessages( $item, 'description', array( $msg ) );
+                               if ( isset( $item['description'] ) ) {
+                                       if ( is_array( $item['description'] ) ) {
+                                               $item['description'] = $item['description'][0];
                                        } else {
-                                               $item['description'] = implode( $v, "\n" );
+                                               $result->setSubelements( $item, 'description' );
                                        }
-                                       $retval['examples'] .= $item['description'] . ' ' . $k;
-                                       ApiResult::setContent( $item, $k );
                                }
-                               $retval['allexamples'][] = $item;
+                               $ret['examples'][] = $item;
                        }
+                       $result->setIndexedTagName( $ret['examples'], 'example' );
                }
-               $result->setIndexedTagName( $retval['allexamples'], 'example' );
-
-               $retval['parameters'] = array();
-               $paramDesc = $obj->getFinalParamDescription();
-               foreach ( $allowedParams as $n => $p ) {
-                       $a = array( 'name' => $n );
-                       if ( isset( $paramDesc[$n] ) ) {
-                               $a['description'] = implode( "\n", (array)$paramDesc[$n] );
+
+               $ret['parameters'] = array();
+               $params = $module->getFinalParams( ApiBase::GET_VALUES_FOR_HELP );
+               $paramDesc = $module->getFinalParamDescription();
+               foreach ( $params as $name => $settings ) {
+                       if ( !is_array( $settings ) ) {
+                               $settings = array( ApiBase::PARAM_DFLT => $settings );
                        }
 
-                       //handle shorthand
-                       if ( !is_array( $p ) ) {
-                               $p = array(
-                                       ApiBase::PARAM_DFLT => $p,
-                               );
+                       $item = array(
+                               'name' => $name
+                       );
+                       if ( isset( $paramDesc[$name] ) ) {
+                               $this->formatHelpMessages( $item, 'description', $paramDesc[$name] );
                        }
 
-                       //handle missing type
-                       if ( !isset( $p[ApiBase::PARAM_TYPE] ) ) {
-                               $dflt = isset( $p[ApiBase::PARAM_DFLT] ) ? $p[ApiBase::PARAM_DFLT] : null;
-                               if ( is_bool( $dflt ) ) {
-                                       $p[ApiBase::PARAM_TYPE] = 'boolean';
-                               } elseif ( is_string( $dflt ) || is_null( $dflt ) ) {
-                                       $p[ApiBase::PARAM_TYPE] = 'string';
-                               } elseif ( is_int( $dflt ) ) {
-                                       $p[ApiBase::PARAM_TYPE] = 'integer';
-                               }
+                       if ( !empty( $settings[ApiBase::PARAM_REQUIRED] ) ) {
+                               $item['required'] = '';
                        }
 
-                       if ( isset( $p[ApiBase::PARAM_DEPRECATED] ) && $p[ApiBase::PARAM_DEPRECATED] ) {
-                               $a['deprecated'] = '';
+                       if ( !empty( $settings[ApiBase::PARAM_DEPRECATED] ) ) {
+                               $item['deprecated'] = '';
                        }
-                       if ( isset( $p[ApiBase::PARAM_REQUIRED] ) && $p[ApiBase::PARAM_REQUIRED] ) {
-                               $a['required'] = '';
+
+                       if ( $name === 'token' && $module->needsToken() ) {
+                               $item['tokentype'] = $module->needsToken();
                        }
 
-                       if ( $n === 'token' && $obj->needsToken() ) {
-                               $a['tokentype'] = $obj->needsToken();
+                       if ( !isset( $settings[ApiBase::PARAM_TYPE] ) ) {
+                               $dflt = isset( $settings[ApiBase::PARAM_DFLT] )
+                                       ? $settings[ApiBase::PARAM_DFLT]
+                                       : null;
+                               if ( is_bool( $dflt ) ) {
+                                       $settings[ApiBase::PARAM_TYPE] = 'boolean';
+                               } elseif ( is_string( $dflt ) || is_null( $dflt ) ) {
+                                       $settings[ApiBase::PARAM_TYPE] = 'string';
+                               } elseif ( is_int( $dflt ) ) {
+                                       $settings[ApiBase::PARAM_TYPE] = 'integer';
+                               }
                        }
 
-                       if ( isset( $p[ApiBase::PARAM_DFLT] ) ) {
-                               $type = $p[ApiBase::PARAM_TYPE];
-                               if ( $type === 'boolean' ) {
-                                       $a['default'] = ( $p[ApiBase::PARAM_DFLT] ? 'true' : 'false' );
-                               } elseif ( $type === 'string' ) {
-                                       $a['default'] = strval( $p[ApiBase::PARAM_DFLT] );
-                               } elseif ( $type === 'integer' ) {
-                                       $a['default'] = intval( $p[ApiBase::PARAM_DFLT] );
-                               } else {
-                                       $a['default'] = $p[ApiBase::PARAM_DFLT];
+                       if ( isset( $settings[ApiBase::PARAM_DFLT] ) ) {
+                               switch ( $settings[ApiBase::PARAM_TYPE] ) {
+                                       case 'boolean':
+                                               $item['default'] = ( $settings[ApiBase::PARAM_DFLT] ? 'true' : 'false' );
+                                               break;
+                                       case 'string':
+                                               $item['default'] = strval( $settings[ApiBase::PARAM_DFLT] );
+                                               break;
+                                       case 'integer':
+                                               $item['default'] = intval( $settings[ApiBase::PARAM_DFLT] );
+                                               break;
+                                       default:
+                                               $item['default'] = $settings[ApiBase::PARAM_DFLT];
+                                               break;
                                }
                        }
-                       if ( isset( $p[ApiBase::PARAM_ISMULTI] ) && $p[ApiBase::PARAM_ISMULTI] ) {
-                               $a['multi'] = '';
-                               $a['limit'] = $this->getMain()->canApiHighLimits() ?
+
+                       if ( !empty( $settings[ApiBase::PARAM_ISMULTI] ) ) {
+                               $item['multi'] = '';
+                               $item['limit'] = $this->getMain()->canApiHighLimits() ?
                                        ApiBase::LIMIT_SML2 :
                                        ApiBase::LIMIT_SML1;
-                               $a['lowlimit'] = ApiBase::LIMIT_SML1;
-                               $a['highlimit'] = ApiBase::LIMIT_SML2;
+                               $item['lowlimit'] = ApiBase::LIMIT_SML1;
+                               $item['highlimit'] = ApiBase::LIMIT_SML2;
                        }
 
-                       if ( isset( $p[ApiBase::PARAM_ALLOW_DUPLICATES] ) && $p[ApiBase::PARAM_ALLOW_DUPLICATES] ) {
-                               $a['allowsduplicates'] = '';
+                       if ( !empty( $settings[ApiBase::PARAM_ALLOW_DUPLICATES] ) ) {
+                               $item['allowsduplicates'] = '';
                        }
 
-                       if ( isset( $p[ApiBase::PARAM_TYPE] ) ) {
-                               if ( $p[ApiBase::PARAM_TYPE] === 'submodule' ) {
-                                       $a['type'] = $obj->getModuleManager()->getNames( $n );
-                                       sort( $a['type'] );
-                                       $a['submodules'] = '';
+                       if ( isset( $settings[ApiBase::PARAM_TYPE] ) ) {
+                               if ( $settings[ApiBase::PARAM_TYPE] === 'submodule' ) {
+                                       $item['type'] = $module->getModuleManager()->getNames( $name );
+                                       sort( $item['type'] );
+                                       $item['submodules'] = '';
                                } else {
-                                       $a['type'] = $p[ApiBase::PARAM_TYPE];
+                                       $item['type'] = $settings[ApiBase::PARAM_TYPE];
                                }
-                               if ( is_array( $a['type'] ) ) {
+                               if ( is_array( $item['type'] ) ) {
                                        // To prevent sparse arrays from being serialized to JSON as objects
-                                       $a['type'] = array_values( $a['type'] );
-                                       $result->setIndexedTagName( $a['type'], 't' );
+                                       $item['type'] = array_values( $item['type'] );
+                                       $result->setIndexedTagName( $item['type'], 't' );
                                }
                        }
-                       if ( isset( $p[ApiBase::PARAM_MAX] ) ) {
-                               $a['max'] = $p[ApiBase::PARAM_MAX];
+                       if ( isset( $settings[ApiBase::PARAM_MAX] ) ) {
+                               $item['max'] = $settings[ApiBase::PARAM_MAX];
                        }
-                       if ( isset( $p[ApiBase::PARAM_MAX2] ) ) {
-                               $a['highmax'] = $p[ApiBase::PARAM_MAX2];
+                       if ( isset( $settings[ApiBase::PARAM_MAX2] ) ) {
+                               $item['highmax'] = $settings[ApiBase::PARAM_MAX2];
                        }
-                       if ( isset( $p[ApiBase::PARAM_MIN] ) ) {
-                               $a['min'] = $p[ApiBase::PARAM_MIN];
+                       if ( isset( $settings[ApiBase::PARAM_MIN] ) ) {
+                               $item['min'] = $settings[ApiBase::PARAM_MIN];
                        }
-                       $retval['parameters'][] = $a;
+                       $ret['parameters'][] = $item;
                }
-               $result->setIndexedTagName( $retval['parameters'], 'param' );
+               $result->setIndexedTagName( $ret['parameters'], 'param' );
 
-               return $retval;
+               return $ret;
        }
 
        public function isReadMode() {
@@ -262,9 +326,9 @@ class ApiParamInfo extends ApiBase {
        }
 
        public function getAllowedParams() {
-               $modules = $this->getMain()->getModuleManager()->getNames( 'action' );
-               sort( $modules );
-               $querymodules = $this->queryObj->getModuleManager()->getNames();
+               // back compat
+               $querymodules = $this->getMain()->getModuleManager()
+                       ->getModule( 'query' )->getModuleManager()->getNames();
                sort( $querymodules );
                $formatmodules = $this->getMain()->getModuleManager()->getNames( 'format' );
                sort( $formatmodules );
@@ -272,15 +336,25 @@ class ApiParamInfo extends ApiBase {
                return array(
                        'modules' => array(
                                ApiBase::PARAM_ISMULTI => true,
-                               ApiBase::PARAM_TYPE => $modules,
                        ),
+                       'helpformat' => array(
+                               ApiBase::PARAM_DFLT => 'none',
+                               ApiBase::PARAM_TYPE => array( 'html', 'wikitext', 'raw', 'none' ),
+                       ),
+
                        'querymodules' => array(
+                               ApiBase::PARAM_DEPRECATED => true,
                                ApiBase::PARAM_ISMULTI => true,
                                ApiBase::PARAM_TYPE => $querymodules,
                        ),
-                       'mainmodule' => false,
-                       'pagesetmodule' => false,
+                       'mainmodule' => array(
+                               ApiBase::PARAM_DEPRECATED => true,
+                       ),
+                       'pagesetmodule' => array(
+                               ApiBase::PARAM_DEPRECATED => true,
+                       ),
                        'formatmodules' => array(
+                               ApiBase::PARAM_DEPRECATED => true,
                                ApiBase::PARAM_ISMULTI => true,
                                ApiBase::PARAM_TYPE => $formatmodules,
                        )
@@ -289,7 +363,9 @@ class ApiParamInfo extends ApiBase {
 
        public function getParamDescription() {
                return array(
-                       'modules' => 'List of module names (value of the action= parameter)',
+                       'modules' => 'List of module names (values of the action= and format= parameters, or "main"). Can specify submodules with a \'+\'',
+                       'helpformat' => 'Format of help strings',
+
                        'querymodules' => 'List of query module names (value of prop=, meta= or list= parameter)',
                        'mainmodule' => 'Get information about the main (top-level) module as well',
                        'pagesetmodule' => 'Get information about the pageset module ' .
@@ -304,7 +380,7 @@ class ApiParamInfo extends ApiBase {
 
        public function getExamples() {
                return array(
-                       'api.php?action=paraminfo&modules=parse&querymodules=allpages|siteinfo'
+                       'api.php?action=paraminfo&modules=parse|phpfm|query+allpages|query+siteinfo'
                );
        }
 
index 06fdf85..0b1f4db 100644 (file)
@@ -79,16 +79,6 @@ class ApiParse extends ApiBase {
                // TODO: Does this still need $wgTitle?
                global $wgParser, $wgTitle;
 
-               // Currently unnecessary, code to act as a safeguard against any change
-               // in current behavior of uselang
-               $oldLang = null;
-               if ( isset( $params['uselang'] )
-                       && $params['uselang'] != $this->getContext()->getLanguage()->getCode()
-               ) {
-                       $oldLang = $this->getContext()->getLanguage(); // Backup language
-                       $this->getContext()->setLanguage( Language::factory( $params['uselang'] ) );
-               }
-
                $redirValues = null;
 
                // Return result
@@ -409,10 +399,6 @@ class ApiParse extends ApiBase {
                );
                $this->setIndexedTagNames( $result_array, $result_mapping );
                $result->addValue( null, $this->getModuleName(), $result_array );
-
-               if ( !is_null( $oldLang ) ) {
-                       $this->getContext()->setLanguage( $oldLang ); // Reset language to $oldLang
-               }
        }
 
        /**
@@ -499,7 +485,7 @@ class ApiParse extends ApiBase {
                        $entry['lang'] = $bits[0];
                        if ( $title ) {
                                $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
-                               // localised language name in user language (maybe set by uselang=)
+                               // localised language name in 'uselang' language
                                $entry['langname'] = Language::fetchLanguageName(
                                        $title->getInterwiki(),
                                        $this->getLanguage()->getCode()
@@ -704,7 +690,6 @@ class ApiParse extends ApiBase {
                        'pst' => false,
                        'onlypst' => false,
                        'effectivelanglinks' => false,
-                       'uselang' => null,
                        'section' => null,
                        'disablepp' => false,
                        'disableeditsection' => false,
@@ -771,7 +756,6 @@ class ApiParse extends ApiBase {
                                'Returns the same wikitext, after a PST has been applied.',
                                "Only valid when used with {$p}text",
                        ),
-                       'uselang' => 'Which language to parse the request in',
                        'section' => 'Only retrieve the content of this section number',
                        'disablepp' => 'Disable the PP Report from the parser output',
                        'disableeditsection' => 'Disable edit section links from the parser output',
index 7c750e4..a8e20dc 100644 (file)
@@ -540,9 +540,11 @@ class ApiQuery extends ApiBase {
 
        /**
         * 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();
@@ -562,6 +564,7 @@ class ApiQuery extends ApiBase {
 
        /**
         * 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
         */
index 65e10ab..b1581f3 100644 (file)
@@ -90,6 +90,13 @@ abstract class ApiQueryBase extends ApiBase {
                return $this->mQueryModule;
        }
 
+       /**
+        * @see ApiBase::getParent()
+        */
+       public function getParent() {
+               return $this->getQuery();
+       }
+
        /**
         * Get the Query database connection (read-only)
         * @return DatabaseBase
@@ -711,6 +718,17 @@ abstract class ApiQueryGeneratorBase extends ApiQueryBase {
                }
        }
 
+       /**
+        * @see ApiBase::getHelpFlags()
+        *
+        * Corresponding messages: api-help-flag-generator
+        */
+       protected function getHelpFlags() {
+               $flags = parent::getHelpFlags();
+               $flags[] = 'generator';
+               return $flags;
+       }
+
        /**
         * Execute this module as a generator
         * @param ApiPageSet $resultPageSet All output should be appended to this object
index 2e80447..946977d 100644 (file)
@@ -569,6 +569,7 @@ class ApiResult extends ApiBase {
                } else {
                        $key = 'continue';
                        $data = array();
+                       $batchcomplete = false;
 
                        $finishedModules = array_diff(
                                array_keys( $this->continueAllModules ),
@@ -611,9 +612,11 @@ class ApiResult extends ApiBase {
                                $finishedModules = array_diff(
                                        $finishedModules, $this->continueGeneratedModules
                                );
+                               $batchcomplete = true;
                        } else {
                                // Generator and prop modules are all done. Mark it so.
                                $this->generatorDone = true;
+                               $batchcomplete = true;
                        }
 
                        // Set 'continue' if any continuation data is set or if the generator
@@ -623,6 +626,10 @@ class ApiResult extends ApiBase {
                                        ( $this->generatorDone ? '-' : join( '|', $this->generatorParams ) ) .
                                        '||' . join( '|', $finishedModules );
                        }
+
+                       if ( $batchcomplete ) {
+                               $this->addValue( null, 'batchcomplete', '', ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
+                       }
                }
                if ( $data ) {
                        $this->addValue( null, $key, $data, ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
index 164594e..e5e9d5d 100644 (file)
@@ -77,6 +77,10 @@ class ApiTokens extends ApiBase {
                return $types;
        }
 
+       public function isDeprecated() {
+               return true;
+       }
+
        public function getAllowedParams() {
                return array(
                        'type' => array(
index e6a660b..8cd0f05 100644 (file)
@@ -104,17 +104,6 @@ class ApiWatch extends ApiBase {
 
                $res = array( 'title' => $title->getPrefixedText() );
 
-               // Currently unnecessary, code to act as a safeguard against any change
-               // in current behavior of uselang.
-               // Copy from ApiParse
-               $oldLang = null;
-               if ( isset( $params['uselang'] ) &&
-                       $params['uselang'] != $this->getContext()->getLanguage()->getCode()
-               ) {
-                       $oldLang = $this->getContext()->getLanguage(); // Backup language
-                       $this->getContext()->setLanguage( Language::factory( $params['uselang'] ) );
-               }
-
                if ( $params['unwatch'] ) {
                        $status = UnwatchAction::doUnwatch( $title, $user );
                        if ( $status->isOK() ) {
@@ -131,10 +120,6 @@ class ApiWatch extends ApiBase {
                        }
                }
 
-               if ( !is_null( $oldLang ) ) {
-                       $this->getContext()->setLanguage( $oldLang ); // Reset language to $oldLang
-               }
-
                if ( !$status->isOK() ) {
                        if ( $compatibilityMode ) {
                                $this->dieStatus( $status );
@@ -176,7 +161,6 @@ class ApiWatch extends ApiBase {
                                ApiBase::PARAM_DEPRECATED => true
                        ),
                        'unwatch' => false,
-                       'uselang' => null,
                        'continue' => '',
                );
                if ( $flags ) {
@@ -192,7 +176,6 @@ class ApiWatch extends ApiBase {
                return $psModule->getParamDescription() + array(
                        'title' => 'The page to (un)watch. use titles instead',
                        'unwatch' => 'If set the page will be unwatched rather than watched',
-                       'uselang' => 'Language to show the message in',
                        'continue' => 'When more results are available, use this to continue',
                );
        }
diff --git a/includes/api/i18n/en.json b/includes/api/i18n/en.json
new file mode 100644 (file)
index 0000000..6c45425
--- /dev/null
@@ -0,0 +1,98 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Anomie"
+               ]
+       },
+
+       "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page Documentation]\n* [https://www.mediawiki.org/wiki/API:FAQ FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mailing list]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API Announcements]\n* [https://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts Bugs & requests]\n</div>\n<strong>Status:</strong> All features shown on this page should be working, but the API is still in active development, and may change at any time. Subscribe to [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce mailing list] for notice of updates.\n\n<strong>Erroneous requests:</strong> When erroneous requests are sent to the API, a HTTP header will be sent with the key \"MediaWiki-API-Error\" and then both the value of the header and the error code sent back will be set to the same value. For more information see https://www.mediawiki.org/wiki/API:Errors_and_warnings.",
+       "apihelp-main-param-action": "Which action to perform.",
+       "apihelp-main-param-format": "The format of the output.",
+       "apihelp-main-param-maxlag": "Maximum lag can be used when MediaWiki is installed on a database replicated cluster. To save actions causing any more site replication lag, this parameter can make the client wait until the replication lag is less than the specified value. In case of excessive lag, error code \"maxlag\" is returned with a message like \"Waiting for $host: $lag seconds lagged\".<br />See https://www.mediawiki.org/wiki/Manual:Maxlag_parameter for more information.",
+       "apihelp-main-param-smaxage": "Set the s-maxage header to this many seconds. Errors are never cached.",
+       "apihelp-main-param-maxage": "Set the max-age header to this many seconds. Errors are never cached.",
+       "apihelp-main-param-assert": "Verify the user is logged in if set to \"user\", or has the bot userright if \"bot\".",
+       "apihelp-main-param-requestid": "Any value given here will be included in the response. May be used to distinguish requests.",
+       "apihelp-main-param-servedby": "Include the hostname that served the request in the results.",
+       "apihelp-main-param-curtimestamp": "Include the current timestamp in the result.",
+       "apihelp-main-param-origin": "When accessing the API using a cross-domain AJAX request (CORS), set this to the originating domain. This must be included in any pre-flight request, and therefore must be part of the request URI (not the POST body). This must match one of the origins in the Origin: header exactly, so it has to be set to something like http://en.wikipedia.org or https://meta.wikimedia.org. If this parameter does not match the Origin: header, a 403 response will be returned. If this parameter matches the Origin: header and the origin is whitelisted, an Access-Control-Allow-Origin header will be set.",
+       "apihelp-main-param-uselang": "Language to use for message translations. A list of codes may be fetched from [[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo&siprop=languages]], or specify \"user\" to use the current user's language preference.",
+
+       "apihelp-format-example-generic": "Format the query result in the $1 format",
+       "apihelp-dbg-description": "Output data in PHP's var_export() format.",
+       "apihelp-dbgfm-description": "Output data in PHP's var_export() format (pretty-print in HTML).",
+       "apihelp-dump-description": "Output data in PHP's var_dump() format.",
+       "apihelp-dumpfm-description": "Output data in PHP's var_dump() format (pretty-print in HTML).",
+       "apihelp-json-description": "Output data in JSON format.",
+       "apihelp-json-param-callback": "If specified, wraps the output into a given function call. For safety, all user-specific data will be restricted.",
+       "apihelp-json-param-utf8": "If specified, encodes most (but not all) non-ASCII characters as UTF-8 instead of replacing them with hexadecimal escape sequences.",
+       "apihelp-jsonfm-description": "Output data in JSON format (pretty-print in HTML).",
+       "apihelp-none-description": "Output nothing.",
+       "apihelp-php-description": "Output data in serialized PHP format.",
+       "apihelp-phpfm-description": "Output data in serialized PHP format (pretty-print in HTML).",
+       "apihelp-rawfm-description": "Output data with the debugging elements in JSON format (pretty-print in HTML).",
+       "apihelp-txt-description": "Output data in PHP's print_r() format.",
+       "apihelp-txtfm-description": "Output data in PHP's print_r() format (pretty-print in HTML).",
+       "apihelp-wddx-description": "Output data in WDDX format.",
+       "apihelp-wddxfm-description": "Output data in WDDX format (pretty-print in HTML).",
+       "apihelp-xml-description": "Output data in XML format.",
+       "apihelp-xml-param-xslt": "If specified, adds &lt;xslt&gt; as stylesheet. This should be a wiki page in the MediaWiki namespace whose page name ends with \".xsl\".",
+       "apihelp-xml-param-includexmlnamespac": "If specified, adds an XML namespace.",
+       "apihelp-xmlfm-description": "Output data in XML format (pretty-print in HTML).",
+       "apihelp-yaml-description": "Output data in YAML format.",
+       "apihelp-yamlfm-description": "Output data in YAML format (pretty-print in HTML).",
+
+       "apihelp-help-description": "Display help for the specified modules.",
+       "apihelp-help-param-modules": "Modules to display help for (values of the action= and format= parameters, or \"main\"). Can specify submodules with a \"+\".",
+       "apihelp-help-param-submodules": "Include help for submodules of the named module.",
+       "apihelp-help-param-recursivesubmodules": "Include help for submodules recursively.",
+       "apihelp-help-param-helpformat": "Format of the help output.",
+       "apihelp-help-param-wrap": "Wrap the output in a standard API response structure.",
+       "apihelp-help-param-toc": "Include a table of contents in the HTML output.",
+       "apihelp-help-example-main": "Help for the main module",
+       "apihelp-help-example-recursive": "All help in one page",
+       "apihelp-help-example-help": "Help for the help module itself",
+       "apihelp-help-example-query": "Help for two query submodules",
+
+       "api-format-title": "MediaWiki API result",
+       "api-format-prettyprint-header": "You are looking at the HTML representation of the $1 format. HTML is good for debugging, but is unsuitable for application use.\n\nSpecify the format parameter to change the output format. To see the non-HTML representation of the $1 format, set format=$2.\n\nSee the [https://www.mediawiki.org/wiki/API complete documentation], or [[Special:ApiHelp/main|API help]] for more information.",
+
+       "api-help-title": "MediaWiki API help",
+       "api-help-lead": "This is an auto-generated MediaWiki API documentation page.\n\nDocumentation and examples: https://www.mediawiki.org/wiki/API",
+       "api-help-main-header": "Main module",
+       "api-help-fallback-description": "$1",
+       "api-help-fallback-parameter": "$1",
+       "api-help-fallback-example": "$1",
+       "api-help-flags": "",
+       "api-help-flag-deprecated": "This module is deprecated.",
+       "api-help-flag-internal": "<strong>This module is internal or unstable.</strong> Its operation may change without notice.",
+       "api-help-flag-readrights": "This module requires read rights.",
+       "api-help-flag-writerights": "This module requires write rights.",
+       "api-help-flag-mustbeposted": "This module only accepts POST requests.",
+       "api-help-flag-generator": "This module can be used as a generator.",
+       "api-help-help-urls": "",
+       "api-help-parameters": "{{PLURAL:$1|Parameter|Parameters}}:",
+       "api-help-param-deprecated": "Deprecated.",
+       "api-help-param-required": "This parameter is required.",
+       "api-help-param-list": "{{PLURAL:$1|1=One value|2=Values (separate with \"{{!}}\")}}: $2",
+       "api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Must be empty|Can be empty, or $2}}",
+       "api-help-param-limit": "No more than $1 allowed.",
+       "api-help-param-limit2": "No more than $1 ($2 for bots) allowed.",
+       "api-help-param-integer-min": "The {{PLURAL:$1|1=value|2=values}} must be no less than $2.",
+       "api-help-param-integer-max": "The {{PLURAL:$1|1=value|2=values}} must be no greater than $3.",
+       "api-help-param-integer-minmax": "The {{PLURAL:$1|1=value|2=values}} must be between $2 and $3.",
+       "api-help-param-upload": "Must be posted as a file upload using multipart/form-data.",
+       "api-help-param-multi-separate": "Separate values with \"|\".",
+       "api-help-param-multi-max": "Maximum number of values is {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} for bots).",
+       "api-help-param-default": "Default: $1",
+       "api-help-param-default-empty": "Default: <span class=\"apihelp-empty\">(empty)</span>",
+       "api-help-param-token": "A \"$1\" token retrieved from [[Special:ApiHelp/query+tokens|action=query&meta=tokens]]",
+       "api-help-param-no-description": "<span class=\"apihelp-empty\">(no description)</span>",
+       "api-help-examples": "{{PLURAL:$1|Example|Examples}}:",
+       "api-help-permissions": "{{PLURAL:$1|Permission|Permissions}}:",
+       "api-help-permissions-granted-to": "{{PLURAL:$1|Granted to}}: $2",
+       "api-help-right-apihighlimits": "Use higher limits in API queries (slow queries: $1; fast queries: $2). The limits for slow queries also apply to multivalue parameters.",
+
+       "api-credits-header": "Credits",
+       "api-credits": "API developers:\n* Roan Kattouw (lead developer Sep 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (creator, lead developer Sep 2006–Sep 2007)\n* Brad Jorsch (lead developer 2013–present)\n\nPlease send your comments, suggestions and questions to mediawiki-api@lists.wikimedia.org\nor file a bug report at https://bugzilla.wikimedia.org/."
+}
diff --git a/includes/api/i18n/qqq.json b/includes/api/i18n/qqq.json
new file mode 100644 (file)
index 0000000..a4dfd7c
--- /dev/null
@@ -0,0 +1,96 @@
+{
+       "@metadata": {
+               "authors": []
+       },
+
+       "apihelp-main-description": "{{doc-apihelp-description|main}}",
+       "apihelp-main-param-action": "{{doc-apihelp-param|main|action}}",
+       "apihelp-main-param-format": "{{doc-apihelp-param|main|format}}",
+       "apihelp-main-param-maxlag": "{{doc-apihelp-param|main|maxlag}}",
+       "apihelp-main-param-smaxage": "{{doc-apihelp-param|main|smaxage}}",
+       "apihelp-main-param-maxage": "{{doc-apihelp-param|main|maxage}}",
+       "apihelp-main-param-assert": "{{doc-apihelp-param|main|assert}}",
+       "apihelp-main-param-requestid": "{{doc-apihelp-param|main|requestid}}",
+       "apihelp-main-param-servedby": "{{doc-apihelp-param|main|servedby}}",
+       "apihelp-main-param-curtimestamp": "{{doc-apihelp-param|main|curtimestamp}}",
+       "apihelp-main-param-origin": "{{doc-apihelp-param|main|origin}}",
+       "apihelp-main-param-uselang": "{{doc-apihelp-param|main|uselang}}",
+
+       "apihelp-format-example-generic": "{{doc-apihelp-example|format|params=* $1 - Format name|paramstart=2|noseealso=1}}",
+       "apihelp-dbg-description": "{{doc-apihelp-description|dbg|seealso=* {{msg-mw|apihelp-dbgfm-description}}}}",
+       "apihelp-dbgfm-description": "{{doc-apihelp-description|dbgfm|seealso=* {{msg-mw|apihelp-dbg-description}}}}",
+       "apihelp-dump-description": "{{doc-apihelp-description|dump|seealso=* {{msg-mw|apihelp-dumpfm-description}}}}",
+       "apihelp-dumpfm-description": "{{doc-apihelp-description|dumpfm|seealso=* {{msg-mw|apihelp-dump-description}}}}",
+       "apihelp-json-description": "{{doc-apihelp-description|json|seealso=* {{msg-mw|apihelp-jsonfm-description}}}}",
+       "apihelp-json-param-callback": "{{doc-apihelp-param|json|callback}}",
+       "apihelp-json-param-utf8": "{{doc-apihelp-param|json|utf8}}",
+       "apihelp-jsonfm-description": "{{doc-apihelp-description|jsonfm|seealso=* {{msg-mw|apihelp-json-description}}}}",
+       "apihelp-none-description": "{{doc-apihelp-description|none}}",
+       "apihelp-php-description": "{{doc-apihelp-description|php|seealso=* {{msg-mw|apihelp-phpfm-description}}}}",
+       "apihelp-phpfm-description": "{{doc-apihelp-description|phpfm|seealso=* {{msg-mw|apihelp-php-description}}}}",
+       "apihelp-rawfm-description": "{{doc-apihelp-description|rawfm|seealso=* {{msg-mw|apihelp-raw-description}}}}",
+       "apihelp-txt-description": "{{doc-apihelp-description|txt|seealso=* {{msg-mw|apihelp-txtfm-description}}}}",
+       "apihelp-txtfm-description": "{{doc-apihelp-description|txtfm|seealso=* {{msg-mw|apihelp-txt-description}}}}",
+       "apihelp-wddx-description": "{{doc-apihelp-description|wddx|seealso=* {{msg-mw|apihelp-wddxfm-description}}}}",
+       "apihelp-wddxfm-description": "{{doc-apihelp-description|wddxfm|seealso=* {{msg-mw|apihelp-wddx-description}}}}",
+       "apihelp-xml-description": "{{doc-apihelp-description|xml|seealso=* {{msg-mw|apihelp-xmlfm-description}}}}",
+       "apihelp-xml-param-xslt": "{{doc-apihelp-param|xml|xslt}}",
+       "apihelp-xml-param-includexmlnamespac": "{{doc-apihelp-param|xml|includexmlnamespac}}",
+       "apihelp-xmlfm-description": "{{doc-apihelp-description|xmlfm|seealso=* {{msg-mw|apihelp-xml-description}}}}",
+       "apihelp-yaml-description": "{{doc-apihelp-description|yaml|seealso=* {{msg-mw|apihelp-yamlfm-description}}}}",
+       "apihelp-yamlfm-description": "{{doc-apihelp-description|yamlfm|seealso=* {{msg-mw|apihelp-yaml-description}}}}",
+
+       "apihelp-help-description": "{{doc-apihelp-description|help}}",
+       "apihelp-help-param-modules": "{{doc-apihelp-param|help|modules}}",
+       "apihelp-help-param-submodules": "{{doc-apihelp-param|help|submodules}}",
+       "apihelp-help-param-recursivesubmodules": "{{doc-apihelp-param|help|recursivesubmodules}}",
+       "apihelp-help-param-helpformat": "{{doc-apihelp-param|help|helpformat}}",
+       "apihelp-help-param-wrap": "{{doc-apihelp-param|help|wrap}}",
+       "apihelp-help-param-toc": "{{doc-apihelp-param|help|toc}}",
+       "apihelp-help-example-main": "{{doc-apihelp-example|help}}",
+       "apihelp-help-example-recursive": "{{doc-apihelp-example|help}}",
+       "apihelp-help-example-help": "{{doc-apihelp-example|help}}",
+       "apihelp-help-example-query": "{{doc-apihelp-example|help}}",
+
+       "api-format-title": "Page title when API output is pretty-printed in HTML.",
+       "api-format-prettyprint-header": "{{technical}} Displayed as a header when API output is pretty-printed in HTML.\n\nParameters:\n* $1 - Format name\n* $2 - Non-pretty-printing module name",
+
+       "api-help-title": "Page title for the auto-generated help output",
+       "api-help-lead": "Text displayed at the top of the API help page",
+       "api-help-main-header": "Text for the header of the main module",
+       "api-help-fallback-description": "{{notranslate}}",
+       "api-help-fallback-parameter": "{{notranslate}}",
+       "api-help-fallback-example": "{{notranslate}}",
+       "api-help-flags": "{{optional}} Label for the API help flags box\n\nParameters:\n* $1 - Number of flags to be displayed",
+       "api-help-flag-deprecated": "Flag displayed for an API module that is deprecated",
+       "api-help-flag-internal": "Flag displayed for an API module that is considered internal or unstable",
+       "api-help-flag-readrights": "Flag displayed for an API module that requires read rights",
+       "api-help-flag-writerights": "Flag displayed for an API module that requires write rights",
+       "api-help-flag-mustbeposted": "Flag displayed for an API module that only accepts POST requests",
+       "api-help-flag-generator": "Flag displayed for an API module that can be used as a generator",
+       "api-help-help-urls": "{{optional}} Label for the API help urls section\n\nParameters:\n* $1 - Number of urls to be displayed",
+       "api-help-parameters": "Label for the API help parameters section\n\nParameters:\n* $1 - Number of parameters to be displayed",
+       "api-help-param-deprecated": "Displayed in the API help for any deprecated parameter",
+       "api-help-param-required": "Displayed in the API help for any required parameter",
+       "api-help-param-list": "Used to display the possible values for a parameter taking a list of values\n\nParameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes any number of values\n* $2 - Comma-separated list of values, possibly formatted using {{msg-mw|api-help-param-list-can-be-empty}}",
+       "api-help-param-list-can-be-empty": "Used to indicate that one of the possible values in the list is the empty string.\n\nParameters:\n* $1 - Number of items in the rest of the list; may be 0\n* $2 - Remainder of the list as a comma-separated string",
+       "api-help-param-limit": "Used to display the maximum value of a limit parameter\n\nParameters:\n* $1 - Maximum value",
+       "api-help-param-limit2": "Used to display the maximum values of a limit parameter\n\nParameters:\n* $1 - Maximum value without the apihighlimits right\n* $2 - Maximum value with the apihighlimits right",
+       "api-help-param-integer-min": "Used to display an integer parameter with a minimum but no maximum value\n\nParameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes any number of values\n* $2 - Minimum value\n* $3 - unused\n\nSee also:\n* {{msg-mw|api-help-param-integer-max}}\n* {{msg-mw|api-help-param-integer-minmax}}",
+       "api-help-param-integer-max": "Used to display an integer parameter with a maximum but no minimum value\n\nParameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes any number of values\n* $2 - unused\n* $3 - Maximum value\n\nSee also:\n* {{msg-mw|api-help-param-integer-min}}\n* {{msg-mw|api-help-param-integer-minmax}}",
+       "api-help-param-integer-minmax": "Used to display an integer parameter with a maximum and minimum values\n\nParameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes any number of values\n* $2 - Minimum value\n* $3 - Maximum value\n\nSee also:\n* {{msg-mw|api-help-param-integer-min}}\n* {{msg-mw|api-help-param-integer-max}}",
+       "api-help-param-upload": "{{technical}} Used to indicate that an 'upload'-type parameter must be posted as a file upload using multipart/form-data",
+       "api-help-param-multi-separate": "Used to indicate how to separate multiple values. Not used with {{msg-mw|api-help-param-list}}.",
+       "api-help-param-multi-max": "Used to indicate the maximum number of values accepted for a multi-valued parameter.\n\nParameters:\n* $1 - Maximum value without the apihighlimits right\n* $2 - Maximum value with the apihighlimits right",
+       "api-help-param-default": "Used to display the default value for an API parameter\n\nParameters:\n* $1 - Default value\n\nSee also:\n* {{msg-mw|api-help-param-default-empty}}",
+       "api-help-param-default-empty": "Used to display the default value for an API parameter when that default is an empty value\n\nSee also:\n* {{msg-mw|api-help-param-default}}",
+       "api-help-param-token": "{{doc-apihelp-param|description=any 'token' parameter|paramstart=3|params=\n* $1 - Token type|noseealso=1}}",
+       "api-help-param-no-description": "Displayed on API parameters that lack any description",
+       "api-help-examples": "Label for the API help examples section\n\nParameters:\n* $1 - Number of examples to be displayed",
+       "api-help-permissions": "Label for the \"permissions\" section in the main module's help output.\n\nParameters:\n* $1 - Number of permissions displayed",
+       "api-help-permissions-granted-to": "Used to introduce the list of groups each permission is assigned to.\n\nParameters:\n* $1 - Number of groups\n* $2 - List of group names, comma-separated",
+       "api-help-right-apihighlimits": "{{technical}}{{doc-right|apihighlimits|prefix=api-help}}\nThis message is used instead of {{msg-mw|right-apihighlimits}} in the API help to display the actual limits.\n\nParameters:\n* $1 - Limit for slow queries\n* $2 - Limit for fast queries",
+
+       "api-credits-header": "Header for the API credits section in the API help output",
+       "api-credits": "API credits text, displayed in the API help output"
+}
index 2f898b7..755a851 100644 (file)
@@ -129,6 +129,7 @@ class ORMTable extends DBAccessBase implements IORMTable {
         * Gets the db field prefix.
         *
         * @since 1.20
+        * @deprecated since 1.25, use the $this->fieldPrefix property instead
         *
         * @return string
         */
@@ -770,7 +771,7 @@ class ORMTable extends DBAccessBase implements IORMTable {
         * @return string
         */
        public function getPrefixedField( $field ) {
-               return $this->getFieldPrefix() . $field;
+               return $this->fieldPrefix . $field;
        }
 
        /**
@@ -796,7 +797,7 @@ class ORMTable extends DBAccessBase implements IORMTable {
         * @return string
         */
        public function unprefixFieldName( $fieldName ) {
-               return substr( $fieldName, strlen( $this->getFieldPrefix() ) );
+               return substr( $fieldName, strlen( $this->fieldPrefix ) );
        }
 
        /**
index 21fcb9d..dedc3c2 100644 (file)
        "config-install-stats": "統計情報の初期化",
        "config-install-keys": "秘密鍵の生成",
        "config-insecure-keys": "<strong>警告:</strong> インストール中に生成されたセキュアキー ($1) は完璧に安全ではありません。手動で変更することを検討してください。",
+       "config-install-updates": "不要な更新を実行するのを防ぐ",
        "config-install-sysop": "管理者のアカウントの作成",
        "config-install-subscribe-fail": "mediawiki-announce を購読できませんでした: $1",
        "config-install-subscribe-notpossible": "cURL がインストールされていないため、<code>allow_url_fopen</code> を利用できません。",
index cae6aa1..081f50f 100644 (file)
        "config-suhosin-max-value-length": "수호신(Suhosin)이 설치되고 $1 바이트로 GET 매개 변수 <code>length</code>를 제한하고 있습니다.\n미디어위키의 ResourceLoader 구성 요소는 이 제한을 회피하지만 성능이 저하됩니다.\n가능하면 <code>php.ini</code>의 <code>suhosin.get.max_value_length</code>를 1024 이상으로 설정하고 <code>LocalSettings.php</code>의 <code>$wgResourceLoaderMaxQueryLength</code>를 같은 값으로 설정해야 합니다.",
        "config-db-type": "데이터베이스 종류:",
        "config-db-host": "데이터베이스 호스트:",
-       "config-db-host-help": "ë\8d°ì\9d´í\84°ë² ì\9d´ì\8a¤ ì\84\9cë²\84ê°\80 ë\8b¤ë¥¸ ì\84\9cë²\84ì\97\90 ì\9e\88ì\9c¼ë©´ ì\97¬ê¸°ì\97\90 í\98¸ì\8a¤í\8a¸ ì\9d´ë¦\84ì\9d´ë\82\98 IP ì£¼ì\86\8c를 ì\9e\85ë ¥í\95\98ì\84¸ì\9a\94.\n\nê³µì\9c í\95\98ë\8a\94 ì\9b¹ í\98¸ì\8a¤í\8c\85ì\9d\84 ì\82¬ì\9a©í\95\98ê³  ì\9e\88ì\9c¼ë©´ í\98¸ì\8a¤í\8c\85 ì \9cê³µ ì\97\85ì²´ë\8a\94 ì \95í\99\95í\95\9c í\98¸ì\8a¤í\8a¸ ì\9d´ë¦\84ì\9d\84 ì\84¤ëª\85í\95\98ê³  ì\9e\88ì\9d\84 ê²\83ì\9e\85ë\8b\88ë\8b¤.\n\nì\9c\88ë\8f\84 ì\84\9cë²\84ì\97\90 ì\84¤ì¹\98í\95\98ê³  MySQLì\9d\84 ì\82¬ì\9a©í\95\98ë©´ \"localhost\"ê°\80 í\95´ë\8b¹ 서버 이름으로는 작동하지 않을 수 있습니다. 그렇게 된다면 로컬 IP 주소로 \"127.0.0.1\"을 시도하세요.\n\nPostgreSQL을 사용하면 유닉스 소켓을 통해 연결되도록 입력란을 비워두세요.",
+       "config-db-host-help": "ë\8d°ì\9d´í\84°ë² ì\9d´ì\8a¤ ì\84\9cë²\84ê°\80 ë\8b¤ë¥¸ ì\84\9cë²\84ì\97\90 ì\9e\88ì\9c¼ë©´ ì\97¬ê¸°ì\97\90 í\98¸ì\8a¤í\8a¸ ì\9d´ë¦\84ì\9d´ë\82\98 IP ì£¼ì\86\8c를 ì\9e\85ë ¥í\95\98ì\84¸ì\9a\94.\n\nê³µì\9c í\95\98ë\8a\94 ì\9b¹ í\98¸ì\8a¤í\8c\85ì\9d\84 ì\82¬ì\9a©í\95\98ê³  ì\9e\88ì\9c¼ë©´ í\98¸ì\8a¤í\8c\85 ì \9cê³µ ì\97\85ì²´ë\8a\94 ì\98¬ë°\94른 í\98¸ì\8a¤í\8a¸ ì\9d´ë¦\84ì\9d\84 ì\84¤ëª\85í\95\98ê³  ì\9e\88ì\9d\84 ê²\83ì\9e\85ë\8b\88ë\8b¤.\n\nWindows ì\84\9cë²\84ì\97\90 ì\84¤ì¹\98í\95\98ê³  MySQLì\9d\84 ì\82¬ì\9a©í\95\98ë©´ \"localhost\"ê°\80 서버 이름으로는 작동하지 않을 수 있습니다. 그렇게 된다면 로컬 IP 주소로 \"127.0.0.1\"을 시도하세요.\n\nPostgreSQL을 사용하면 유닉스 소켓을 통해 연결되도록 입력란을 비워두세요.",
        "config-db-host-oracle": "데이터베이스 TNS:",
        "config-db-host-oracle-help": "올바른 [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm 로컬 연결 이름]을 입력하세요. tnsnames.ora 파일이 이 설치 위치에서 참조할 수 있는 곳에 있어야 합니다.<br />10g 이후의 클라이언트 라이브러리를 사용하는 경우 [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm 쉬운 연결] 네이밍 메서드도 사용할 수 있습니다.",
        "config-db-wiki-settings": "이 위키 식별",
        "config-db-name": "데이터베이스 이름:",
        "config-db-name-help": "위키를 식별하기 위한 이름을 선택하세요.\n공백이 없어야 합니다.\n\n공유하는 웹 호스팅 사용하면 호스팅 제공 업체가 특정 데이터베이스 이름을 제공하거나 제어판에서 데이터베이스를 만들 수 있습니다.",
        "config-db-name-oracle": "데이터베이스 스키마:",
-       "config-db-account-oracle-warn": "데이터베이스 백엔드로 오라클을 설치하기 위해 지원하는 세 가지 시나리오가 있습니다:\n\n설치 과정의 일부로 데이터베이스 계정을 만들려면 설치를 위해 데이터베이스 계정으로 SYSDBA 역할을 가진 계정을 제공하고 웹 접근 계정에 대해 원하는 자격 증명을 지정하세요, 그렇지 않으면 수동으로 웹 접근 계정을 만들 수 있으며 (스키마 개체를 만들 권한이 필요한 경우) 또는 생성 권한으 가진 계정과 웹 접근이 제한된 계정의 두 가지 다른 계정을 제공할 수도 있습니다\n\n필요한 권한을 가진 계정을 만드는 스크립트는 이 설치 위치의 \"maintenance/oracle/\" 디렉터리에서 찾을 수 있습니다. 제한된 계정을 사용하면 기본 계정의 모든 유지 관리 기능이 비활성화된다는 점에 유의하십시오.",
+       "config-db-account-oracle-warn": "데이터베이스 백엔드로 Oracle을 설치하기 위해 지원하는 세 가지 시나리오가 있습니다:\n\n설치 과정의 일부로 데이터베이스 계정을 만들려면 설치를 위해 데이터베이스 계정으로 SYSDBA 역할을 가진 계정을 제공하고 웹 접근 계정에 대해 원하는 자격 증명을 지정하세요, 그렇지 않으면 수동으로 웹 접근 계정을 만들 수 있으며 (스키마 개체를 만들 권한이 필요한 경우) 또는 생성 권한을 가진 계정과 웹 접근이 제한된 계정의 두 가지 다른 계정을 제공할 수도 있습니다\n\n필요한 권한을 가진 계정을 만드는 스크립트는 이 설치 위치의 \"maintenance/oracle/\" 디렉터리에서 찾을 수 있습니다. 제한된 계정을 사용하면 기본 계정의 모든 유지 관리 기능이 비활성화된다는 점에 유의하십시오.",
        "config-db-install-account": "설치를 위한 사용자 계정",
        "config-db-username": "데이터베이스 사용자 이름:",
        "config-db-password": "데이터베이스 비밀번호:",
        "config-oracle-temp-ts": "임시 테이블공간:",
        "config-type-mysql": "MySQL (또는 호환되는 데이터베이스 시스템)",
        "config-type-oracle": "Oracle",
-       "config-type-mssql": "마이크로소프트 SQL 서버",
+       "config-type-mssql": "Microsoft SQL 서버",
        "config-support-info": "미디어위키는 다음의 데이터베이스 시스템을 지원합니다:\n\n$1\n\n데이터베이스 시스템이 표시되지 않을 때 아래에 나열된 다음 지원을 활성화하려면 위의 링크된 지시에 따라 설치해볼 수 있습니다.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL]은 미디어위키의 기본 대상이며 가장 잘 지원됩니다. 미디어위키는 또한 MySQL와 호환되는 [{{int:version-db-mariadb-url}} MariaDB]와 [{{int:version-db-percona-url}} Percona 서버]에서도 작동합니다. \n\n([http://www.php.net/manual/en/mysql.installation.php MySQL을 지원하여 PHP를 컴파일하는 방법])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL]은 MySQL의 대안으로서 인기 있는 오픈 소스 데이터베이스 시스템입니다. ([http://www.php.net/manual/en/pgsql.installation.php PostgreSQL을 지원하여 PHP를 컴파일하는 방법]) 몇 가지 해결하지 못한 사소한 버그가 있을 수 있으며, 이를 제작 환경에서 사용하지 않는 것이 좋습니다.",
-       "config-dbsupport-sqlite": "*  [{{int:version-db-sqlite-url}} SQLite]는 매우 잘 지원되고 가벼운 데이터베이스 시스템입니다. ([http://www.php.net/manual/en/pdo.installation.php SQLite를 지원하여 PHP를 컴파일하는 방법], PDO 사용)",
-       "config-dbsupport-oracle": "*  [{{int:version-db-oracle-url}} 오라클]은 상용 엔터프라이스 데이터베이스입니다. ([http://www.php.net/manual/en/oci8.installation.php OCI8을 지원하여 PHP를 컴파일하는 방법])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} 마이크로소프트 SQL 서버]는 윈도용 상용 기업 데이터베이스입니다.([http://www.php.net/manual/en/sqlsrv.installation.php SQLSRV 지원으로 PHP를 컴파일하는 방법])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL]은 미디어위키의 기본 대상이며 가장 잘 지원됩니다. 미디어위키는 또한 MySQL와 호환되는 [{{int:version-db-mariadb-url}} MariaDB]와 [{{int:version-db-percona-url}} Percona 서버]에서도 작동합니다. ([http://www.php.net/manual/en/mysql.installation.php MySQL 지원으로 PHP를 컴파일하는 방법])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL]은 MySQL의 대안으로서 인기 있는 오픈 소스 데이터베이스 시스템입니다. ([http://www.php.net/manual/en/pgsql.installation.php PostgreSQL 지원으로 PHP를 컴파일하는 방법]) 몇 가지 해결하지 못한 사소한 버그가 있을 수 있으며, 이를 제작 환경에서 사용하지 않는 것이 좋습니다.",
+       "config-dbsupport-sqlite": "*  [{{int:version-db-sqlite-url}} SQLite]는 매우 잘 지원되고 가벼운 데이터베이스 시스템입니다. ([http://www.php.net/manual/en/pdo.installation.php SQLite 지원으로 PHP를 컴파일하는 방법], PDO 사용)",
+       "config-dbsupport-oracle": "*  [{{int:version-db-oracle-url}} Oracle]은 상용 기업 데이터베이스입니다. ([http://www.php.net/manual/en/oci8.installation.php OCI8 지원으로 PHP를 컴파일하는 방법])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL 서버]는 Windows용 상용 기업 데이터베이스입니다. ([http://www.php.net/manual/en/sqlsrv.installation.php SQLSRV 지원으로 PHP를 컴파일하는 방법])",
        "config-header-mysql": "MySQL 설정",
        "config-header-postgres": "PostgreSQL 설정",
        "config-header-sqlite": "SQLite 설정",
        "config-header-oracle": "Oracle 설정",
-       "config-header-mssql": "마이크로소프트 SQL 서버 설정",
+       "config-header-mssql": "Microsoft SQL 서버 설정",
        "config-invalid-db-type": "잘못된 데이터베이스 종류",
        "config-missing-db-name": "\"{{int:config-db-name}}\"에 대한 값을 입력해야 합니다.",
        "config-missing-db-host": "\"{{int:config-db-host}}\"에 대한 값을 입력해야 합니다.",
        "config-missing-db-server-oracle": "\"{{int:config-db-host-oracle}}\"에 대한 값을 입력해야 합니다.",
-       "config-invalid-db-server-oracle": "\"$1\" 데이터베이스 TNS가 잘못됐습니다.\n\"TNS Name\"이나 \"Easy Connect\" 문자열 중 하나를 사용하세요 ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm 오라클 네이밍 메서드])",
+       "config-invalid-db-server-oracle": "\"$1\" 데이터베이스 TNS가 잘못됐습니다.\n\"TNS Name\"이나 \"Easy Connect\" 문자열 중 하나를 사용하세요 ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Oracle 네이밍 메서드]).",
        "config-invalid-db-name": "\"$1\" 데이터베이스 이름이 잘못되었습니다.\nASCII 글자 (a-z, A-Z), 숫자 (0-9), 밑줄 (_)과 하이픈 (-)만 사용하세요.",
        "config-invalid-db-prefix": "\"$1\" 데이터베이스 접두어가 잘못됐습니다.\nASCII 글자 (a-z, A-Z), 숫자 (0-9), 밑줄 (_)과 하이픈 (-)만 사용하세요.",
        "config-connection-error": "$1.\n\n호스트, 계정 이름과 비밀번호를 확인하고 다시 시도하세요.",
        "config-db-sys-create-oracle": "설치 프로그램은 새 계정을 만들기 위한 SYSDBA 계정만을 지원합니다.",
        "config-db-sys-user-exists-oracle": "\"$1\" 사용자 계정이 이미 존재합니다. SYSDBA는 새 계정을 만드는 데에만 사용할 수 있습니다!",
        "config-postgres-old": "PostgreSQL $1 이상이 필요하나 $2(이)가 있습니다.",
-       "config-mssql-old": "마이크로소프트 SQL 서버 $1 이상의 버전이 필요합니다. 현재 버전은 $2입니다.",
+       "config-mssql-old": "Microsoft SQL 서버 $1 이상의 버전이 필요합니다. 현재 버전은 $2입니다.",
        "config-sqlite-name-help": "위키를 식별하기 위한 이름을 선택하세요.\n공백이나 하이픈을 사용하지 마십시오.\nSQLite 데이터 파일 이름에 사용됩니다.",
        "config-sqlite-parent-unwritable-group": "<code><nowiki>$1</nowiki></code> 데이터 디렉토리를 만들 수 없으며, 이는 웹 서버는 상위 디렉토리인 <code><nowiki>$2</nowiki></code>에 쓸 수 없기 때문입니다.\n\n설치 프로그램은 웹 서버로 실행 중인 사용자를 지정할 수 없습니다.\n계속하려면 웹 서버가 쓸 수 있는 <code><nowiki>$3</nowiki></code> 디렉토리를 만드세요.\n유닉스/리눅스 시스템에서의 수행:\n\n<pre>cd $2\nmkdir $3\nchgrp $4 $3\nchmod g+w $3</pre>",
        "config-sqlite-parent-unwritable-nogroup": "<code><nowiki>$1</nowiki></code> 데이터 디렉토리를 만들 수 없으며, 이는 웹 서버가 상위 디렉토리인 <code><nowiki>$2</nowiki></code>에 쓸 수 없기 때문입니다.\n\n설치 프로그램은 웹 서버로 실행 중인 사용자를 지정할 수 없습니다.\n계속하려면 웹 서버(와 그 외 서버!)가 전역으로 쓸 수 있는 <code><nowiki>$3</nowiki></code> 디렉토리를 만드세요.\n유닉스/리눅스 시스템에서의 수행:\n\n<pre>cd $2\nmkdir $3\nchmod a+w $3</pre>",
index 9a6b787..febd119 100644 (file)
@@ -156,6 +156,7 @@ class SpecialPageFactory {
                'Booksources' => 'SpecialBookSources',
 
                // Unlisted / redirects
+               'ApiHelp' => 'SpecialApiHelp',
                'Blankpage' => 'SpecialBlankpage',
                'Diff' => 'SpecialDiff',
                'Emailuser' => 'SpecialEmailUser',
diff --git a/includes/specials/SpecialApiHelp.php b/includes/specials/SpecialApiHelp.php
new file mode 100644 (file)
index 0000000..b43911f
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Implements Special:ApiHelp
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * Special page to redirect to API help pages, for situations where linking to
+ * the api.php endpoint is not wanted.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialApiHelp extends UnlistedSpecialPage {
+       public function __construct() {
+               parent::__construct( 'ApiHelp' );
+       }
+
+       public function execute( $par ) {
+               if ( empty( $par ) ) {
+                       $par = 'main';
+               }
+
+               // These come from transclusions
+               $request = $this->getRequest();
+               $options = array(
+                       'action' => 'help',
+                       'nolead' => true,
+                       'submodules' => $request->getCheck( 'submodules' ),
+                       'recursivesubmodules' => $request->getCheck( 'recursivesubmodules' ),
+                       'title' => $request->getVal( 'title', $this->getPageTitle( '$1' )->getPrefixedText() ),
+               );
+
+               // These are for linking from wikitext, since url parameters are a pain
+               // to do.
+               while ( true ) {
+                       if ( substr( $par, 0, 4 ) === 'sub/' ) {
+                               $par = substr( $par, 4 );
+                               $options['submodules'] = 1;
+                               continue;
+                       }
+
+                       if ( substr( $par, 0, 5 ) === 'rsub/' ) {
+                               $par = substr( $par, 5 );
+                               $options['recursivesubmodules'] = 1;
+                               continue;
+                       }
+
+                       $moduleName = $par;
+                       break;
+               }
+
+               if ( !$this->including() ) {
+                       unset( $options['nolead'], $options['title'] );
+                       $options['modules'] = $moduleName;
+                       $link = wfAppendQuery( wfExpandUrl( wfScript( 'api' ), PROTO_CURRENT ), $options );
+                       $this->getOutput()->redirect( $link );
+                       return;
+               }
+
+               $main = new ApiMain( $this->getContext(), false );
+               try {
+                       $module = $main->getModuleFromPath( $moduleName );
+               } catch ( UsageException $ex ) {
+                       $this->getOutput()->addHTML( Html::rawElement( 'span', array( 'class' => 'error' ),
+                               $this->msg( 'apihelp-no-such-module', $moduleName )->inContentLanguage()->parse()
+                       ) );
+                       return;
+               }
+
+               ApiHelp::getHelp( $this->getContext(), $module, $options );
+       }
+
+       public function isIncludable() {
+               return true;
+       }
+}
index 5631c3a..107413e 100644 (file)
@@ -485,6 +485,8 @@ class SpecialContributions extends IncludableSpecialPage {
                        $filterSelection = Html::rawElement( 'td', array( 'colspan' => 2 ), '' );
                }
 
+               $this->getOutput()->addModules( 'mediawiki.userSuggest' );
+
                $labelNewbies = Xml::radioLabel(
                        $this->msg( 'sp-contributions-newbies' )->text(),
                        'contribs',
@@ -505,9 +507,15 @@ class SpecialContributions extends IncludableSpecialPage {
                        'target',
                        $this->opts['target'],
                        'text',
-                       array( 'size' => '40', 'required' => '', 'class' => 'mw-input mw-ui-input-inline' ) +
-                               ( $this->opts['target'] ? array() : array( 'autofocus' )
-                               )
+                       array(
+                               'size' => '40',
+                               'required' => '',
+                               'class' => array(
+                                       'mw-input',
+                                       'mw-ui-input-inline',
+                                       'mw-autocomplete-user', // used by mediawiki.userSuggest
+                               ),
+                       ) + ( $this->opts['target'] ? array() : array( 'autofocus' ) )
                );
                $targetSelection = Html::rawElement(
                        'td',
index 68f2c46..1b665f6 100644 (file)
@@ -533,6 +533,8 @@ class DeletedContributionsPage extends SpecialPage {
                        $f .= "\t" . Html::hidden( $name, $value ) . "\n";
                }
 
+               $this->getOutput()->addModules( 'mediawiki.userSuggest' );
+
                $f .= Xml::openElement( 'fieldset' );
                $f .= Xml::element( 'legend', array(), $this->msg( 'sp-contributions-search' )->text() );
                $f .= Xml::tags(
@@ -546,7 +548,10 @@ class DeletedContributionsPage extends SpecialPage {
                        'text',
                        array(
                                'size' => '20',
-                               'required' => ''
+                               'required' => '',
+                               'class' => array(
+                                       'mw-autocomplete-user', // used by mediawiki.userSuggest
+                               ),
                        ) + ( $options['target'] ? array() : array( 'autofocus' ) )
                ) . ' ';
                $f .= Html::namespaceSelector(
index 2a97abc..bf17a20 100644 (file)
@@ -519,6 +519,7 @@ class ImageListPager extends TablePager {
                        );
                }
 
+               $this->getOutput()->addModules( 'mediawiki.userSuggest' );
                $fields['user'] = array(
                        'type' => 'text',
                        'name' => 'user',
@@ -527,6 +528,7 @@ class ImageListPager extends TablePager {
                        'default' => $this->mUserName,
                        'size' => '40',
                        'maxlength' => '255',
+                       'cssclass' => 'mw-autocomplete-user', // used by mediawiki.userSuggest
                );
 
                $fields['ilshowall'] = array(
index 0b70bb7..3a74e7a 100644 (file)
@@ -221,6 +221,8 @@ class SpecialNewpages extends IncludableSpecialPage {
                        list( $tagFilterLabel, $tagFilterSelector ) = $tagFilter;
                }
 
+               $this->getOutput()->addModules( 'mediawiki.userSuggest' );
+
                $form = Xml::openElement( 'form', array( 'action' => wfScript() ) ) .
                        Html::hidden( 'title', $this->getPageTitle()->getPrefixedDBkey() ) .
                        Xml::fieldset( $this->msg( 'newpages' )->text() ) .
@@ -262,7 +264,10 @@ class SpecialNewpages extends IncludableSpecialPage {
                                        Xml::label( $this->msg( 'newpages-username' )->text(), 'mw-np-username' ) .
                                        '</td>
                                <td class="mw-input">' .
-                                       Xml::input( 'username', 30, $userText, array( 'id' => 'mw-np-username' ) ) .
+                                       Xml::input( 'username', 30, $userText, array(
+                                               'id' => 'mw-np-username',
+                                               'class' => 'mw-autocomplete-user', // used by mediawiki.userSuggest
+                                       ) ) .
                                        '</td>
                        </tr>' .
                        '<tr> <td></td>
index d435615..4eea01c 100644 (file)
@@ -258,6 +258,7 @@ class UsercreateTemplate extends BaseTemplate {
                                        $this->getMsg( $this->data['loggedin'] ? 'createacct-another-submit' : 'createacct-submit' ),
                                        $attrs = array(
                                                'id' => 'wpCreateaccount',
+                                               'name' => 'wpCreateaccount',
                                                'tabindex' => $tabIndex++
                                        ),
                                        array(
index 99fe218..2a9badf 100644 (file)
@@ -150,6 +150,7 @@ class UserloginTemplate extends BaseTemplate {
                                <?php
                                $attrs = array(
                                        'id' => 'wpLoginAttempt',
+                                       'name' => 'wpLoginAttempt',
                                        'tabindex' => '6',
                                );
                                $modifiers = array(
index aba2d0b..8a3c5a3 100644 (file)
        "wlheader-enotif": "الإخطار بالبريد الإلكتروني مُفعّل.",
        "wlheader-showupdated": "الصفحات التي تم تحريرها بعد مطالعتك إياها آخر مرة عناوينها بالخط '''الغليظ'''",
        "wlnote": "بالأسفل {{PLURAL:$1|لا توجد تغييرات|التغيير الأخير|آخر تغييرين|آخر '''$1''' تغييرات|آخر '''$1''' تغييرا|آخر '''$1''' تغيير}} في {{PLURAL:$2||'''الساعة''' الماضية|'''الساعتين''' الماضيتين|ال'''$2''' ساعات الماضية|ال'''$2''' ساعة الماضية}} وفقاً ل$3، $4.",
-       "wlshowlast": "عرض آخر $1 ساعات $2 أيام",
+       "wlshowlast": "عرض آخر $1 ساعات $2 يوما",
        "watchlist-options": "خيارات قائمة المراقبة",
        "watching": "يراقب...",
        "unwatching": "إزالة المراقبة...",
index 6be037d..cade0c3 100644 (file)
        "wantedfiles": "আবশ্যিক ফাইলগুলো",
        "wantedfiletext-cat": "নিচের ফাইলগুলো ব্যবহৃত হচ্ছে কিন্তু এগুলো অপসারিত হয়েছে। অন্যান্য রিপোজিটরী থেকে ব্যবহৃত ফাইলগুলো এভাবে প্রদর্শিত হতে পারে। এই ধরনের কোন ফাইল খুজে পেলে <del>অপসারণ করুন</del>। এছাড়া অপসারিত হয়েছে এমন ছবির সংযোগ রয়েছে এমন পাতাসমূহের লিংক পাওয়া যাবে এখানে [[:$1]]।",
        "wantedfiletext-nocat": "নিচের ফাইলগুলো ব্যবহৃত হচ্ছে কিন্তু এগুলো অপসারিত হয়েছে। অন্যান্য রিপোজিটরী থেকে ব্যবহৃত ফাইলগুলো এভাবে প্রদর্শিত হতে পারে। এই ধরনের ভূলগুলো শিঘ্রই <del>অপসারিত হবে</del>।",
+       "wantedfiletext-nocat-noforeign": "নিম্নলিখিত ফাইলসমূহ ব্যবহৃত হয়েছে কিন্তু এর অস্তিত্ব নেই।",
        "wantedtemplates": "আবশ্যিক টেম্পলেটগুলো",
        "mostlinked": "যেসব পাতার প্রতি সবচেয়ে বেশি সংযোগ আছে",
        "mostlinkedcategories": "যেসব বিষয়শ্রেণীর প্রতি সবচেয়ে বেশি সংযোগ আছে",
        "mediastatistics-header-audio": "অডিও",
        "mediastatistics-header-video": "ভিডিও",
        "mediastatistics-header-office": "অফিস",
+       "json-error-unknown": "JSON-এ একটি সমস্যা রয়েছে। ত্রুটি: $1",
        "json-error-syntax": "সিনট্যাক্স ত্রুটি"
 }
index cfb0e61..06edf40 100644 (file)
        "prefs-tabs-navigation-hint": "Consell: Podeu utilitzar les tecles de cursor de dreta i esquerra per a navegar entre les pestanyes.",
        "email-address-validity-valid": "L'adreça de correu electrònic sembla vàlida",
        "email-address-validity-invalid": "Escriviu una adreça vàlida de correu electrònic",
-       "userrights": "Gestió dels permisos d'usuari",
+       "userrights": "Gestió dels permisos dusuari",
        "userrights-lookup-user": "Gestiona els grups d'usuari",
        "userrights-user-editname": "Introduïu un nom d'usuari:",
        "editusergroup": "Edita els grups d'usuaris",
index c366b2a..c4674cc 100644 (file)
        "talkpage": "討論茲頁",
        "talkpagelinktext": "討論",
        "specialpage": "特殊頁",
-       "personaltools": "å\80\8b人å\85¶å®¶ç§\81",
+       "personaltools": "å\80\8b人å\85¶å\82¢ç§\81è\8a±",
        "articlepage": "覷蜀覷內容頁面",
        "talk": "討論",
        "views": "覷蜀覷",
-       "toolbox": "家ç§\81",
+       "toolbox": "å\82¢ç§\81è\8a±",
        "userpage": "覷蜀覷用戶頁面",
        "projectpage": "看工程頁",
        "imagepage": "覷蜀覷文件頁面",
index 481a64e..c3b4416 100644 (file)
        "resetpass-submit-loggedin": "Skift adgangskode",
        "resetpass-submit-cancel": "Annuller",
        "resetpass-wrong-oldpass": "Ugyldig midlertidig eller gældende adgangskode.\nDu har muligvis allerede skiftet din adgangskode eller anmodet om en ny midlertidig kode.",
-       "resetpass-recycled": "Vær venlig at ændre dit kodeord til et andet end dit nuværende kodeord.",
-       "resetpass-temp-emailed": "Du loggede på med en midlertidig kode tilsendt på e-mail.\nFor at afslutte indlogning, skal du oprette et nyt kodeord:",
+       "resetpass-recycled": "Vær venlig at ændre din adgangskode til noget andet end din nuværende adgangskode.",
+       "resetpass-temp-emailed": "Du loggede på med en midlertidig kode tilsendt på e-mail.\nFor at afslutte indlogning, skal du oprette en nyt adgangskode:",
        "resetpass-temp-password": "Midlertidig adgangskode",
        "resetpass-abort-generic": "Ændring af adgangskode er blevet afbrudt af en udvidelse",
-       "resetpass-expired": "Dit kodeord er udløbet. Vær venlig at ændre det til et nyt.",
+       "resetpass-expired": "Din adgangskode er udløbet. Angiv en ny adgangskode for at logge på.",
        "resetpass-expired-soft": "Din adgangskode er udløbet og skal ændres. Vær venlig at ændre den nu, eller tryk \"{{int:resetpass-submit-cancel}}\" for at ændre den senere.",
        "resetpass-validity-soft": "Din adgangskode er ikke gyldig:  $1 \n\nVær venlig at ændre den nu, eller tryk \"{{int:resetpass-submit-cancel}}\" for at ændre den senere.",
        "passwordreset": "Nulstil adgangskode",
index 54ba6b0..fae849e 100644 (file)
        "others": "anderen",
        "siteusers": "{{SITENAME}}-{{PLURAL:$2|Benutzer}} $1",
        "anonusers": "{{PLURAL:$2|unangemeldetem|unangemeldeten}} {{SITENAME}}-{{PLURAL:$2|Benutzer|Benutzern}} $1",
-       "creditspage": "Seiteninformationen",
-       "nocredits": "Für diese Seite sind keine Informationen vorhanden.",
+       "creditspage": "Seitenzuschreibung",
+       "nocredits": "Für diese Seite sind keine Zuschreibungen vorhanden.",
        "spamprotectiontitle": "Spamschutzfilter",
        "spamprotectiontext": "Der Text, die du speichern willst, wurde vom Spamschutzfilter blockiert.\nDas liegt wahrscheinlich an einem Link auf eine externe Seite.",
        "spamprotectionmatch": "'''Der folgende Text wurde vom Spamfilter gefunden: ''$1'''''",
index 250d9fb..ca5d41c 100644 (file)
        "qbfind": "Bıvêne",
        "qbbrowse": "Çım ra viyarne",
        "qbedit": "Bıvurne",
-       "qbpageoptions": "Ena pele",
+       "qbpageoptions": "Ena perer",
        "qbmyoptions": "Pelê mı",
        "faq": "PZP (Persê ke zehf persiyenê)",
        "faqpage": "Project: PZP",
        "edit-local": "Şınasnayışê lokali bıvurne",
        "create": "Vıraze",
        "create-local": "Şınasnayışê lokali cı ke",
-       "editthispage": "Ena pele bıvurne",
+       "editthispage": "Perer bıvurne",
        "create-this-page": "Na pele bınuse",
        "delete": "Bestere",
-       "deletethispage": "Ena pele bestere",
+       "deletethispage": "Perer bestere",
        "undeletethispage": "Na perer mebesterne",
        "undelete_short": "{{PLURAL:$1|Yew vurnayışi|$1 Vurnayışan}} mestere",
        "viewdeleted_short": "{{PLURAL:$1|Yew vurnayışo esterıte|$1 Vurnayışanê esterıtan}} bımocne",
        "protect": "Bışevekne",
        "protect_change": "bıvurne",
-       "protectthispage": "Ena pele bıpawe",
+       "protectthispage": "Perer bıpawe",
        "unprotect": "Starkerdışi bıvurne",
        "unprotectthispage": "Starkerdışe ena peler bıvurne",
        "newpage": "Pela newiye",
-       "talkpage": "Ena pele sero werêne",
+       "talkpage": "Perer sero werêne",
        "talkpagelinktext": "Vatenayış",
        "specialpage": "Pela xısusiye",
        "personaltools": "Hacetê şexsiy",
        "action-createtalk": "pelanê werênayışi bıvıraze",
        "action-createaccount": "hesabê nê karberi bıvıraze",
        "action-minoredit": "nê vurnayışi be qıckek işaret ke",
-       "action-move": "ena pele bere",
+       "action-move": "Perer bere",
        "action-move-subpages": "ena pele, u pelanê daê bınênan bere",
        "action-move-rootuserpages": "pelanê karberiyê bıngeyan bere",
        "action-movefile": "ena dosya bere",
        "action-reupload-shared": "dosyayê ki ho embarê medyayî de esto ser ay binusne",
        "action-upload_by_url": "Ena dosya yew URL ra bar bike",
        "action-writeapi": "ser nuşte API gure bike",
-       "action-delete": "ena pele bestere",
+       "action-delete": "Perer bestere",
        "action-deleterevision": "nê çımraviyarnayışi bestere",
        "action-deletedhistory": "tarixê ena pel ki estereyî biya, ey bivine",
        "action-browsearchive": "pelanê esterıteyan bıgeyre",
-       "action-undelete": "ena pele reyna biyere",
+       "action-undelete": "Perer reyna biyere",
        "action-suppressrevision": "revizyone ki nimnaye biye reyna bivîne u restore bike",
        "action-suppressionlog": "enê qeydê xısusi bıvêne",
        "action-block": "enê karberi vurnayışi ra bıreyne",
        "newpages-username": "Nameyê karberi:",
        "ancientpages": "Wesiqeyê ke vurnayışê ciyê peyeni tewr kehani",
        "move": "Bere",
-       "movethispage": "Ena pele bere",
+       "movethispage": "Perer bere",
        "unusedimagestext": "Enê dosyey estê, feqet zerrey yew pele de wedardey niyê.\nXo vira mekerê ke, sıteyê webiê bini şenê direkt ebe URLi yew dosya ra gırê bê, u wına şenê verba gurênayışo feal de tiya hewna lista bê.",
        "unusedcategoriestext": "Kategoriyê ke cêr derê, nê bıbê zi, terefê qet madeyan ya zi kategoriyan ra nêgureniyenê.",
        "notargettitle": "Hedef çini yo",
        "special-categories-sort-count": "goreyê çendi rêz ker.",
        "special-categories-sort-abc": "alfabetik rêz ker",
        "deletedcontributions": "İştiraqê karberan de besternayına",
-       "deletedcontributions-title": "Îştirakê karberî wederna",
+       "deletedcontributions-title": "İştıraqé karberan de besterneyınan",
        "sp-deletedcontributions-contribs": "iştıraqi",
        "linksearch": "Gıreyê teberi cı geyrê",
        "linksearch-pat": "bıgêr motif:",
index 76bbd4c..7935e31 100644 (file)
        "pager-older-n": "{{PLURAL:$1|older 1|older $1}}",
        "suppress": "Oversight",
        "querypage-disabled": "This special page is disabled for performance reasons.",
+       "apihelp": "API help",
+       "apihelp-summary": "",
+       "apihelp-no-such-module": "Module \"$1\" not found.",
+       "apihelp-link": "[[Special:ApiHelp/$1|$2]]",
        "booksources": "Book sources",
        "booksources-summary": "",
        "booksources-search-legend": "Search for book sources",
        "accesskey-pt-mycontris": "y",
        "accesskey-pt-login": "o",
        "accesskey-pt-logout": "",
+       "accesskey-pt-createaccount": "",
        "accesskey-ca-talk": "t",
        "accesskey-ca-edit": "e",
        "accesskey-ca-addsection": "+",
        "tooltip-pt-mycontris": "A list of your contributions",
        "tooltip-pt-login": "You are encouraged to log in; however, it is not mandatory",
        "tooltip-pt-logout": "Log out",
+       "tooltip-pt-createaccount": "You are encouraged to create an account and log in; however, it is not mandatory",
        "tooltip-ca-talk": "Discussion about the content page",
        "tooltip-ca-edit": "You can edit this page. Please use the preview button before saving",
        "tooltip-ca-addsection": "Start a new section",
index 8b1c980..9df939c 100644 (file)
        "logdelete-selected": "{{PLURAL:$1|Selektata protokola evento|Selektataj protokolaj eventoj}}:",
        "revdelete-text-text": "Forigitaj versioj ankoraŭ restas en la versia historio, sed partoj de ilia enhavo ne estas alireblaj por la publiko.",
        "revdelete-text-file": "Forigitaj dosieraj versioj ankoraŭ restas en la dosiera historio, sed partoj de ilia enhavo ne estas alireblaj por la publiko.",
-       "revdelete-text-others": "Aliaj administrantoj sur {{SITENAME}} ankoraŭ havas aliron al la kaŝita enhavo kaj povas malforigi ĝin denove per ĉi tiu sama interfaco, tiel longe kiel aldonaj restriktoj ne estas difinitaj.",
+       "revdelete-text-others": "Aliaj administrantoj ankoraŭ havas aliron al la kaŝita enhavo kaj povas malforigi ĝin, tiel longe kiel aldonaj restriktoj ne estas difinitaj.",
        "revdelete-confirm": "Bonvolu konfirmi ke vi intencias fari ĉi tion, ke vi komprenas la konsekvencojn kaj ke vi faras ĉi tion laŭ [[{{MediaWiki:Policy-url}}|la regularo]].",
        "revdelete-suppress-text": "Subpremo '''nur''' estu uzata por la jenaj kazoj:\n* Ebla kalumnia informo\n* Netaŭga persona informo\n*: ''hejmaj adresoj kaj telefonnumeroj, ŝtataj identnumeroj, ktp.''",
        "revdelete-legend": "Fari videblecajn limigojn",
        "search-result-category-size": "{{PLURAL:$1|1 membro|$1 membroj}} ({{PLURAL:$2|1 subkategorio|$2 subkategorioj}}, {{PLURAL:$3|1 dosiero|$3 dosieroj}})",
        "search-redirect": "(alidirektilo $1)",
        "search-section": "(sekcio $1)",
+       "search-file-match": "(kongruas kun dosiera enhavo)",
        "search-suggest": "Ĉu vi intenciis: $1",
        "search-interwiki-caption": "Kunprojektoj",
        "search-interwiki-default": "Rezultoj de $1:",
        "searchall": "ĉiuj",
        "showingresults": "Montras {{PLURAL:$1|'''1''' trovitan|'''$1''' trovitajn}} ekde la #'''$2'''-a.",
        "showingresultsinrange": "Malsupre montriĝas {{PLURAL:$1|<strong>1</strong> rezulto|<strong>$1</strong> rezultoj}} en la intervalo #<strong>$2</strong> ĝis #<strong>$3</strong>.",
+       "search-showingresults": "{{PLURAL:$4|Rezulto <strong>$1</strong> el <strong>$3</strong>|Rezultoj <strong>$1 - $2</strong> el <strong>$3</strong>}}",
        "search-nonefound": "La serĉomendo rezultis kun neniuj trafoj.",
        "powersearch-legend": "Progresa serĉo",
        "powersearch-ns": "Serĉi en nomspacoj:",
        "preferences": "Preferoj",
        "mypreferences": "Preferoj",
        "prefs-edits": "Nombro de redaktoj:",
-       "prefsnologintext2": "Bonvolu $1, por ŝanĝi viajn preferojn.",
+       "prefsnologintext2": "Bonvolu ensaluti, por ŝanĝi viajn preferojn.",
        "prefs-skin": "Etoso",
        "skin-preview": "Antaŭrigardo",
        "datedefault": "Nenia prefero",
        "querypage-disabled": "Tiu ĉi speciala paĝo estas malfunkciigita pro rendimentaj kialoj.",
        "booksources": "Libroservoj",
        "booksources-search-legend": "Serĉi librofontojn",
+       "booksources-search": "Serĉi",
        "booksources-text": "Jen ligilaro al aliaj TTT-ejoj, kiuj vendas librojn,\nkaj/aŭ informumos pri la libro ligita.\nLa {{SITENAME}} ne estas komerce ligita al tiuj vendejoj, kaj la listo ne estu\nkomprenata kiel rekomendo aŭ reklamo.",
        "booksources-invalid-isbn": "La donata ISBN verŝajne estas nevalida; kontrolu pri erara kopiado el la originala fonto.",
        "specialloguserlabel": "Faranto:",
        "mediastatistics-table-mimetype": "MIME-tipo",
        "mediastatistics-table-count": "Nombro de dosieroj",
        "mediastatistics-header-unknown": "Nekonata",
+       "mediastatistics-header-bitmap": "Rastrumaj bildoj",
+       "mediastatistics-header-drawing": "Desegnaĵoj (vektoraj bildoj)",
        "mediastatistics-header-audio": "Sonaj",
        "mediastatistics-header-video": "Videaj dosieroj",
        "mediastatistics-header-multimedia": "Multmediaj",
        "mediastatistics-header-office": "Oficejaj",
-       "mediastatistics-header-text": "Tekstaj"
+       "mediastatistics-header-text": "Tekstaj",
+       "json-error-syntax": "Sintaksa eraro"
 }
index 874e2f7..e69205a 100644 (file)
        "log-name-pagelang": "Registro de cambios en idiomas",
        "log-description-pagelang": "Este es un registro de los cambios en los idiomas de las páginas.",
        "logentry-pagelang-pagelang": "$1 {{GENDER:$2|cambió}} el idioma de la página «$3» del $4 al $5.",
-       "default-skin-not-found": "¡Oops! La apariencia por defecto de la wiki (<code>$wgDefaultSkin</code>), <code>$1</code>, no está disponible.\n\nLa instalación parece poseer las siguientes opciones de apariencia. Por favor revise [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] para mayor información sobre cómo configurarla y seleccionar la apariencia por defecto.\n\n$2\n\n; Si acaba de instalar MediaWiki:\n: Probablemente la haya instalado desde git, o directamente desde el código fuente usando algún otro método. Esto es lo esperado. Intente instalar algunos sets de apariencia desde [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org's skin directory]:\n:* Descargando [https://www.mediawiki.org/wiki/Download el instalador tarball], el cual contiene varios sets de apariencia y extensiones. Puede copiar y pegar el directorio <code>skins/</code> desde ahi.\n:* Clonando uno de los repositorios en <code>mediawiki/skins/*</code> via git dentro del directorio <code>skins/</code> de su instaación de MediaWiki.\n: Haciendo esto no debería interferir con su repositorio git si usted es un desarrollador de MediaWiki.\n\n; Si acaba de actualizar MediaWiki:\n: MediaWiki 1.24 y versiones posteriores ya no tiene habilitada la actualización de apariencia (revise [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]). Puede pegar las siguientes lineas <code>LocalSettings.php</code> para habilitar todos los sets de apariencia que haya configurado:\n\n<pre>$3</pre>\n\n; Si acaba de modificar <code>LocalSettings.php</code>:\n: Compruebe detenidamente posibles errores tipográficos en los nombres de los sets de apariencias.",
-       "default-skin-not-found-no-skins": "¡Vaya! La apariencia predeterminada de tu wiki (<code>$wgDefaultSkin</code>), <code>$1</code>, no está disponible.\n\nNo tienes apariencias instaladas.\n\n; Si has instalado o actualizado MediaWiki recientemente:\n: Probablemente has instalado desde git, o directamente desde el código fuente usando algún otro método. Esto es lo esperado. MediaWiki 1.24 y versiones posteriores no incluyen ninguna apariencia en el repositorio principal. Trata de instalar algunas apariencias desde el [https://www.mediawiki.org/wiki/Category:All_skins directorio de apariencias de mediawiki.org], siguiendo el siguiente procedimiento:\n:* Descarga el [https://www.mediawiki.org/wiki/Download instalador tarball], que viene con varias apariencias y extensiones. Puedes copiar y pegar el directorio <code>skins/</code> desde ahí.\n:* Clonando alguno de los repositorios en <code>mediawiki/skins/*</code> usando git en el directorio <code>skins/</code> de tu instalación de MediaWiki.\n: Hacer esto no debería interferir con tu repositorio de MediaWiki si eres un desarrollador de MediaWiki. Revisa [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] para información sobre cómo habilitar las apariencias y seleccionar la apariencia predeterminada.",
+       "default-skin-not-found": "¡Oops! La apariencia predeterminada de la wiki, definida en <code dir=\"ltr\">$wgDefaultSkin</code> como <code>$1</code>, no está disponible.\n\nLa instalación parece poseer las siguientes apariencias. Revisa [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual:Configuración de apariencias] para mayor información sobre cómo configurar y seleccionar la apariencia predeterminada.\n\n$2\n\n; Si acabas de instalar MediaWiki:\n: Probablemente la hayas instalado desde git, o directamente desde el código fuente usando algún otro método. Esto es lo esperado. Intenta instalar algunas apariencias desde [https://www.mediawiki.org/wiki/Category:All_skins el directorio de apariencias de mediawiki.org] ya sea:\n:* Descargando [https://www.mediawiki.org/wiki/Download el instalador tarball], el cual contiene varias apariencias y extensiones. Puedes copiar y pegar el directorio <code>skins/</code> desde ahí.\n:* Clonando uno de los repositorios en <code>mediawiki/skins/*</code> via git dentro del directorio <code dir=\"ltr\">skins/</code> de tu instalación de MediaWiki.\n: Hacer esto no debería interferir con tu repositorio git si eres un desarrollador de MediaWiki.\n\n; Si acabas de actualizar MediaWiki:\n: MediaWiki 1.24 y versiones posteriores ya no tiene habilitada la actualización de apariencia (revisa [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]). Puedes pegar las siguientes líneas en <code>LocalSettings.php</code> para habilitar todas las apariencias instaladas:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Si acabas de modificar <code>LocalSettings.php</code>:\n: Comprueba detenidamente posibles errores tipográficos en los nombres de las apariencias.",
+       "default-skin-not-found-no-skins": "¡Vaya! La apariencia predeterminada de tu wiki, definida en <code>$wgDefaultSkin</code> como <code>$1</code>, no está disponible.\n\nNo tienes apariencias instaladas.\n\n; Si has instalado o actualizado MediaWiki recientemente:\n: Probablemente has instalado desde git, o directamente desde el código fuente usando algún otro método. Esto es lo esperado. MediaWiki 1.24 y versiones posteriores no incluyen ninguna apariencia en el repositorio principal. Trata de instalar algunas apariencias desde el [https://www.mediawiki.org/wiki/Category:All_skins directorio de apariencias de mediawiki.org], siguiendo el siguiente procedimiento:\n:* Descarga el [https://www.mediawiki.org/wiki/Download instalador tarball], que viene con varias apariencias y extensiones. Puedes copiar y pegar el directorio <code>skins/</code> desde ahí.\n:* Clonando alguno de los repositorios en <code>mediawiki/skins/*</code> usando git en el directorio <code dir=\"ltr\">skins/</code> de tu instalación de MediaWiki.\n: Hacer esto no debería interferir con tu repositorio de MediaWiki si eres un desarrollador de MediaWiki. Revisa [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual:Configuración de apariencias] para información sobre cómo habilitar las apariencias y seleccionar la predeterminada.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (activado)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''desactivado''')",
        "mediastatistics": "Estadísticas de multimedia",
index 49780cc..610001c 100644 (file)
        "edit-gone-missing": "Ezin da orria eguneratu. Ezabatu omen dute.",
        "edit-conflict": "Aldaketa gatazka.",
        "edit-no-change": "Zure edizioa baztertu da testua aldatu ez duzulako.",
+       "postedit-confirmation-created": "Orrialdea sortu da.",
+       "postedit-confirmation-restored": "Orrialdea leheneratua izan da.",
        "postedit-confirmation-saved": "Zure aldaketa gorde da.",
        "edit-already-exists": "Ezin izan da orri berria sortu.\nJada existitzen da.",
        "defaultmessagetext": "Testu lehenetsia",
        "rcnotefrom": "Jarraian azaltzen diren aldaketak data honetatik aurrerakoak dira: <b>$2</b> (gehienez <b>$1</b> erakusten dira).",
        "rclistfrom": "Erakutsi $3 $2 ondorengo aldaketa berriak",
        "rcshowhideminor": "$1 aldaketa txikiak",
+       "rcshowhideminor-show": "Erakutsi",
+       "rcshowhideminor-hide": "Ezkutatu",
        "rcshowhidebots": "$1 bot-ak",
-       "rcshowhideliu": "$1 erabiltzaile erregistratuak",
+       "rcshowhidebots-show": "Erakutsi",
+       "rcshowhidebots-hide": "Ezkutatu",
+       "rcshowhideliu": "$1 erregistratutako erabiltzaileak",
+       "rcshowhideliu-show": "Erakutsi",
+       "rcshowhideliu-hide": "Ezkutatu",
        "rcshowhideanons": "$1 erabiltzaile anonimoak",
+       "rcshowhideanons-show": "Erakutsi",
+       "rcshowhideanons-hide": "Ezkutatu",
        "rcshowhidepatr": "$1 patruilatutako aldaketak",
+       "rcshowhidepatr-show": "Erakutsi",
+       "rcshowhidepatr-hide": "Ezkutatu",
        "rcshowhidemine": "$1 nire ekarpenak",
+       "rcshowhidemine-show": "Erakutsi",
+       "rcshowhidemine-hide": "Ezkutatu",
        "rclinks": "Erakutsi azken $2 egunetako $1 aldaketak<br />$3",
        "diff": "ezb",
        "hist": "hist",
        "randomincategory": "Kategoriako ausazko orrialdea",
        "randomincategory-invalidcategory": "\"$1\" ez da kategoria izen baliagarri bat.",
        "randomincategory-nopages": "Ez dago orrialderik [[:Category:$1|$1]] kategorian.",
+       "randomincategory-category": "Kategoria:",
        "randomredirect": "Ausazko birbideratzea",
        "randomredirect-nopages": "Ez dago birzuzenketarik \"$1\" izen-tartean.",
        "statistics": "Estatistikak",
        "version-hook-name": "Estentsioaren izena",
        "version-hook-subscribedby": "Hauen harpidetzarekin",
        "version-version": "(Bertsioa $1)",
+       "version-no-ext-name": "[izenik gabe]",
        "version-license": "MediaWiki Lizentzia",
        "version-ext-license": "Lizentzia",
        "version-ext-colheader-name": "Luzapena",
        "expand_templates_remove_comments": "Iruzkinak kendu",
        "expand_templates_remove_nowiki": "Ezabatu <nowiki> etiketen emaitzak",
        "expand_templates_generate_xml": "Erakutsi XML parse zuhaitza",
-       "expand_templates_preview": "Aurreikusi"
+       "expand_templates_preview": "Aurreikusi",
+       "pagelang-language": "Hizkuntza",
+       "mediastatistics-nbytes": "{{PLURAL:$1|$1 byte|$1 byte}} ($2; %$3)",
+       "mediastatistics-table-count": "Fitxategi kopurua",
+       "mediastatistics-header-video": "Bideoak",
+       "json-error-syntax": "Sintaxi-errorea"
 }
index 2566aea..a56cd54 100644 (file)
        "protectedpages-timestamp": "برچسب زمان",
        "protectedpages-page": "صفحه",
        "protectedpages-expiry": "انقضا",
-       "protectedpages-performer": "در حال حفاظت از کاربر",
+       "protectedpages-performer": "کاربر حفاظت‌کننده",
        "protectedpages-params": "پارامترهای حفاظت",
        "protectedpages-reason": "دلیل",
        "protectedpages-unknown-timestamp": "ناشناس",
index 319543c..f24b1a2 100644 (file)
        "cannotdelete-title": "Sivua $1 ei voi poistaa",
        "delete-hook-aborted": "Laajennuskoodi esti poiston antamatta syytä.",
        "no-null-revision": "Nollamuokkausta sivulla \"$1\" ei voi tehdä",
-       "badtitle": "Virheellinen otsikko",
+       "badtitle": "Kelvoton sivun nimi",
        "badtitletext": "Pyytämäsi sivunimi oli virheellinen, tyhjä tai väärin linkitetty kieltenvälinen tai wikienvälinen nimi.\nSiinä saattaa olla yksi tai useampi sellainen merkki, jota ei voi käyttää sivujen nimissä.",
        "perfcached": "Nämä tiedot ovat välimuistista eivätkä välttämättä ole ajan tasalla. Välimuistissa on saatavilla enintään {{PLURAL:$1|yksi tulos|$1 tulosta}}.",
        "perfcachedts": "Nämä tiedot ovat välimuistista, ja ne on päivitetty viimeksi $1. Välimuistissa on saatavilla enintään {{PLURAL:$4|yksi tulos|$4 tulosta}}.",
index 4b54e40..c9893e1 100644 (file)
        "mediastatistics-table-totalbytes": "Taille combinée",
        "mediastatistics-header-unknown": "Inconnu",
        "mediastatistics-header-bitmap": "Images raster",
-       "mediastatistics-header-drawing": "Desseins (images vectorielles)",
+       "mediastatistics-header-drawing": "Dessins (images vectorielles)",
        "mediastatistics-header-audio": "Audio",
        "mediastatistics-header-video": "Vidéos",
        "mediastatistics-header-multimedia": "Média riche",
index 0ceca56..4630efe 100644 (file)
        "upload-source": "קובץ המקור",
        "sourcefilename": "שם הקובץ:",
        "sourceurl": "כתובת URL של המקור:",
-       "destfilename": "ש×\9e×\95ר קובץ בשם:",
+       "destfilename": "ש×\9e×\99רת ×\94קובץ בשם:",
        "upload-maxfilesize": "גודל הקובץ המרבי: $1",
        "upload-description": "תיאור הקובץ",
        "upload-options": "אפשרויות העלאה",
index 2062da1..16ca978 100644 (file)
@@ -57,6 +57,7 @@
        "tog-showhiddencats": "Ցուցադրել թաքնված կատեգորիաները",
        "tog-norollbackdiff": "Չցուցադրել տարբերությունները հետ գլորելուց հետո",
        "tog-useeditwarning": "Զգուշացնել ինձ, երբ ես լքում եմ խմբագրման էջը առանց կատարած փոփոխությունները հիշելու։",
+       "tog-prefershttps": "Մուտք գործելուց հետո, միշտ գործածել անվնտանգ միացումից (HTTPS)",
        "underline-always": "Միշտ",
        "underline-never": "Երբեք",
        "underline-default": "Դիտարկչի կամ թեմայի լռելյայն ոճով",
        "showpreview": "Նախադիտել",
        "showdiff": "Կատարված փոփոխությունները",
        "anoneditwarning": "'''Ուշադրություն.''' Դուք չեք մտել համակարգ։\nՁեր IP հասցեն կգրանցվի այս էջի խմբագրումների պատմության մեջ։",
-       "anonpreviewwarning": "Դուք չեք մտել համակարգ։\n''Հիշելով ձեր կատարած խմբագրումը, այն կգրանցվի Ձեր IP հասցեի ներքո այս էջի խմբագրումների պատմության մեջ։''",
+       "anonpreviewwarning": "<em>Դուք չեք մտել համակարգ։\nՀիշելով Ձեր կատարած խմբագրումը, այն կպահանվի Ձեր IP հասցեի հետ միասին այս էջի խմբագրումների պատմության մեջ։</em>",
        "missingsummary": "'''Հիշեցում.''' Դուք չեք տվել խմբագրման ամփոփում։ «Հիշել» կոճակի կրկնակի մատնահարման դեպքում փոփոխությունները կհիշվեն առանց ամփոփման։",
        "missingcommenttext": "Խնդրում ենք մեկնաբանություն ավելացնել ստորև։",
        "missingcommentheader": "'''Հիշեցում.''' Դուք չեք նշել մեկնաբանության վերնագիրը։ «Հիշել» կոճակի կրկնակի մատնահարման դեպքում ձեր մեկնաբանությունը կհիշվի առանց վերնագրի։",
        "recentchanges-label-minor": "Սա չնչին խմբագրում է",
        "recentchanges-label-bot": "Այս խմբագրումը կատարվել է բոտի կողմից",
        "recentchanges-label-unpatrolled": "Այս խմբագրումը դեռ չի պարեկվել",
-       "recentchanges-label-plusminus": "Ô·Õ»Õ« Õ¹Õ¡Ö\83Õ½Õ¶ Ö\83Õ¸Õ­Õ¸Õ­Õ¾Õ¥Ö\81 Õ¡ÕµÕ½Ö\84Õ¡Õ¶ Õ¢Õ¡ÕµÕ©Õ¸Õ¾Ö\89",
+       "recentchanges-label-plusminus": "Ô·Õ»Õ« Õ¹Õ¡Ö\83Õ½Õ¨ Ö\83Õ¸Ö\83Õ¸Õ­Õ¾Õ¥Ö\81 Õ¡ÕµÕ½Ö\84Õ¡Õ¶ Õ¢Õ¡ÕµÕ©Õ¸Õ¾",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (տես նաև՝  [[Special:NewPages|նոր էջերի ցանկ]])",
        "rcnotefrom": "Ստորև բերված են փոփոխությունները սկսած՝ '''$2''' (մինչև՝ '''$1''')։",
        "rclistfrom": "Ցույց տալ նոր փոփոխությունները սկսած $3 $2",
        "confirm-watch-button": "ԼԱՎ",
        "confirm-watch-top": "Ավելացնե՞լ ձեր հսկացանկին",
        "confirm-unwatch-button": "ԼԱՎ",
-       "confirm-unwatch-top": "Õ\80Õ¥Õ¼Õ¡Ö\81Õ¶Õ¥Õ\9eÕ¬ Õ±եր հսկացանկից։",
+       "confirm-unwatch-top": "Õ\80Õ¥Õ¼Õ¡Ö\81Õ¶Õ¥Õ\9eÕ¬ Õ\81եր հսկացանկից։",
        "imgmultipageprev": "← նախորդ էջ",
        "imgmultipagenext": "հաջորդ էջ →",
        "imgmultigo": "Անցնե՛լ",
index 1032b7d..9a348f3 100644 (file)
        "prefs-watchlist": "ウォッチリスト",
        "prefs-watchlist-days": "ウォッチリストの表示日数:",
        "prefs-watchlist-days-max": "最大 $1 {{PLURAL:$1|日間}}",
-       "prefs-watchlist-edits": "拡張ウォッチリストの表示件数:",
+       "prefs-watchlist-edits": "ウォッチリストの展開時の最大表示件数:",
        "prefs-watchlist-edits-max": "最大数: 1000",
        "prefs-watchlist-token": "ウォッチリストのトークン:",
        "prefs-misc": "その他",
        "json-error-state-mismatch": "JSON が無効か、または破損しています",
        "json-error-ctrl-char": "制御文字のエラーです。おそらく正しく符号化されていません",
        "json-error-syntax": "構文エラー",
-       "json-error-utf8": "UTF-8 の文字が破損しています。エンコーディングが誤っているおそれがあります"
+       "json-error-utf8": "UTF-8 の文字が破損しています。エンコーディングが誤っているおそれがあります",
+       "json-error-recursion": "エンコードされる値に1つ以上の循環参照が含まれます",
+       "json-error-inf-or-nan": "エンコードされる値に1つ以上の NAN または INF が含まれます",
+       "json-error-unsupported-type": "エンコードできない種類の値が入力されました"
 }
index fba9511..71e236d 100644 (file)
        "delete_and_move": "Жою және жылжыту",
        "delete_and_move_text": "== Жоюды қажет етеді ==\nТағайындалған «[[:$1]]» беті әлдеқашан бар.\nЖылжытуға жол беру үшін бұны жойғыңыз келе ме?",
        "delete_and_move_confirm": "Иә, бұл бетті жой",
-       "delete_and_move_reason": "\"[[$1]]\" дегеннен жылжытуға жол беру үшін жойылған",
+       "delete_and_move_reason": "«[[$1]]» дегеннен жылжытуға жол беру үшін жойылған",
        "selfmove": "Қайнар және нысана тақырып аттары бірдей;\nбет өзінің үстіне жылжытылмайды.",
        "immobile-source-namespace": "\"$1\" есім кеңістігіндегі беттер жылжытылмайды",
        "immobile-target-namespace": "\"$1\" есім кеңістігіне беттерді жылдытылмайды",
index 07d8c69..7d56808 100644 (file)
@@ -85,7 +85,7 @@
        "underline-always": "항상",
        "underline-never": "항상 치지 않기",
        "underline-default": "스킨 또는 브라우저 기본값",
-       "editfont-style": "í\8e¸ì§\91 ì°½의 글꼴:",
+       "editfont-style": "í\8e¸ì§\91 ì\98\81ì\97­의 글꼴:",
        "editfont-default": "브라우저 기본값",
        "editfont-monospace": "고정폭 글꼴",
        "editfont-sansserif": "산세리프 글꼴",
        "hidden-categories": "{{PLURAL:$1|숨은 분류}}",
        "hidden-category-category": "숨은 분류",
        "category-subcat-count": "{{PLURAL:$2|이 분류에는 하위 분류 1개만이 속해 있습니다.|다음은 이 분류에 속하는 {{PLURAL:$1|하위 분류}} $2개 가운데 $1개입니다.}}",
-       "category-subcat-count-limited": "이 분류에 {{PLURAL:$1|하위 분류}} $1개가 있습니다.",
+       "category-subcat-count-limited": "이 분류에 {{PLURAL:$1|하위 분류가|하위 분류 $1개가}} 있습니다.",
        "category-article-count": "{{PLURAL:$2|이 분류에는 문서 1개만이 속해 있습니다.|다음은 이 분류에 속하는 {{PLURAL:$1|문서}} $2개 가운데 $1개입니다.}}",
-       "category-article-count-limited": "이 분류에 {{PLURAL:$1|문서}} $1개가 있습니다.",
+       "category-article-count-limited": "이 분류에 {{PLURAL:$1|문서가|문서 $1개가}} 있습니다.",
        "category-file-count": "{{PLURAL:$2|이 분류에는 파일 1개만이 속해 있습니다.|다음은 이 분류에 속하는 {{PLURAL:$1|파일}} $2개 가운데 $1개입니다.}}",
-       "category-file-count-limited": "이 분류에 {{PLURAL:$1|파일}} $1개가 있습니다.",
+       "category-file-count-limited": "이 분류에 {{PLURAL:$1|파일이|파일 $1개가}} 있습니다.",
        "listingcontinuesabbrev": "(계속)",
        "index-category": "색인된 문서",
        "noindex-category": "색인에서 제외되는 문서",
        "morenotlisted": "이 목록은 완성되지 않았습니다.",
        "mypage": "문서",
        "mytalk": "토론",
-       "anontalk": "ì\9dµëª\85 사용자와 토론",
+       "anontalk": "ì\9d´ IP ì£¼ì\86\8cì\9d\98 사용자와 토론",
        "navigation": "둘러보기",
        "and": ",",
        "qbfind": "찾기",
        "delete": "삭제",
        "deletethispage": "이 문서 삭제하기",
        "undeletethispage": "이 문서를 되살리기",
-       "undelete_short": "{{PLURAL:$1|편집}} $1개 되살리기",
-       "viewdeleted_short": "{{PLURAL:$1|삭제된 편집}} $1개 보기",
+       "undelete_short": "{{PLURAL:$1|편집 한 개|편집 $1개}} 되살리기",
+       "viewdeleted_short": "{{PLURAL:$1|삭제된 편집 한 개|삭제된 편집 $1개}} 보기",
        "protect": "보호",
        "protect_change": "보호 수준 바꾸기",
        "protectthispage": "이 문서 보호하기",
        "privacypage": "Project:개인 정보 정책",
        "badaccess": "권한 오류",
        "badaccess-group0": "요청한 명령을 실행할 권한이 없습니다.",
-       "badaccess-groups": "요청한 명령은 {{PLURAL:$2|다음|다음 중 하나의}} 권한을 가진 사용자에게만 가능합니다: $1",
+       "badaccess-groups": "요청한 명령은 {{PLURAL:$2|다음|다음 중 하나의}} 권한을 가진 사용자에게 제한됩니다: $1.",
        "versionrequired": "미디어위키 $1 버전 필요",
        "versionrequiredtext": "이 문서를 사용하려면 $1 버전 미디어위키가 필요합니다.\n[[Special:Version|설치된 미디어위키 버전]]을 참고하세요.",
        "ok": "확인",
        "retrievedfrom": "원본 주소 \"$1\"",
-       "youhavenewmessages": "다른 사용자가 $1를 {{PLURAL:$3|남겼습니다}}. ($2)",
-       "youhavenewmessagesfromusers": "{{PLURAL:$3|다른 사용자가|사용자 $3명이}} $1를 {{PLURAL:$4|남겼습니다}}. ($2)",
-       "youhavenewmessagesmanyusers": "여러 사용자가 $1를 남겼습니다. ($2)",
+       "youhavenewmessages": "다른 사용자로부터의 $1가 {{PLURAL:$3|있습니다}}. ($2)",
+       "youhavenewmessagesfromusers": "{{PLURAL:$3|다른 사용자로|사용자 $3명으로}}부터의 $1가 {{PLURAL:$4|있습니다}}. ($2)",
+       "youhavenewmessagesmanyusers": "여러 사용자로부터의 $1가 있습니다. ($2)",
        "newmessageslinkplural": "{{PLURAL:$1|새 메시지}}",
        "newmessagesdifflinkplural": "마지막으로 {{PLURAL:$1|바뀐 내용}}",
        "youhavenewmessagesmulti": "다른 사용자가 $1에 남긴 새 메시지가 있습니다",
        "confirmable-no": "아니오",
        "thisisdeleted": "$1 문서를 보거나 되살리겠습니까?",
        "viewdeleted": "$1 문서를 보겠습니까?",
-       "restorelink": "{{PLURAL:$1|삭제된 편집}} $1개",
+       "restorelink": "{{PLURAL:$1|삭제된 편집 한 개|삭제된 편집 $1개}}",
        "feedlinks": "피드:",
        "feed-invalid": "잘못된 구독 피드 방식입니다.",
-       "feed-unavailable": "피드 서비스를 사용할 수 없습니다",
+       "feed-unavailable": "피드 배달을 사용할 수 없습니다",
        "site-rss-feed": "$1 RSS 피드",
        "site-atom-feed": "$1 Atom 피드",
        "page-rss-feed": "\"$1\" RSS 피드",
        "nstab-template": "틀",
        "nstab-help": "도움말",
        "nstab-category": "분류",
-       "nosuchaction": "해당하는 명령이 없습니다.",
-       "nosuchactiontext": "URLì\9d´ ì§\80ì \95í\95\9c ëª\85ë ¹ì\9d´ ì\9e\98못ë\90\98ì\97\88ì\8aµë\8b\88ë\8b¤.\nURLì\9d\84 ì\9e\98못 ì\9e\85ë ¥í\95\98ì\98\80ê±°ë\82\98, ì\9e\98못ë\90\9c ë§\81í\81¬ë¥¼ ë\94°ë\9d¼ê°\94ì\9d\84 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.\n{{SITENAME}}ì\9d\98 ë²\84ê·¸ì\9d¼ ì\88\98ë\8f\84 있습니다.",
+       "nosuchaction": "이러한 명령이 없습니다",
+       "nosuchactiontext": "URLì\97\90 ì§\80ì \95í\95\9c ëª\85ë ¹ì\9d´ ì\98¬ë°\94르ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤.\nURLì\9d\84 ì\9e\98못 ì\9e\85ë ¥í\96\88ê±°ë\82\98, ì\98¬ë°\94르ì§\80 ì\95\8aì\9d\80 ë§\81í\81¬ë¥¼ ë\94°ë\9d¼ê°\94ì\9d\84 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.\n{{SITENAME}}ì\97\90 ì\82¬ì\9a©í\95\98ë\8a\94 ì\86\8cí\94\84í\8a¸ì\9b¨ì\96´ì\9d\98 ë²\84ê·¸ê°\80 ì\9e\88ì\9d\84 ì\88\98 있습니다.",
        "nosuchspecialpage": "해당하는 특수 문서가 없습니다.",
        "nospecialpagetext": "<strong>요청한 특수 문서가 존재하지 않습니다.</strong>\n\n특수 문서의 목록은 [[Special:SpecialPages|여기]]에서 볼 수 있습니다.",
        "error": "오류",
        "databaseerror-query": "쿼리: $1",
        "databaseerror-function": "함수: $1",
        "databaseerror-error": "오류: $1",
-       "laggedslavemode": "'''경고:''' 문서가 최근에 바뀐 내용을 포함하지 않을 수도 있습니다.",
+       "laggedslavemode": "<strong>경고:</strong> 문서가 최근에 바뀐 내용을 포함하지 않을 수도 있습니다.",
        "readonly": "데이터베이스 잠김",
        "enterlockreason": "데이터베이스를 잠그는 이유와 예상되는 기간을 적어 주세요.",
        "readonlytext": "데이터베이스가 잠겨 있어서 문서를 편집할 수 없습니다. 데이터베이스 관리가 끝난 후에는 정상으로 돌아올 것입니다.\n\n관리자가 데이터베이스를 잠글 때 남긴 메시지는 다음과 같습니다: $1",
        "filedeleteerror": "\"$1\" 파일을 삭제할 수 없습니다.",
        "directorycreateerror": "\"$1\" 디렉터리를 만들 수 없습니다.",
        "filenotfound": "\"$1\" 파일을 찾을 수 없습니다.",
-       "unexpected": "예기치 못한 값: \"$1\"=\"$2\"",
+       "unexpected": "예기치 않은 값: \"$1\"=\"$2\".",
        "formerror": "오류: 양식을 제출할 수 없습니다.",
-       "badarticleerror": "해당 명령은 이 문서에서 실행할 수 없습니다.",
+       "badarticleerror": "이 명령은 이 문서에서 수행할 수 없습니다.",
        "cannotdelete": "\"$1\" 문서나 파일을 삭제할 수 없습니다.\n이미 삭제되었을 수도 있습니다.",
        "cannotdelete-title": "\"$1\" 문서를 삭제할 수 없습니다.",
        "delete-hook-aborted": "훅이 삭제를 중단했습니다.\n아무런 설명도 주어지지 않았습니다.",
        "no-null-revision": "\"$1\" 문서에 대한 새 빈 판을 만들 수 없습니다",
        "badtitle": "잘못된 제목",
        "badtitletext": "요청한 문서 제목이 잘못되었거나, 비어있거나, 잘못된 인터위키 제목으로 링크했습니다.\n문서 제목에 사용할 수 없는 문자를 사용했을 수 있습니다.",
-       "perfcached": "ë\8b¤ì\9d\8c ì\9e\90ë£\8cë\8a\94 ìº\90ì\8b\9cë\90\9c ê²\83ì\9d´ë¯\80ë¡\9c ì\83\88ë¡\9c ë°\94ë\80\90 ë\82´ì\9a©ì\9d\84 ë°\98ì\98\81í\95\98ì§\80 ëª»í\95  ì\88\98ë\8f\84 ì\9e\88ì\8aµë\8b\88ë\8b¤. ìº\90ì\8b\9cì\97\90 ìµ\9cë\8c\80 {{PLURAL:$1|$1ê°\9cì\9d\98 ê²°ê³¼}}가 있습니다.",
-       "perfcachedts": "ë\8b¤ì\9d\8c ì\9e\90ë£\8cë\8a\94 ìº\90ì\8b\9cë\90\9c ê²\83ì\9c¼ë¡\9c, $1ì\97\90 ë§\88ì§\80ë§\89ì\9c¼ë¡\9c ì\83\88ë¡\9c ê³ ì³\90ì¡\8cì\8aµë\8b\88ë\8b¤. ìº\90ì\8b\9cì\97\90 ìµ\9cë\8c\80 {{PLURAL:$4|결과 $4개}}가 있습니다.",
-       "querypage-no-updates": "ì\9d´ ë¬¸ì\84\9cì\9d\98 ì\83\88ë¡\9c ê³ ì¹¨ì\9d´ í\98\84ì\9e¬ ë¹\84í\99\9cì\84±í\99\94ë\90\98ì\96´ ì\9e\88ì\8aµë\8b\88ë\8b¤.\nì\9d´ ë¬¸ì\84\9cì\9d\98 ì\9e\90ë£\8c를 ì\9e ì\8b\9c ë\8f\99ì\95\88 새로 고치지 않을 것입니다.",
+       "perfcached": "ë\8b¤ì\9d\8c ì\9e\90ë£\8cë\8a\94 ìº\90ì\8b\9cë\90\9c ê²\83ì\9d´ë©° ìµ\9cì\8b ì\9d´ ì\95\84ë\8b\90 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ìº\90ì\8b\9cì\97\90 ìµ\9cë\8c\80 {{PLURAL:$1|ê²°ê³¼ í\95\9c ê°\9c|ê²°ê³¼ $1ê°\9c}}가 있습니다.",
+       "perfcachedts": "ë\8b¤ì\9d\8c ì\9e\90ë£\8cë\8a\94 ìº\90ì\8b\9cë\90\9c ê²\83ì\9c¼ë¡\9c, $1ì\97\90 ë§\88ì§\80ë§\89ì\9c¼ë¡\9c ì\97\85ë\8d°ì\9d´í\8a¸ë\90\98ì\97\88ì\8aµë\8b\88ë\8b¤. ìº\90ì\8b\9cì\97\90 ìµ\9cë\8c\80 {{PLURAL:$4|ê²°ê³¼ í\95\9c ê°\9c|결과 $4개}}가 있습니다.",
+       "querypage-no-updates": "ì\9d´ ë¬¸ì\84\9cì\9d\98 ì\83\88ë¡\9c ê³ ì¹¨ì\9d´ í\98\84ì\9e¬ ë¹\84í\99\9cì\84±í\99\94ë\90\98ì\96´ ì\9e\88ì\8aµë\8b\88ë\8b¤.\nì\9e\90ë£\8cê°\80 ì\9e ì\8b\9c 새로 고치지 않을 것입니다.",
        "viewsource": "원본 보기",
        "viewsource-title": "$1 문서 원본 보기",
        "actionthrottled": "동작 중지",
        "exception-nologin-text-manual": "이 문서에 접근하거나 이 명령을 수행하려면 $1하세요.",
        "virus-badscanner": "잘못된 설정: 알 수 없는 바이러스 검사기: '''$1'''",
        "virus-scanfailed": "검사 실패 (코드 $1)",
-       "virus-unknownscanner": "알 수 없는 백신 소프트웨어:",
-       "logouttext": "'''지금 로그아웃했습니다.'''\n\n브라우저 캐시를 지우지 않으면 일부 문서에서 로그인이 되어 있는 것처럼 보일 수 있습니다.",
+       "virus-unknownscanner": "알 수 없는 안티 바이러스:",
+       "logouttext": "<strong>지금 로그아웃했습니다.</strong>\n\n브라우저 캐시를 지우지 않으면 일부 문서에서 로그인이 되어 있는 것처럼 보일 수 있습니다.",
        "welcomeuser": "$1님, 환영합니다!",
        "welcomecreation-msg": "계정이 만들어졌습니다.\n[[Special:Preferences|{{SITENAME}} 사용자 환경 설정]]을 바꿀 수 있습니다.",
        "yourname": "사용자 이름:",
        "search-file-match": "(내용이 일치하는 파일 있음)",
        "search-suggest": "$1 문서를 찾고 있으신가요?",
        "search-interwiki-caption": "자매 프로젝트",
-       "search-interwiki-default": "$1 로부터의 결과:",
+       "search-interwiki-default": "$1로부터의 결과:",
        "search-interwiki-more": "(더 보기)",
        "search-relatedarticle": "관련",
        "searchrelated": "관련",
        "searchall": "모두",
        "showingresults": "'''$2'''번 부터의 {{PLURAL:$1|결과 '''1'''개|결과 '''$1'''개}}입니다.",
        "showingresultsinrange": "#<strong>$2</strong>부터 #<strong>$3</strong>까지의 범위에서 <strong>$1</strong>개의 {{PLURAL:$1|결과}}가 아래에 보입니다.",
+       "search-showingresults": "{{PLURAL:$4|결과 <strong>$3</strong>개 중 <strong>$1</strong>개|결과 <strong>$3</strong>개 중 <strong>$1 - $2</strong>개}}",
        "search-nonefound": "검색어와 일치하는 결과가 없습니다.",
        "powersearch-legend": "고급 검색",
        "powersearch-ns": "다음 이름공간에서 검색:",
        "powersearch-toggleall": "모두",
        "powersearch-togglenone": "모두 제외",
        "powersearch-remember": "향후 검색에 선택 기억하기",
-       "search-external": "바깥에서 검색",
+       "search-external": "바깥 검색",
        "searchdisabled": "{{SITENAME}} 검색이 비활성화되어 있습니다.\n검색이 작동하지 않는 동안에는 Google(구글)을 통해 검색할 수 있습니다.\n검색 엔진의 내용은 최신이 아닐 수 있다는 점을 참고하세요.",
        "search-error": "검색하는 동안 오류가 발생했습니다: $1",
        "preferences": "사용자 환경 설정",
        "mypreferences": "환경 설정",
        "prefs-edits": "편집 수:",
-       "prefsnologintext2": "ì\82¬ì\9a©ì\9e\90 í\99\98ê²½ ì\84¤ì \95ì\9d\84 ë³\80ê²½í\95\98려면 ë¡\9cê·¸ì\9d¸í\95\98ì\8b­ì\8b\9cì\98¤.",
+       "prefsnologintext2": "ì\82¬ì\9a©ì\9e\90 í\99\98ê²½ ì\84¤ì \95ì\9d\84 ë°\94꾸려면 ë¡\9cê·¸ì\9d¸í\95\98ì\84¸ì\9a\94.",
        "prefs-skin": "스킨",
        "skin-preview": "미리 보기",
        "datedefault": "설정하지 않음",
        "prefs-files": "파일",
        "prefs-custom-css": "사용자 CSS",
        "prefs-custom-js": "사용자 자바스크립트",
-       "prefs-common-css-js": "모든 스킨에 대한 공통 CSS/자바스크립트:",
+       "prefs-common-css-js": "모든 스킨에 공유된 CSS/자바스크립트:",
        "prefs-reset-intro": "이 페이지를 사용해 사이트 기본값으로 환경 설정을 재설정할 수 있습니다.\n이는 되돌릴 수 없습니다.",
        "prefs-emailconfirm-label": "이메일 인증:",
        "youremail": "이메일:",
        "prefs-tokenwatchlist": "토큰",
        "prefs-diffs": "차이",
        "prefs-help-prefershttps": "이 사용자 환경 설정은 다음 로그인부터 적용됩니다.",
+       "prefswarning-warning": "사용자 환경 설정에서 바뀐 것이 아직 저장되어 있지 않습니다.\n사용자 환경 설정에서 \"$1\"을 클릭하지 않고 이 페이지를 떠나면 바뀌지 않습니다.",
        "prefs-tabs-navigation-hint": "팁: 탭 목록에서 탭 사이를 둘러보려면 왼쪽과 오른쪽 화살표 키를 사용할 수 있습니다.",
        "email-address-validity-valid": "이메일 주소가 올바른 것으로 보입니다",
        "email-address-validity-invalid": "올바른 이메일 주소를 입력하세요",
        "noindex-category-desc": "문서는 그것과 그 플래그가 허용된 곳에 있는 이름공간에서 <code><nowiki>__NOINDEX__</nowiki></code> 특수 명령이 있기 때문에 로봇이 색인하지 않습니다.",
        "index-category-desc": "문서는 그것(과 플래그가 허용된 곳에 있는 이름공간에 있는 것)에 <code><nowiki>__INDEX__</nowiki></code>가 있어서, 정상적이지 않을 곳에 로봇에 의해 색인됩니다.",
        "post-expand-template-inclusion-category-desc": "모든 틀을 전개하였을 때, 문서 크기가 <code>$wgMaxArticleSize</code>보다 커지므로, 어떤 틀은 전개하지 않았습니다.",
-       "post-expand-template-argument-category-desc": "틀 변수 (<code>{{{Foo}}}</code>와 같은, 중괄호가 세 개 있는 무언가)를 확장하고 나서, 문서는 <code>$wgMaxArticleSize</code>보다 커집니다.",
-       "expensive-parserfunction-category-desc": "(<code>#ifexist</code>와 같은) 느린 파서 함수가 너무 많이 문서에 포함되어 있습니다. [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Manual:$wgExpensiveParserFunctionLimit]를 보세요.",
-       "broken-file-category-desc": "ë\84ë¥\98ê°\80 ê¹¨ì§\84 í\8c\8cì\9d¼ ë§\81í\81¬ (í\8c\8cì\9d¼ì\9d´ ì¡´ì\9e¬í\95\98ì§\80 ì\95\8aì\9d\84 ë\95\8c í\8f¬í\95¨ë\90\98ë\8a\94 ë§\81í\81¬)ê°\80 ì\9e\88ë\8a\94 ë¬¸ì\84\9cê°\80 ì\9e\88ë\8b¤ë©´ ì¶\94ê°\80ë\90©ë\8b\88ë\8b¤.",
-       "hidden-category-category-desc": "기본적으로 문서에 분류 링크 상자가 보여지는 것에서 막기 위한, <code><nowiki>__HIDDENCAT__</nowiki></code>가 있는 분류입니다.",
+       "post-expand-template-argument-category-desc": "틀 변수 (<code>{{{Foo}}}</code>와 같은, 중괄호가 세 개 있는 무언가)를 확장하고 나서 문서는 <code>$wgMaxArticleSize</code>보다 커집니다.",
+       "expensive-parserfunction-category-desc": "문서에 (<code>#ifexist</code>와 같은) 느린 파서 함수가 너무 많이 쓰이고 있습니다. [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Manual:$wgExpensiveParserFunctionLimit]를 보세요.",
+       "broken-file-category-desc": "문ì\84\9cì\97\90 ê¹¨ì§\84 í\8c\8cì\9d¼ ë§\81í\81¬ (í\8c\8cì\9d¼ì\9d´ ì¡´ì\9e¬í\95\98ì§\80 ì\95\8aì\9d\84 ë\95\8c í\8f¬í\95¨ë\90\98ë\8a\94 ë§\81í\81¬)를 í\8f¬í\95¨í\95©ë\8b\88ë\8b¤.",
+       "hidden-category-category-desc": "기본적으로 문서에 분류 링크 상자가 보여지는 것에서 막기 위한, 분류의 문서 내용에 <code><nowiki>__HIDDENCAT__</nowiki></code>를 포함합니다.",
        "trackingcategories-nodesc": "사용할 수 있는 설명이 없습니다.",
        "trackingcategories-disabled": "분류가 비활성화되어 있습니다",
        "mailnologin": "보낼 이메일 주소가 없음",
        "watchlist-details": "별도의 토론 문서를 세지 않고, 주시문서 목록에 {{PLURAL:$1|문서 $1개}}가 있습니다.",
        "wlheader-enotif": "이메일 알림 기능이 활성화되었습니다.",
        "wlheader-showupdated": "마지막으로 방문한 이후에 바뀐 문서는 '''굵은 글씨'''로 보입니다.",
-       "wlnote": "다음은 최근 {{PLURAL:$2|'''$2'''시간}} 동안 {{PLURAL:$1|바뀐 문서 '''$1'''개 입니다}}. ($3 $4 기준)",
+       "wlnote": "$3 $4 기준으로, 아래에 최근 {{PLURAL:$2|한 시간|<strong>$2</strong>시간}} 동안 {{PLURAL:$1|마지막 바뀜이|마지막 바뀜 <strong>$1</strong>개가}} 있습니다.",
        "wlshowlast": "최근 $1시간 $2일 동안의 바뀜 보기",
        "watchlist-options": "주시문서 목록 설정",
        "watching": "주시 추가 중…",
        "print.css": "/* 이 CSS 설정은 인쇄 출력 화면에 적용됩니다 */",
        "noscript.css": "/* 이 CSS 설정은 자바스크립트를 비활성화한 사용자에 적용됩니다 */",
        "group-autoconfirmed.css": "/* 이 CSS 설정은 자동 인증된 사용자에만 적용됩니다 */",
+       "group-user.css": "/* 이 CSS 설정은 등록된 사용자에만 적용됩니다 */",
        "group-bot.css": "/* 이 CSS 설정은 봇에만 적용됩니다 */",
        "group-sysop.css": "/* 이 CSS 설정은 관리자에만 적용됩니다 */",
        "group-bureaucrat.css": "/* 이 CSS 설정은 사무관에만 적용됩니다 */",
        "common.js": "/* 이 자바스크립트 설정은 모든 문서, 모든 사용자에게 적용됩니다. */",
        "group-autoconfirmed.js": "/* 이 자바스크립트 설정은 자동 인증된 사용자에만 적용됩니다 */",
+       "group-user.js": "/* 이 자바스크립트 설정은 등록된 사용자에만 적용됩니다 */",
        "group-bot.js": "/* 이 자바스크립트 설정은 봇에만 적용됩니다 */",
        "group-sysop.js": "/* 이 자바스크립트 설정은 관리자에만 적용됩니다 */",
        "group-bureaucrat.js": "/* 이 자바스크립트 설정은 사무관에만 적용됩니다 */",
        "log-name-pagelang": "언어 바꾸기 기록",
        "log-description-pagelang": "문서 언어를 바꾼 기록입니다.",
        "logentry-pagelang-pagelang": "$1 사용자가 $3의 문서 언어를 $4에서 $5로 {{GENDER:$2|바꾸었습니다}}.",
+       "default-skin-not-found": "이런! 당신의 위키에 <code dir=\"ltr\">$wgDefaultSkin</code>에 <code>$1</code>(으)로 지정한 기본 스킨은 사용할 수 없습니다.\n\n설치에는 다음 스킨이 포함된 것으로 보입니다. 스킨을 활성화하고 기본값으로 선택하는 방법에 대한 정보에 대해서는 [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: 스킨 설정]을 보세요.\n\n$2\n\n; 미디어위키를 설치했다면:\n: 아마 git에서 설치했거나, 어떤 다른 방법을 사용하여 직접 설치했을 수 있을 것으로 봅니다. [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org의 스킨 디렉터리]에서 어떤 스킨을 설치해보세요:\n:* 여러 스킨과 확장 기능이 들어 있는 [https://www.mediawiki.org/wiki/Download tarball 설치 프로그램]을 다운로드하세요. 거기서 <code>skins/</code> 디렉터리를 복사하여 붙여 넣을 수 있습니다.\n:* 미디어위키 설치의 <code dir=\"ltr\">skins/</code> 디렉터리 안에 git를 통해 <code>mediawiki/skins/*</code> 저장소 중 하나를 복제하세요.\n: 당신이 미디어위키 개발자이면 당신의 git 저장소를 방해하면 안됩니다.\n\n; 미디어위키를 업그레이드했다면:\n: 미디어위키 1.24와 새 버전은 더 이상 설치된 스킨을 자동으로 활성화하지 않습니다 ([https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: 스킨 자동발견]을 보세요). 현재 설치된 스킨을 모두 활성화하려면 <code>LocalSettings.php</code> 안에 다음 줄을 붙여 넣을 수 있습니다:\n\n<pre dir=\"ltr\">$3</pre>\n\n; <code>LocalSettings.php</code>를 수정했다면:\n: 스킨 이름에 오타가 났는지 다시 확인하세요.",
+       "default-skin-not-found-no-skins": "이런! 당신의 위키에 <code dir=\"ltr\">$wgDefaultSkin</code>에 <code>$1</code>(으)로 지정한 기본 스킨은 사용할 수 없습니다.\n\n설치된 스킨은 없습니다.\n\n; 미디어위키를 설치했거나 업그레이드했다면:\n: 아마 git에서 설치했거나, 어떤 다른 방법을 사용하여 직접 설치했을 수 있을 것으로 봅니다. 미디어위키 1.24와 새 버전은 주 저장소에 어떠한 스킨도 포함되어 있지 않습니다. [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org의 스킨 디렉터리]에서 어떤 스킨을 설치해보세요:\n:* 여러 스킨과 확장 기능이 들어 있는 [https://www.mediawiki.org/wiki/Download tarball 설치 프로그램]을 다운로드하세요. 거기서 <code>skins/</code> 디렉터리를 복사하여 붙여 넣을 수 있습니다.\n:* 미디어위키 설치의 <code dir=\"ltr\">skins/</code> 디렉터리 안에 git를 통해 <code>mediawiki/skins/*</code> 저장소 중 하나를 복제하세요.\n: 당신이 미디어위키 개발자이면 당신의 git 저장소를 방해하면 안됩니다. 스킨을 활성화하고 기본값으로 선택하는 방법에 대한 정보에 대해서는 [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: 스킨 설정]을 보세요.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (활성화)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''비활성화''')",
        "mediastatistics": "미디어 통계",
        "mediastatistics-header-text": "텍스트",
        "mediastatistics-header-executable": "실행 파일",
        "mediastatistics-header-archive": "압축 파일",
+       "json-warn-trailing-comma": "뒤 {{PLURAL:$1|쉼표}} $1개가 JSON에서 제거되었습니다",
        "json-error-unknown": "JSON에 문제가 있었습니다. 오류: $1",
        "json-error-depth": "최대 스택 깊이를 초과했습니다",
        "json-error-state-mismatch": "올바르지 않거나 잘못된 형식의 JSON",
index b688d2e..9058ecd 100644 (file)
        "listgrouprights-namespaceprotection-namespace": "نوم جا",
        "listgrouprights-namespaceprotection-restrictedto": "دسرسیا مجاز کاریار سی ویرایشت",
        "trackingcategories": "دما گری دسه یا",
+       "trackingcategories-summary": "ای بلگه نومگه دسه یایی دماگری بیه ئه که وه شکل خودانجوم وه دس ویکی وارسگر پر بوئن . نومیا ونو نها آلشت کردن پیغومیا سامونه ای مرتوط د نومجا {{ns:8}} آلشت دئه با.",
        "trackingcategories-msg": "دماگری دسه",
        "trackingcategories-name": "نوم پیغوم",
        "trackingcategories-desc": "جادیارکنیا گنجایشت دسه",
+       "noindex-category-desc": "ای بلگه وا رباتیا نومگه کاری نبیه و سی یه کلیمه یا جادویی <code><nowiki>__NOINDEX__</nowiki></code> د وه یا د جاگه ای که بیرق مجازه دش هئ.",
+       "index-category-desc": "ای بلگه<code><nowiki>__INDEX__</nowiki></code> که ها دش(و د نومجایی یه که بیرق دش مجازه)،  سی یه وا رباط ما مشگلی ناره که وه شکل عادی نباید با.",
        "broken-file-category-desc": "بلگه مینونه دار یه گل هوم پیوند جانیا خراوه(هوم پیوندی سی جاسازی کردن یه گل جانیا سی گاتی که او جانیا نئئش).",
        "trackingcategories-nodesc": "هیچ شرحی د دسرس نئ.",
        "trackingcategories-disabled": "دسه ناکشتگر بیه",
        "thumbnail_error_remote": "پیغوم خطا $1 :\n$2",
        "djvu_page_error": "بلگه DjVu وه در د حد مجاز",
        "djvu_no_xml": "امکان پیدا کردن جانیا XML سی وه کار گرتن DjVu وجود ناشت.",
+       "thumbnail-temp-create": "نبوئه جانیا موقت بن کلیکی نه راست بکیت",
+       "thumbnail-dest-create": "نبوئه بن کلیکی نه د مقصدش اماییه بکیت",
+       "thumbnail_invalid_params": "بن کلیکی وا پارامتریا نامعتور",
+       "thumbnail_dest_directory": "نبوئه دایرکتوری مقصد نه درست بکیت",
+       "thumbnail_image-type": "نوع عسگ حامیین داری نبوئه",
+       "thumbnail_image-missing": "وه ویر و باور میا که جانیا گم بیه:$1",
        "import": "وامین اوردن بلگه یا",
+       "importinterwiki": "وامین اوردن ترانس ویکی",
        "import-interwiki-sourcewiki": "سرچشمه ویکی:",
        "import-interwiki-sourcepage": "بلگه سرچشمه:",
+       "import-interwiki-history": "ؤرداشتن ویرگار همه وانئریا سی ای بلگه",
        "import-interwiki-templates": "همه چوئه یا",
        "import-interwiki-submit": "وامین اوردن",
        "import-interwiki-namespace": "نومجا مقصد:",
+       "import-interwiki-rootpage": "ریشه بلگه مقصد(دل به حایی):",
        "import-upload-filename": "نوم جانیا:",
        "import-comment": "ویر و باور:",
        "importstart": "د حال و بار وامین اوردن",
        "import-revision-count": "$1 {{جمی:$1|وانئری|وانئریا}}",
        "importnopages": "هیچ بلگه ای وامین نیومائه.",
+       "imported-log-entries": "$1 {{PLURAL:$1|داده وار پهرستنومه|داده وار پهرستنومه یا}} وامین اومائه.",
        "importfailed": "وامین اوردن شکست حرده: <nowiki>$1</nowiki>",
+       "importunknownsource": "نوع سرچشمه وامین اوردن نادیاره",
        "importcantopen": "نبوئه جانیا دئه بیه نه وا بکید",
        "importbadinterwiki": "هوم پیوند مینجاویکی گن",
        "importsuccess": "وامین اوردن تموم بی!",
        "importnofile": "هیچ جانیا دئه بیه ای سوار نبیه.",
+       "importuploaderrorpartial": "د سوارکرد وامین اوردن جانیا شکستی پیش اومائه.\nانازه جانیا د انازه بیشترونه مجاز گپتره.",
+       "importuploaderrortemp": "د سوارکرد جانیا وامین اوردن مشگلی پیش اومائه.\nتابنده موقت گم بیه.",
        "import-parse-failure": "خطا د وااشکافت یه گل وامین اوردن ایکس ام ال",
        "import-noarticle": "هیچ بلگه ای سی وامین اوردن نئ!",
+       "import-nonewrevisions": "وانئرییا وامین اورده نبیه(همه یا د ایسنی هئشو، یا سی پیش اومائن خطا ور نظر نبینه).",
        "xml-error-string": "$1 د خط$2, ستین $3 (byte $4): $5",
        "import-upload": "سوار کرد دونسمنیا ایکس ام ال",
        "import-token-mismatch": "کمبود د دونسمنیا نشینگه.\nلطفن هنی کوششت بکید.",
+       "import-invalid-interwiki": "نبوئه د ویکی دیارکرده چی یی وامین اورد.",
+       "import-error-edit": "بلگه «$1» وامین نیومائه، سی یه که شما نمی تونیت ونه ویرایشت بکیت.",
+       "import-error-create": "بلگه «$1» وامین نیومائه، سی یه که شما نمی تونیت ونه راست بکیت.",
+       "import-error-interwiki": "بلگه «$1» وامین نیومائه، سی یه که نوم وه سی یه گل هوم پیوندگری خارجی اماییه کاری بیه(مینجا ویکی).",
+       "import-error-special": "بلگه «$1» وامین نیومائه، سی یه که وه مال وه یه گل نومجا خاصه که او بلگه یا صلادار نئین.",
+       "import-error-invalid": "بلگه \"$1\"  سی یه که نامعتور بیین نومش ممکن بی د ویکی وامین اورده نبیه.",
+       "import-error-unserialize": "نبوئه وه دراوردن بلگه $2 د بلگه «$1» د شکل رازینه کاری بیه نه انجوم بییت.چؤ اومائه که نسقه ای د مدل مینونه $3 وه کار گرته که وه د شکل $4 رازینه کاری بیه.",
+       "import-options-wrong": "{{PLURAL:$2|جزئیات|جزئیات}} اشتوا: <nowiki>$1</nowiki>",
+       "import-rootpage-invalid": "ریشه دئه بیه د بلگه یه گل سرون نامعتوره.",
+       "import-rootpage-nosubpage": "نومجا \"$1\" بلگه پایه صلا زیر بلگه نه نمی یه.",
        "importlogpage": "پهرستنومه دئن",
+       "importlogpagetext": "وامین اوردن بلگه یا وا ویرگارچه ویرایشت ونو د ویکی یا هنی",
+       "import-logentry-upload": "[[$1]] نه د طریق سوارکرد جانیا وامین اورد",
+       "import-logentry-upload-detail": "$1 {{جمی:$1|وانئری|وانئریا}} وامین اومانه",
+       "import-logentry-interwiki": "$1 نه تراویکی کرد",
+       "import-logentry-interwiki-detail": "$1 {{جمی:$1|وانئری|وانئریا}} د $2 وامین اومائنه",
        "javascripttest": "ازمایشت کردن جاوا اسکریپت",
+       "javascripttest-title": "د حال انجوم دئن ازمایشتیا $1",
+       "javascripttest-pagetext-noframework": "ای بلگه سی انجوم دئن ازمایشتیا جاوا اسکریپت اماییه کاری بیه.",
+       "javascripttest-pagetext-unknownframework": "چوئه کار نادیار ازمایشت \"$1\"",
+       "javascripttest-pagetext-frameworks": "لطفن یه گل د چوئه یا ازمایشت هاری نه انتخاو بکیت :$1",
+       "javascripttest-pagetext-skins": "یه گل پوسه نه سی انجوم دئن ازمایشتا انتخاو بکیت:",
+       "javascripttest-qunit-intro": "[$1 مستندیا ازمایشت] نه د mediawiki.org سیل بکیت.",
+       "javascripttest-qunit-heading": "کومله ازمایشت QUnit جاوااسکریپت سی ویکی وارسگر",
        "tooltip-pt-userpage": "بلگه كارورتو",
+       "tooltip-pt-anonuserpage": "بلگه کاریاری تیرنشون آی پی ای که دش ویرایشت می کید",
        "tooltip-pt-mytalk": "بلگه قسه كردن شما",
+       "tooltip-pt-anontalk": "چک چنه دباره ویرایشتیا ای تیرنشون آی پی",
        "tooltip-pt-preferences": "اولويتيا شما",
        "tooltip-pt-watchlist": "نوم نوشت د بلگه يايی كه شما آلشتاشونه پيگئری  ميكيد",
        "tooltip-pt-mycontris": "يه گل د هومياريا شما",
        "tooltip-ca-viewsource": "ای بلگه حفاظت بيه.\nشما تونيت سرچمه ش بئوينيت",
        "tooltip-ca-history": "دوواره ديئن ای بلگه",
        "tooltip-ca-protect": "ای بلگه نه حفاظت بكيد",
+       "tooltip-ca-unprotect": "پر و پیم گیری د ای بلگه نه آلشت بکیت",
        "tooltip-ca-delete": "ای بلگه نه پاکسا کو",
+       "tooltip-ca-undelete": "د نو زنه کردن ویرایشتیا ری ای بلگه دما یه که پاکساگری بان",
        "tooltip-ca-move": "ای بگله نه جا وه جا كو",
        "tooltip-ca-watch": "اضاف کردن ای بلگه وه نوم نوشت پیگئریاتو",
        "tooltip-ca-unwatch": "ورداشتن ای بلگه وه نوم نوشت پیگئریاتو",
        "tooltip-watch": "ای بلگه نه د سیل برگتو اضاف بکید",
        "tooltip-watchlistedit-normal-submit": "ؤرداشتن سرونیا",
        "tooltip-watchlistedit-raw-submit": "وه هنگوم سازی سیل برگ",
+       "tooltip-recreate": "د نو راس کردن بلگه بی یه که و پاکساگری دماتر وه سیل بکیم",
        "tooltip-upload": "شرو د سوار کرد",
        "tooltip-rollback": "\"ورگشتن\" لرستن د حالت اول  سی ای بلگه  که سی  يه كه هومياری  نيايی اصلاح بيه وا يه پورنسن",
        "tooltip-undo": "انجوم نگرتن ای ویرایشت ورگن و همه فرمیا ویرایشت تانه که حالت پیش سیل واکو.یه اجازه میئه سی اضاف کردن یه دلیل د چکسته.",
        "anonymous": "ناشناس {{جمی:$1|کارور|کاروریا}}  {{سیل جا}}",
        "siteuser": "{{نوم سیلجا}} کارور $1",
        "anonuser": "{{سیل جا}}  کارور ناشناس $1",
+       "lastmodifiedatby": "ای بلگه آخری بار د $1,$2 وه دس $2 آلشت دئه بیه.",
+       "othercontribs": "د اساس کار وا $1.",
        "others": "دیه رون",
        "siteusers": "{{نوم سیل جا}} {{جمی:$2|کارور|کاروریا}} $1",
+       "anonusers": "{{نوم سیل جا}} نادیار {{جمی:$2|کاریار|کاریاریا}} $1",
        "creditspage": "اعتوار بلگه",
+       "nocredits": "دونسمنیا راس کننه یا ای بلگه د دسرس نئ",
+       "spamprotectiontitle": "فیلتر پر و پیم گری د اسپم",
+       "spamprotectionmatch": "نیسسه هاری چی ای یه که فیلتر اسپم ایما نه ونه د کار: $1",
+       "spambot_username": "اسپم پاک کن ویکی وارسگر",
+       "spam_reverting": "واگردونی وه آخری نسقه ای که هوم پیوندی وه $1 ناره.",
+       "spam_blanking": "همه وانئریایی که مینونه دار هوم پیوند $1 هئن، دارن حالی بوئن",
+       "spam_deleting": "همه وانئریایی که مینونه دار هوم پیوند $1 هئن، دارن پاکساگری بوئن",
+       "simpleantispam-label": "وارسی ضد اسپم.\nای \"جاگه\" نه پر نکیت!",
        "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-robot-policy": "نومگه کاری وا رباتیا",
        "pageinfo-robot-index": "صلادار",
        "pageinfo-robot-noindex": "بی صلا",
        "pageinfo-views": "شماره دیئن یا",
        "pageinfo-watchers": "شماره سیل کننه بلگه یا",
+       "pageinfo-few-watchers": "کمتر د $1 {{PLURAL:$1|سیل کننه|سیل کننه یا}}",
        "pageinfo-redirects-name": "شماره واگردونیا ای بلگه",
        "pageinfo-redirects-value": "$1",
+       "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": "$1{{جمی:$1|دسه|دسه يا}} قام بیه",
+       "pageinfo-templates": "{{PLURAL:$1|چوئه|چوئه یا}} وه کار گرته بیه($1)",
+       "pageinfo-transclusions": "{{PLURAL:$1|بلگه|بلگه یا}} وه کار گرته بیه د ($1)",
        "pageinfo-toolboxlink": "دونسمنیا بلگه",
        "pageinfo-redirectsto": "واگردونی سی",
        "pageinfo-redirectsto-info": "دونسمنیا",
        "pageinfo-category-pages": "شماره بلگيا",
        "pageinfo-category-subcats": "شماره زیر دسه یا",
        "pageinfo-category-files": "شماره جانیایا",
+       "markaspatrolleddiff": "نشو دار کردن چی سردیاری بیه",
+       "markaspatrolledtext": "ای بلگه نه چی بلگه ای که سردیاری کرده با نشودار کو",
+       "markedaspatrolled": "نشو دار کردن چی سردیاری بیه",
+       "rcpatroldisabled": "سردیاری کردن سی آلشتیا ایسنی ناکنشتگر بیه",
+       "rcpatroldisabledtext": "خصوصیت سردیاری کردن د ری آلشتیا ایسنی تازه ای یا ناکشتگر بیه.",
+       "markedaspatrollederror": "نبوئه چی یه گل سردیاری کرده نشودار با",
+       "markedaspatrollederrortext": "شما واس سی نشودار کردن یه گل وانئری چی سردیاری کرده ونه تیار بکیت.",
+       "markedaspatrollederror-noautopatrol": "شما صلا یه نه که آلشتیا خوتونه چی یه که سردیاری کرده بان ناریت.",
+       "markedaspatrollednotify": "آلشتیایی که مال $1 چی یه گل چی سردیاری کرده نشودار بینه.",
+       "markedaspatrollederrornotify": "نشودار کردن چی نشودار بیه شکست حرده",
        "patrol-log-page": "پهرستنومه گشتن",
+       "patrol-log-header": "یه پهرستنومه وانئریا سردیاری کرده هئ.",
+       "log-show-hide-patrol": "$1 پهرستنومه سردیاری کردن",
+       "deletedrevision": "وانئری دماتری پاکسابیه د $1",
        "filedeleteerror-short": "خطا پاک نبیئن جانیا:$1",
+       "filedeleteerror-long": "د گات پاکسا کردن جانیا یه گل خطا پیش اوما:\n\n\n$1",
+       "filedelete-missing": "نبوئه جانیا \"$1\" نه پاکسا بکیت سی یه که وه وجود ناره.",
+       "filedelete-old-unregistered": "وانئری جانیا تیارکرده \"$1\" د رسینه جا وجود ناره.",
+       "filedelete-current-unregistered": "جانیا تیارکرده \"$1\" د رسینه جا نئیش.",
+       "filedelete-archive-read-only": "نشونگه مال دیارکردن ($1) د لا سرور قاول نیسنن نئ.",
        "previousdiff": "← ويرايشت كۈهنه تر",
        "nextdiff": "ويرايشت تازه تر",
+       "imagemaxsize": "انازه عسگ:<br /><em>(سی شرح جانیا بلگه یا)</em>",
        "thumbsize": "انازه بن کلکی:",
        "widthheight": "$1 × $2",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|بلگه|بلگه یا}}",
        "file-info-size-pages": "$1 × $2 pixels, انازه جانیا: $3, MIME type: $4, $5 {{PLURAL:$5|بلگه|بلگه یا}}",
        "file-nohires": "عسك ون بالاتري دش ني",
        "svg-long-desc": "اس وی جی فايل.نومنا $1 $2 پيكسل",
+       "svg-long-desc-animated": "جانیا جمشدار اس وی جی .نومنا $1 × $2 پيكسل،انازه جانیا:$3",
+       "svg-long-error": "جانیا اس وی جی نامعتور:$1",
        "show-big-image": "فایل اصلی",
+       "show-big-image-preview": "انازه ای پیش سیل:$1.",
+       "show-big-image-other": "هنی{{PLURAL:$2|گپ نما کردن|گپ نما کردنیا}}: $1.",
        "show-big-image-size": "$1 × $2 pixels",
        "file-info-gif-looped": "حلقه دار",
        "file-info-gif-frames": "$1 {{PLURAL:$1|فریم|فریمیا}}",
        "file-info-png-repeat": "$1 بازی کرده{{جمی:$1|وخت|وختیا}}",
        "file-info-png-frames": "$1 {{PLURAL:$1|فریم|فریمیا}}",
        "newimages": "عسگدونی جانیایا تازه",
+       "imagelisttext": "د هار نومگه <strong>$1</strong> {{PLURAL:$1|جانیا|جانیایا}} اماییه جا بیه$2.",
        "newimages-summary": "ای بلگه یا ویجه همه جانیایا سوار بیه نه نشو می ئین.",
        "newimages-legend": "فیلتر",
        "newimages-label": "نوم جانیا(یا بشقی د وه):",
+       "newimages-showbots": "سوارکردیا نه وا بوتیا نشو بیه",
        "noimages": "هیچی سی دیئن نئ",
        "ilsubmit": "پی جوری",
        "bydate": "وا گات",
        "bad_image_list": "دونسمنديانه وه ای شلگ وارد بكيت:\n\nفقط سرخط يایی که وا * شرو بوئن د وير گرته بوئن. اولی چسب ون مئن هر سرخط، باید چسب ونی وه یک عسگ گن با.\nچسب ونيا نيایی د همو سرخط، وه عنوان چيا استثنادار د وير گرته بوئن",
        "metadata": "داديا  فره گپ",
        "metadata-help": "ای فایل شومل دونسمنیا هنی یه.شایت د دیربین رقم ون یا اسکنری که سی راس کردنشو استفاده بیه،وه ایچه اضاف بیه",
+       "metadata-expand": "نشو دئن جزییات دمادیسگری",
+       "metadata-collapse": "قام کردن جزییات دمادیسگری",
        "metadata-fields": "رشته یا گپ دونسمنیا که د ای پیغوم نوم ون بینه شومل بلگه عسگ ن که وختی که جدول گپ دونسمنیا وا بوئه نشون دئیه بوئن.\nچی یا هنی سی یه که پیش فرضن قام بوئن.\n*راست کو\n*مدل\n*دم وخت اصل\n*وخت آشگار\n*اف ان شماره\n*ایزو نرخ من سرعت\n*فوکالنس\n*هنرمن\n*کپی رایت\n*حالت جی پی اس \n*جی پی اس گپ حالت\n*جی پی اس همه حالت",
        "metadata-langitem": "<strong>$2:</strong> $1",
        "metadata-langitem-default": "$1",
        "exif-imagewidth": "پئنا",
        "exif-imagelength": "بلنگی",
+       "exif-bitspersample": "نقطه یا سی هر اندوم",
+       "exif-compression": "شیوات جم و جور کردن",
+       "exif-photometricinterpretation": "ترکیو پیکسل",
        "exif-orientation": "سرچشمه",
+       "exif-samplesperpixel": "شماره اندومیا",
        "exif-planarconfiguration": "سرجایک کردن رسینه",
+       "exif-ycbcrsubsampling": "نسوت زیرنمونه Y وه C",
+       "exif-ycbcrpositioning": "جاگری کردن Y و C",
+       "exif-xresolution": "گپ نما کردن د آسو",
+       "exif-yresolution": "گپ نما کردن د وارو",
        "exif-stripoffsets": "جاگه رسینه یا عسگ",
+       "exif-rowsperstrip": "انازه ردیفیا سی هر نوار",
        "exif-datetime": "آلشت دئن وخت و دمون جانیا",
        "exif-imagedescription": "نوم عسگ",
        "exif-make": "سازنه دیربین",
index bf01d49..dc1747b 100644 (file)
        "listgrouprights-namespaceprotection-header": "Ограничувања за именски простори",
        "listgrouprights-namespaceprotection-namespace": "Именски простор",
        "listgrouprights-namespaceprotection-restrictedto": "Права што им овозможуваат на корисниците да уредуваат",
-       "trackingcategories": "Следачки категории",
-       "trackingcategories-summary": "Ð\9dа Ñ\81Ñ\82Ñ\80аниÑ\86ава Ñ\81е Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ð¸ Ñ\81ледачки категории што автоматски се пополнуваат од програмот на МедијаВики. Нивните називи можат да се сменат со измена на соодветните системски пораки во именскиот простор {{ns:8}}.",
-       "trackingcategories-msg": "Следачка категорија",
+       "trackingcategories": "Следечки категории",
+       "trackingcategories-summary": "Ð\9dа Ñ\81Ñ\82Ñ\80аниÑ\86ава Ñ\81е Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ð¸ Ñ\81ледечки категории што автоматски се пополнуваат од програмот на МедијаВики. Нивните називи можат да се сменат со измена на соодветните системски пораки во именскиот простор {{ns:8}}.",
+       "trackingcategories-msg": "Следечка категорија",
        "trackingcategories-name": "Назив на пораката",
        "trackingcategories-desc": "Критериуми за вклучување",
        "noindex-category-desc": "Роботите не ја индексираат страницава бидејќи го содржи волшебниот збор <code><nowiki>__NOINDEX__</nowiki></code> и се наоѓа во именски простор кајшто е дозволен.",
index 83efa6d..1a65990 100644 (file)
        "hidetoc": "aħbi",
        "collapsible-collapse": "Aħbi",
        "collapsible-expand": "Espandi",
+       "confirmable-confirm": "Inti{{GENDER:$1|żgur|żgura}}?",
+       "confirmable-yes": "Iva",
+       "confirmable-no": "Le",
        "thisisdeleted": "Uri jew ġib lura $1?",
        "viewdeleted": "Ara $1?",
        "restorelink": "{{PLURAL:$1|waħda mill-modifiki mħassra|$1 modifiki mħassra}}",
        "no-null-revision": "Ma setghitx tinħoloq reviżjoni nulla ġdida għall-paġna \"$1\"",
        "badtitle": "Titlu ħażin",
        "badtitletext": "It-titlu tal-paġna rikjesta huwa invalidu, vojt, jew ġej minn żball fil-ħolqa bejn siti wiki differenti jew verżjonijiet ta' lingwi differenti tal-istess sit. Jista' wkoll ikollu wieħed jew aktar karattri li ma jistgħux jintużaw għat-titli.",
-       "perfcached": "L-informazzjoni li jmiss huwa kopja ''cache'' u jista' ma jkunx aġġornat. A maximum of {{PLURAL:$1|one result is|$1 results are}} available in the cache.",
-       "perfcachedts": "Id-dati segwenti huma estratt ta' kopja cache tad-database. L-aħħar aġġornament: $1. A maximum of {{PLURAL:$4|one result is|$4 results are}} available in the cache.",
+       "perfcached": "L-informazzjoni li jmiss ġejja minn kopja ''cache'' u tista' ma tkunx aġġornata. Massimu ta'  {{PLURAL:$1|riżultat wieħed hu|$1 riżultati huma}} disponibbli fil-\"cache\".",
+       "perfcachedts": "Id-dejta li jmiss ġejja minn kopja \"cache\" u l-aħħar aġġornament kien: $1. Mhux aktar minn {{PLURAL:$4|riżultat wieħed hu|$4 riżultati huma}} disponibbli fil-\"cache\".",
        "querypage-no-updates": "Aġġornamenti għal din il-paġna huma temporalment sospesi. L-Informazzjoni hawnhekk preżentament mhux qiegħed jiġi aġġornat.",
        "viewsource": "Ara s-sors",
        "viewsource-title": "Ara s-sors ta' $1",
        "actionthrottled": "Azzjoni miżmuma",
        "actionthrottledtext": "Bħala miżura għal kontra l-ispam, inti limitat li tagħmel din l-azzjoni għal ħafna drabi f'spazju ta' ħin żgħir, u inti qbiżt dan il-limitu.\nJekk jogħġbok erġa' prova fi ftit minuti oħra.",
-       "protectedpagetext": "Din il-paġna ġiet protetta sabiex twaqqaf kull tip ta' modifika.",
+       "protectedpagetext": "Din il-paġna ġiet protetta sabiex ma ssirx xi modifika jew xi azzjoni oħra.",
        "viewsourcetext": "Tista' tara u tikkopja s-sors ta' din il-paġna:",
        "viewyourtext": "Tista' tara u tikkopja s-sors tal-'''modifiki tiegħek''' fuq din il-paġna:",
-       "protectedinterface": "Din il-paġna għanda element li tagħmel parti mill-interfaċċa tal-utent tas-software, u għaldaqstant ġiet protetta sabiex ma jkunx hemm abbuż.",
+       "protectedinterface": "Din il-paġna tipprovdi test ta' interfaċċa għas-softwer fuq dan il-wiki, u għaldaqstant ġiet protetta sabiex ma jkunx hemm abbuż.\nBiex iżżid jew tibdel traduzzjonijiet għall-wikijiet kollha uża [//translatewiki.net/ translatewiki.net], il-proġett ta' lokalizzazzjoni ta' MediaWiki.",
        "editinginterface": "'''Avviż:''' Qiegħed tagħmel modifiki lejn paġna li qiegħda tintuża biex tipprovdi interfaċċa għall-messaġġi tas-software. Kull modifika f'din il-paġna se taffetwa l-apparenza tal-faċċata tal-utenti kollha. Għat-traduzzjonijiet, ikkunsidra l-possibilità li tuża  [//translatewiki.net/wiki/Main_Page?setlang=mt translatewiki.net], il-proġett MediaWiki għal-lokalizzazzjoni.",
        "cascadeprotected": "Din il-paġna ġiet protetta mill-modifiki, minħabba li tinkludi {{PLURAL:$1|paġni, li huwa|paġni, li huma}} protetti bil-preferenza tal-\"kaskata\" mixewla:\n$2",
        "namespaceprotected": "Inti m'għandhekx il-permess li timodifika paġni fin-''namespace'' '''$1''.",
index 0416b5f..33410bd 100644 (file)
        "tags": "Tag 'e cagnamiento valide",
        "tag-filter": "Filtra ppe [[Special:Tags|etichetta]]:",
        "tag-filter-submit": "Filtra",
+       "tags-title": "Etichette",
+       "tags-tag": "Nomme 'e ll'etichetta",
+       "tags-active-header": "Attivo?",
        "tags-active-yes": "Sì",
        "tags-active-no": "No",
        "tags-edit": "càgna",
        "tags-hitcount": "$1 {{PLURAL:$1|cagnamiento|cagnamiente}}",
+       "compare-page1": "Paggena 1",
+       "compare-page2": "Paggena 2",
+       "compare-rev1": "Vversione 1",
+       "compare-rev2": "Vversione 2",
+       "htmlform-submit": "Manna",
        "htmlform-no": "No",
        "htmlform-yes": "Sì",
+       "htmlform-cloner-delete": "Rimuove",
        "rightsnone": "(nisciuno)",
+       "feedback-message": "Mmasciata:",
        "feedback-cancel": "Canciella",
+       "feedback-close": "Fatto",
        "searchsuggest-search": "Truova",
        "api-error-filename-tooshort": "'O nomme d' 'o file è troppo curto.",
        "api-error-filetype-banned": "Stu tipo 'e file nun è permesso.",
        "limitreport-cputime-value": "$1 {{PLURAL:$1|secondo|seconde}}",
        "limitreport-walltime-value": "$1 {{PLURAL:$1|secondo|seconde}}",
        "limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|byte|byte}}",
+       "expand_templates_ok": "OK",
        "expand_templates_preview": "Anteprimma",
        "pagelang-name": "Paggena",
+       "pagelang-language": "Lengua",
+       "pagelang-select-lang": "Selezziona lengua",
        "mediastatistics-header-unknown": "Scanusciuto",
        "mediastatistics-header-audio": "Audio",
        "mediastatistics-header-video": "Video",
+       "mediastatistics-header-office": "Ufficio",
+       "mediastatistics-header-text": "Testuale",
        "json-error-unknown": "Ce sta nu probblema c' 'o JSON. Errore: $1",
        "json-error-state-mismatch": "Valore malamente furmato o nun buono p' 'o JSON",
        "json-error-syntax": "Errore 'e sintasse",
index 6a9519e..8b72bad 100644 (file)
        "youremail": "E-post:",
        "username": "{{GENDER:$1|Brukernavn}}:",
        "prefs-memberingroups": "{{GENDER:$2|Medlem}} i følgende {{PLURAL:$1|gruppe|grupper}}:",
-       "prefs-registration": "Registreringstid:",
+       "prefs-registration": "Registreringstidspunkt:",
        "yourrealname": "Virkelig navn:",
        "yourlanguage": "Språk:",
        "yourvariant": "Språkvariant for innhold:",
index f2a09e3..b031bdc 100644 (file)
        "changepassword": "ਪਛਾਣ-ਸ਼ਬਦ ਬਦਲੋ",
        "resetpass_announce": "ਲਾਗਇਨ ਪੂਰਾ ਕਰਨ ਲਈ ਤੁਹਾਨੂੰ ਨਵਾਂ ਪਾਸਵਰਡ ਬਣਾਉਣਾ ਪਵੇਗਾ।",
        "resetpass_header": "ਖਾਤੇ ਦਾ ਪਛਾਣ-ਸ਼ਬਦ ਬਦਲੋ",
-       "oldpassword": "ਪà©\81ਰਾਣਾ à¨ªà¨¾à¨¸à¨µà¨°à¨¡:",
+       "oldpassword": "ਪà©\81ਰਾਣਾ à¨ªà¨\9bਾਣ-ਸ਼ਬਦ:",
        "newpassword": "ਨਵਾਂ ਪਾਸਵਰਡ:",
        "retypenew": "ਨਵਾਂ ਪਾਸਵਰਡ ਮੁੜ-ਲਿਖੋ:",
        "resetpass_submit": "ਪਾਸਵਰਡ ਸੈੱਟ ਕਰੋ ਅਤੇ ਲਾਗਇਨ ਕਰੋ",
        "mywatchlist": "ਨਿਗਰਾਨੀ-ਲਿਸਟ",
        "watchlistfor2": "$1 $2 ਲਈ",
        "nowatchlist": "ਤੁਹਾਡੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵਿਚ ਕੋਈ ਚੀਜ਼ ਨਹੀਂ ਹੈ।",
-       "watchlistanontext": "ਆਪਣੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵਿਚਲੀਆਂ ਚੀਜ਼ਾਂ ਵੇਖਣ ਜਾਂ ਸੋਧਣ ਲਈ ਮਿਹਰਬਾਨੀ ਕਰਕੇ $1।",
+       "watchlistanontext": "ਆਪਣੀ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵਿਚਲੀਆਂ ਚੀਜ਼ਾਂ ਵੇਖਣ ਜਾਂ ਸੋਧਣ ਲਈ ਮਿਹਰਬਾਨੀ ਕਰਕੇ ਦਾਖ਼ਲ ਹੋਵੋ।",
        "watchnologin": "ਲਾਗਇਨ ਨਹੀਂ",
        "addwatch": "ਨਿਗਰਾਨੀ-ਲਿਸਟ ’ਚ ਜੋੜੋ",
        "addedwatchtext": "ਪੰਨਾ \"[[:$1]]\" ਤੁਹਾਡੀ [[Special:Watchlist|ਧਿਆਨਸੂਚੀ]] ’ਚ ਜੁੜ ਚੁੱਕਾ ਹੈ।\nਇਸ ਅਤੇ ਇਸਦੇ ਚਰਚਾ ਪੰਨੇ ’ਚ ਹੋਈਆਂ ਬਦਲੀਆਂ ਓਥੇ ਵਖਾਈ ਦੇਣਗੀਆਂ ਅਤੇ ਵੇਖਣ ਦੀ ਸੌਖ ਲਈ [[Special:RecentChanges|ਹਾਲ ਹੀ ’ਚ ਹੋਈਆਂ ਬਦਲੀਆਂ]] ਵਿੱਚ ਇਹ ਪੰਨਾ '''ਗੂੜ੍ਹਾ''' ਦਿਖਾਈ ਦੇਵੇਗਾ।",
        "mediastatistics-header-audio": "ਆਡੀਓ",
        "mediastatistics-header-video": "ਵੀਡੀਓਆਂ",
        "mediastatistics-header-office": "ਦਫ਼ਤਰ",
-       "mediastatistics-header-text": "ਲਿਖਤੀ"
+       "mediastatistics-header-text": "ਲਿਖਤੀ",
+       "json-error-syntax": "ਵਾਕ-ਵਿਉਂਤ 'ਚ ਦੋਸ਼"
 }
index c362533..613dcfb 100644 (file)
        "recentchanges-legend-heading": "'''Legenda:'''",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (zobacz też [[Special:NewPages|listę nowych stron]])",
        "recentchanges-legend-plusminus": "(''±123'')",
-       "rcnotefrom": "Poniżej {{PLURAL:$5|pokazano zmianę|pokazano zmiany}} wykonane po <strong>$3, $4</strong> (nie więcej niż '''$1''' pozycji).",
+       "rcnotefrom": "Poniżej {{PLURAL:$5|pokazano zmianę|pokazano zmiany}} {{PLURAL:$5|wykonaną|wykonane}} po <strong>$3, $4</strong> (nie więcej niż '''$1''' pozycji).",
        "rclistfrom": "Pokaż nowe zmiany od $3 $2",
        "rcshowhideminor": "$1 drobne zmiany",
        "rcshowhideminor-show": "Pokaż",
index b017e4b..2fae44f 100644 (file)
        "action-pagelang": "cangé la lenga dla pàgina",
        "log-name-pagelang": "Argistr dij cangiament ëd lenga",
        "log-description-pagelang": "Cost-sì a l'é n'argistr dij cangiament ant le lenghe dle pàgine.",
-       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|a l'ha cangià}} la lenga dla pàgina $3 da $4 a $5."
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|a l'ha cangià}} la lenga dla pàgina $3 da $4 a $5.",
+       "default-skin-not-found": "Tension! La pel predeterminà për soa wiki, definìa an <code dir=\"ltr\">$wgDefaultSkin</code> tanme <code>$1</code>, a l'é nen disponìbil.\n\nSoa anstalassion a smija anclude le pel sì-dapress. Ch'a vëdda [https://www.mediawiki.org/wiki/Manual:Skin_configuration ël manual ëd configurassion dle pel] për d'anformassion su coma abiliteje e serne col apredefinìa.\n\n$2\n\n; S'a l'ha pen-a anstalà MediaWiki:\n: A l'é probàbil che a l'abia anstalalo da git, o diretaman dal còdes sorgiss an n'àutra manera. A l'é normal. Ch'a preuva a anstalé dle pej da [https://www.mediawiki.org/wiki/Category:All_skins la lista dle pel Ëd mediawiki.org], parèj:\n:* Dëscariand l' [https://www.mediawiki.org/wiki/Download archivi tar ëd l'anstalador], ch'a comprend vàire pel e estension. A peul copié e ancolé la lista dle <code>pel/</code> d'ambelelà.\n:* Clonand un dij depòsit <code>mediawiki/skins/*</code> via git ant la lista <code dir=\"ltr\">skins/</code> ëd soa anstalassion ëd MediaWiki.\n: Sòn a dovrìa nen antërferì con sò depòsit git si chiel a l'é un dësvlupador ëd MediaWiki.\n\n; S'a l'ha pen-a agiornà MediaWiki:\n: MediaWiki 1.24 e pi neuv a përmet pi nen an automàtich le pel anstalà (ch'a vëdda [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery manual an sla dëscuverta automàtica dle pel). A peul copié le linie sì-dapress an <code>LocalSettings.php</code> për abilité tute le pel ch'a son anstalà al moment:\n\n<pre dir=\"ltr\">$3</pre>\n\n; S'a l'ha pen-a modifivà <code>LocalSettings.php</code>:\n: Ch'a verìfica torna ël nòm ëd dle pej për evité ij boro."
 }
index 31bab55..99aecb0 100644 (file)
        "pager-older-n": "This is part of the navigation message on the top and bottom of Special pages which are lists of things in date order, e.g. the User's contributions page. It is passed as the first argument of {{msg-mw|Viewprevnext}}. $1 is the number of items shown per page.",
        "suppress": "{{Identical|Oversight}}",
        "querypage-disabled": "On special pages that use expensive database queries but are not cacheable, this message is displayed when 'miser mode' is on (i.e. no expensive queries allowed).",
+       "apihelp": "{{doc-special|ApiHelp}}",
+       "apihelp-summary": "{{doc-specialpagesummary|ApiHelp}}",
+       "apihelp-no-such-module": "Used as an error message if the requested API module is not found.\n\nParameters:\n* $1 - Requested module name",
+       "apihelp-link": "{{notranslate}} Used to construct a link to [[Special:ApiHelp]]\n\nParameters:\n* $1 - module to link\n* $2 - link text",
        "booksources": "{{doc-special|BookSources}}\n\n'''This message shouldn't be changed unless it has serious mistakes.'''\n\nIt's used as the page name of the configuration page of [[Special:BookSources]]. Changing it breaks existing sites using the default version of this message.\n\nSee also:\n* {{msg-mw|Booksources|title}}\n* {{msg-mw|Booksources-text|text}}",
        "booksources-summary": "{{doc-specialpagesummary|booksources}}",
        "booksources-search-legend": "Box heading on [[Special:BookSources|book sources]] special page. The box is for searching for places where a particular book can be bought or viewed.",
        "accesskey-pt-mycontris": "{{doc-accesskey}}\nSee also:\n* {{msg-mw|Mycontris}}\n* {{msg-mw|Accesskey-pt-mycontris}}\n* {{msg-mw|Tooltip-pt-mycontris}}",
        "accesskey-pt-login": "{{doc-accesskey}}",
        "accesskey-pt-logout": "{{doc-accesskey}}\nSee also:\n* {{msg-mw|Logout}}\n* {{msg-mw|Accesskey-pt-logout}}\n* {{msg-mw|Tooltip-pt-logout}}",
+       "accesskey-pt-createaccount": "{{doc-accesskey}}",
        "accesskey-ca-talk": "{{doc-accesskey}}\nSee also:\n* {{msg-mw|Talk}}\n* {{msg-mw|Accesskey-ca-talk}}\n* {{msg-mw|Tooltip-ca-talk}}",
        "accesskey-ca-edit": "{{doc-accesskey}}\nSee also:\n* {{msg-mw|Edit}}\n* {{msg-mw|Accesskey-ca-edit}}\n* {{msg-mw|Tooltip-ca-edit}}",
        "accesskey-ca-addsection": "{{doc-accesskey}}\nSee also:\n* {{msg-mw|Addsection}}\n* {{msg-mw|Accesskey-ca-addsection}}\n* {{msg-mw|Tooltip-ca-addsection}}",
        "tooltip-pt-preferences": "Tooltip shown when hovering over the {{msg-mw|Mypreferences}} link in your personal toolbox (upper right side).\n\nSee also:\n* {{msg-mw|Mypreferences}}\n* {{msg-mw|Accesskey-pt-preferences}}\n* {{msg-mw|Tooltip-pt-preferences}}\n{{Identical|Preferences}}",
        "tooltip-pt-watchlist": "Tooltip shown when hovering over the {{msg-mw|Mywatchlist}} link in your personal toolbox (upper right side).\n\nSee also:\n* {{msg-mw|Mywatchlist}}\n* {{msg-mw|Accesskey-pt-watchlist}}\n* {{msg-mw|Tooltip-pt-watchlist}}",
        "tooltip-pt-mycontris": "Tooltip shown when hovering over the {{msg-mw|Mycontris}} link in your personal toolbox (upper right side).\n\nSee also:\n* {{msg-mw|Mycontris}}\n* {{msg-mw|Accesskey-pt-mycontris}}\n* {{msg-mw|Tooltip-pt-mycontris}}",
-       "tooltip-pt-login": "Tooltip shown when hovering over the link 'Log in / create account' in the upper right corner show on all pages while not logged in.",
+       "tooltip-pt-login": "Tooltip shown when hovering over the link 'Log in' in the upper right corner show on all pages while not logged in.",
        "tooltip-pt-logout": "Tooltip shown when hovering over the {{msg-mw|Logout}} link in your personal toolbox (upper right side).\n\nSee also:\n* {{msg-mw|Logout}}\n* {{msg-mw|Accesskey-pt-logout}}\n* {{msg-mw|Tooltip-pt-logout}}\n{{Identical|Log out}}",
+       "tooltip-pt-createaccount": "Tooltip shown when hovering over the link 'Create account' in the upper right corner show on all pages while not logged in.",
        "tooltip-ca-talk": "Tooltip shown when hovering over the {{msg-mw|Talk}} tab.\n\nA 'content page' is a page that forms part of the purpose of the wiki. It includes the main page and pages in the main namespace and any other namespaces that are included when the wiki is customised. For example on Wikimedia Commons 'content pages' include pages in the file and category namespaces. On Wikinews 'content pages' include pages in the Portal namespace. For a technical definition of 'content namespaces' see [[mw:Manual:Using_custom_namespaces#Content_namespaces|MediaWiki]].\n\nPossible alternatives to the word 'content' are 'subject matter' or 'wiki subject' or 'wiki purpose'.\n\nSee also:\n* {{msg-mw|Talk}}\n* {{msg-mw|Accesskey-ca-talk}}\n* {{msg-mw|Tooltip-ca-talk}}\n{{Identical|Content page}}",
        "tooltip-ca-edit": "The tooltip when hovering over the {{msg-mw|Edit}} tab.\n\nSee also:\n* {{msg-mw|Edit}}\n* {{msg-mw|Accesskey-ca-edit}}\n* {{msg-mw|Tooltip-ca-edit}}",
        "tooltip-ca-addsection": "Tooltip shown when hovering over the \"addsection\" tab (shown on talk pages).\n\nSee also:\n* {{msg-mw|Addsection}}\n* {{msg-mw|Accesskey-ca-addsection}}\n* {{msg-mw|Tooltip-ca-addsection}}",
index a6e02d3..901f38c 100644 (file)
@@ -70,7 +70,8 @@
                        "Agilight",
                        "Oleg3280",
                        "Nirovulf",
-                       "Striking Blue"
+                       "Striking Blue",
+                       "Fitoschido"
                ]
        },
        "tog-underline": "Подчёркивание ссылок:",
        "change-blocklink": "изменить блокировку",
        "contribslink": "вклад",
        "emaillink": "отправить письмо",
-       "autoblocker": "Автоблокировка из-за того, что ваш IP-адрес недавно использовал «[[User:$1|$1]]».\nПричина блокировки $1ː «$2»",
+       "autoblocker": "Автоблокировка из-за того, что ваш IP-адрес недавно использовал «[[User:$1|$1]]».\nПричина блокировки $1: «$2»",
        "blocklogpage": "Журнал блокировок",
        "blocklog-showlog": "{{GENDER:$1|Этот участник уже блокировался|Эта участница уже блокировалась}} ранее.\nНиже приведён журнал блокировок:",
        "blocklog-showsuppresslog": "{{GENDER:$1|Этот участник уже заблокирован и скрыт|Эта участница уже заблокирована и скрыта}}. Журнал сокрытий приведён ниже:",
index 988f541..06d214f 100644 (file)
        "passwordreset-capture-help": "Кідь означіте тото поличко, буде імейл (з дочасным геслом) оркем посланя хоснователёви указаный і вам.",
        "passwordreset-email": "Адреса електронічной пошты:",
        "passwordreset-emailtitle": "Детайлы конта на {{SITENAME}}",
-       "passwordreset-emailtext-ip": "Дахто (може Вы, з IP адресы $1) попросив о наставлїня нового гесла до вашого конта на {{grammar:6sg|{{SITENAME}}}} ($4). З тов адресов {{PLURAL:$3|є повязане наступне конто|суть повазяны слїдуючі конта}}:\n\n$2\n\n{{PLURAL:$3|Тото дочасне гесло|Тоты дочасны гесла}} стануть неплатныма {{PLURAL:$5|за день|за $5 днї|за $5 днїв}}.\nТеперь бы хотїло, бы сьте ся приголосили та зволлил нове гесло. Кідь тоту просьбу післав хтось другый або сьте ся на старе гесло роспамнятали і не хочете го змінити, можете тото повідомлїня іґноровати та дале хосновати старе гесло.",
-       "passwordreset-emailtext-user": "{{gender:$1|ХоÑ\81новаÑ\82елÑ\8c|ХоÑ\81новаÑ\82елÑ\8cка|ХоÑ\81новаÑ\82елÑ\8c}} $1 {{grammar:2sg|{{SITENAME}}}} {{gender:$1|попÑ\80оÑ\81ив|попÑ\80оÑ\81ила|попÑ\80оÑ\81ив}} Ð¾ Ð½Ð°Ñ\81Ñ\82авлÑ\97нÑ\8f Ð½Ð¾Ð²Ð¾Ð³Ð¾ Ð³ÐµÑ\81ла Ðº Ð²Ð°Ñ\88омÑ\83\nконÑ\82Ñ\83 Ð½Ð° {{grammar:6sg|{{SITENAME}}}} ($4). Ð\9a Ñ\82Ñ\96й Ð°Ð´Ñ\80еÑ\81Ñ\97 {{PLURAL:$3|Ñ\94 Ñ\81пÑ\80Ñ\8fжене Ð½Ð°Ñ\81Ñ\82Ñ\83пне ÐºÐ¾Ð½Ñ\82о|Ñ\81Ñ\83Ñ\82Ñ\8c Ñ\81пÑ\80Ñ\8fженÑ\8b Ð½Ð°Ñ\81Ñ\82Ñ\83пнÑ\83 ÐºÐ¾Ð½Ñ\82а}}:\n\n$2\n\n{{PLURAL:$3|ТоÑ\82о Ð´Ð¾Ñ\87аÑ\81не Ð³ÐµÑ\81ло|ТоÑ\82Ñ\8b Ð´Ð¾Ñ\87аÑ\81нÑ\8b Ð³ÐµÑ\81ла}} ÐºÑ\96нÑ\87аÑ\82Ñ\8c {{PLURAL:$5|о Ñ\94ден Ð´ÐµÐ½Ñ\8c|о $5 Ð´Ð½Ñ\97|о $5 Ð´Ð½Ñ\97в}}.\nÐ\9dÑ\8bнÑ\97 Ð±Ñ\8b Ñ\81Ñ\8cÑ\82е Ñ\81Ñ\8f Ð¼Ð°Ð²(а) Ð¿Ñ\80иголоÑ\81иÑ\82и Ñ\83 Ð·Ð²Ð¾Ð»Ð¸Ñ\82и Ñ\81обÑ\96 Ð½Ð¾Ð²Ðµ Ð³ÐµÑ\81ло. Ð\9aÑ\96дÑ\8c Ñ\82оÑ\82Ñ\83 Ð¿Ð¾Ð¶Ð°Ð´Ð°Ð²ÐºÑ\83\nпоÑ\81лав Ð´Ð°Ñ\85Ñ\82о Ð´Ñ\80Ñ\83гÑ\8bй Ð°Ð±Ð¾ Ñ\81Ñ\8cÑ\82е Ñ\81обÑ\96 Ð½Ð° Ñ\81воÑ\94 Ñ\81Ñ\82аÑ\80е Ð³ÐµÑ\81ло Ñ\81помÑ\8fнÑ\83в(а),і не хочете го\nзмінити, можете тото повідомлїня іґноровати і надале хосновати старе гесло.",
+       "passwordreset-emailtext-ip": "Дахто (може Вы, з IP адресы $1) попросив о наставлїня нового гесла до вашого конта на {{grammar:6sg|{{SITENAME}}}} ($4). З тов адресов {{PLURAL:$3|є повязане слїдуюче конто|суть повязаны слїдуючі конта}}:\n\n$2\n\n{{PLURAL:$3|Тото дочасне гесло стане неплатным|Тоты дочасны гесла стануть неплатныма}} {{PLURAL:$5|за день|за $5 днї|за $5 днїв}}.\nТеперь бы сьте ся мали приголосити і зволити собі нове гесло. Кідь тоту просьбу послав хтось другый або сьте собі на своє старе гесло спомянули і не хочете го змінити, можете тото повідомлїня іґноровати і дале хосновати старе гесло.",
+       "passwordreset-emailtext-user": "{{gender:$1|ХоÑ\81новаÑ\82елÑ\8c|ХоÑ\81новаÑ\82елÑ\8cка|ХоÑ\81новаÑ\82елÑ\8c}} $1 {{grammar:2sg|{{SITENAME}}}} {{gender:$1|попÑ\80оÑ\81ив|попÑ\80оÑ\81ила|попÑ\80оÑ\81ив}} Ð¾ Ð½Ð°Ñ\81Ñ\82авлÑ\97нÑ\8f Ð½Ð¾Ð²Ð¾Ð³Ð¾ Ð³ÐµÑ\81ла Ð´Ð¾ Ð²Ð°Ñ\88ого\nконÑ\82а Ð½Ð° {{grammar:6sg|{{SITENAME}}}} ($4). Ð\97 Ñ\82ов Ð°Ð´Ñ\80еÑ\81ов {{PLURAL:$3|Ñ\94 Ð¿Ð¾Ð²Ñ\8fзане Ð½Ð°Ñ\81Ñ\82Ñ\83пне ÐºÐ¾Ð½Ñ\82о|Ñ\81Ñ\83Ñ\82Ñ\8c Ð¿Ð¾Ð²Ñ\8fзанÑ\8b Ð½Ð°Ñ\81Ñ\82Ñ\83пнÑ\8b ÐºÐ¾Ð½Ñ\82а}}:\n\n$2\n\n{{PLURAL:$3|ТоÑ\82о Ð´Ð¾Ñ\87аÑ\81не Ð³ÐµÑ\81ло ÐºÑ\96нÑ\87иÑ\82Ñ\8c|ТоÑ\82Ñ\8b Ð´Ð¾Ñ\87аÑ\81нÑ\8b Ð³ÐµÑ\81ла ÐºÑ\96нÑ\87аÑ\82Ñ\8c}} {{PLURAL:$5|о Ñ\94ден Ð´ÐµÐ½Ñ\8c|о $5 Ð´Ð½Ñ\97|о $5 Ð´Ð½Ñ\97в}}.\nТепеÑ\80Ñ\8c Ð±Ñ\8b Ñ\81Ñ\8cÑ\82е Ñ\81Ñ\8f Ð¼Ð°Ð»Ð¸ Ð¿Ñ\80иголоÑ\81иÑ\82и Ñ\96 Ð·Ð²Ð¾Ð»Ð¸Ñ\82и Ñ\81обÑ\96 Ð½Ð¾Ð²Ðµ Ð³ÐµÑ\81ло. Ð\9aÑ\96дÑ\8c Ñ\82оÑ\82Ñ\83 Ð¿Ð¾Ð¶Ð°Ð´Ð°Ð²ÐºÑ\83 \nпоÑ\81лав Ð´Ð°Ñ\85Ñ\82о Ð´Ñ\80Ñ\83гÑ\8bй Ð°Ð±Ð¾ Ñ\81Ñ\8cÑ\82е Ñ\81обÑ\96 Ð½Ð° Ñ\81воÑ\94 Ñ\81Ñ\82аÑ\80е Ð³ÐµÑ\81ло Ñ\81помÑ\8fнÑ\83ли і не хочете го\nзмінити, можете тото повідомлїня іґноровати і надале хосновати старе гесло.",
        "passwordreset-emailelement": "Імя хоснователя: $1\nДочасне гесло: $2",
        "passwordreset-emailsent": "Імейл з геслом быв посланый.",
        "passwordreset-emailsent-capture": "Быв выґенерованый імейл з геслом, што є вказаный ниже.",
        "powersearch-togglelabel": "Позначіти:",
        "powersearch-toggleall": "Вшыткы",
        "powersearch-togglenone": "Жадный",
+       "powersearch-remember": "Запамятати выбір про будучі гляданя",
        "search-external": "Екстерне гляданя",
        "searchdisabled": "<p>Перебачте. Повнотекстове гляданя є дочасно недоступне. Затля можете спробовати гляданя Google; є але можне, же ёго резултаты не мусять быти актуалны.</p>",
        "search-error": "Як ся глядало трафіла ся хыба: $1",
index 102cbbf..0c888be 100644 (file)
        "cantcreateaccounttitle": "Саҥа ааты киллэрэр сатаммат",
        "cantcreateaccount-text": "[[User:$3|$3]] кыттааччы бу IP-ттан ('''$1''') саҥа бэлиэтэниини бопто.\n\nБыһаарыыта: $3 - ''$2''",
        "cantcreateaccount-range-text": "Бу IP-диапазонтан '''$1''' ааты бэлиэтиири [[User:$3|$3]] боппут. Эн IP-аадырыһыҥ ('''$4''') онно киирсэр эбит. \n\nЫйыллыбыт төрүөтэ: $2.",
-       "viewpagelogs": "Бу сирэй историятын көрдөр",
+       "viewpagelogs": "Бу сирэй сурунаалларын көрүү",
        "nohistory": "Бу сирэй историята суох эбит.",
        "currentrev": "Билиҥҥи барыл",
        "currentrev-asof": "Билиҥҥи торум манна: $1",
index 0917960..5e41676 100644 (file)
        "tog-showtoolbar": "Ammustra sa mustra de sa barra de sas ainas",
        "tog-editondblclick": "Càmbia pàginas cun duos click",
        "tog-editsectiononrightclick": "Abìlita su càmbiu de sas setziones cun click de dereta in sos tìtulos de sas setziones",
-       "tog-watchcreations": "Agiunghe sas pàginas chi apo creadu e sos documentos chi apo carrigadu in sa watchlist mea",
-       "tog-watchdefault": "Agiunghe pàginas e documentos chi apo cambiadu in sa watchlist mea",
-       "tog-watchmoves": "Agiunghe pàginas e documentos chi apo mòvidu in sa watchlist mea",
-       "tog-watchdeletion": "Agiunghe pàginas e documentos chi apo fuliadu in sa watchlist mea",
+       "tog-watchcreations": "Annanghe is pàginas chi apo creadu e is documentos chi apo carrigadu in sa lista de pàginas annotadas mea",
+       "tog-watchdefault": "Annanghe pàginas e documentos chi apo cambiadu in sa lista de pàginas annotadas mea",
+       "tog-watchmoves": "Annanghe pàginas e documentos chi apo mòvidu in sa lista de pàginas annotadas mea",
+       "tog-watchdeletion": "Annanghe pàginas e documentos chi apo burradu in sa lista de pàginas annotadas mea",
        "tog-watchrollback": "Pone is pàginas innue apo fatu su rollback in is pàginas annotadas",
        "tog-minordefault": "Marca comente minores pro difetu totus sos càmbios",
        "tog-previewontop": "Ammustra s'anteprima in subra de sa casella de càmbiu e no in suta",
        "edit": "Càmbia",
        "edit-local": "Càmbia sa descritzione locale",
        "create": "Crea",
-       "create-local": "Agiunghe descritzione locale",
+       "create-local": "Annanghe descritzione locale",
        "editthispage": "Càmbia custa pàgina",
        "create-this-page": "Crea custa pàgina",
        "delete": "Burra",
index ad70cfb..18d96fd 100644 (file)
        "otherlanguages": "V iných jazykoch",
        "redirectedfrom": "(Presmerované z $1)",
        "redirectpagesub": "Presmerovacia stránka",
+       "redirectto": "Presmerovať na:",
        "lastmodifiedat": "Čas poslednej úpravy tejto stránky je $2, $1.",
        "viewcount": "Táto stránka bola navštívená {{PLURAL:$1|raz|$1-krát|$1-krát}}.",
        "protectedpage": "Zamknutá stránka",
        "jumptonavigation": "navigácia",
        "jumptosearch": "hľadanie",
        "view-pool-error": "Ľutujeme, servery sú momentálne preťažené.\nPríliš veľa používateľov sa pokúša zobraziť túto stránku.\nProsím, počkajte chvíľu predtým, než sa pokúsite na túto stránku dostať znova.\n\n$1",
+       "generic-pool-error": "Ľutujeme, servery sú momentálne preťažené.\nPríliš veľa používateľov sa pokúša zobraziť tento zdroj.\nProsím, pred ďalším pokusom o prístup chvíľu počkajte.",
        "pool-timeout": "Bol prekročený vyhradený čas čakania na zámok",
        "pool-queuefull": "Front je plný",
        "pool-errorunknown": "Neznáma chyba",
        "hidetoc": "skryť",
        "collapsible-collapse": "zbaliť",
        "collapsible-expand": "rozbaliť",
+       "confirmable-confirm": "Ste si {{GENDER:$1|istý|istá|istí}}?",
        "confirmable-yes": "Áno",
        "confirmable-no": "Nie",
        "thisisdeleted": "Zobraziť alebo obnoviť $1?",
        "invalidtitle-knownnamespace": "Neplatný názov s menným priestorom „$2“ a textom „$3“",
        "invalidtitle-unknownnamespace": "Neplatný názov s neznámym číslom menného priestoru „$1“ a textom „$2“",
        "exception-nologin": "Nie ste prihlásený",
-       "exception-nologin-text": "Táto stránka alebo operácia vyžaduje, aby ste [[Special:Userlogin|boli prihlásený]].",
+       "exception-nologin-text": "Táto stránka alebo operácia vyžaduje, aby ste boli prihlásený.",
        "exception-nologin-text-manual": "Pre prístup na túto stránku alebo k tejto akcii sa musíte $1.",
        "virus-badscanner": "Chybná konfigurácia: neznámy antivírus: ''$1''",
        "virus-scanfailed": "kontrola zlyhala (kód $1)",
        "createaccount-text": "Niekto vytvoril účet pre vašu emailovú adresu na {{GRAMMAR:lokál|{{SITENAME}}}}\n($4) s názvom „$2“, s heslom „$3“. Mali by ste sa prihlásiť a svoje heslo teraz zmeniť.\n\nAk bol účet vytvorený omylom, túto správu môžete ignorovať.",
        "login-throttled": "Uskutočnili ste príliš mnoho neúspešných pokusov o prihlásenie.\nProsím, počkajte $1 predtým, než to skúsite znova.",
        "login-abort-generic": "Vaše prihlásenie nebolo úspešné - zrušené",
+       "login-migrated-generic": "Váš účet bol presťahovaný a vaše používateľské meno už viac na tejto wiki neexistuje.",
        "loginlanguagelabel": "Jazyk: $1",
        "suspicious-userlogout": "Vaša požiadavka odhlásiť sa bola zamietnutá, pretože to vyzerá, že ju poslal pokazený prehliadač alebo proxy server.",
        "createacct-another-realname-tip": "Skutočné meno je nepovinné.\nAk sa rozhodnete ho poskytnúť, použije sa na označenie vašej práce.",
        "resetpass-validity-soft": "Vaše heslo je neplatné: $1\n\nVyberte si nové heslo, alebo kliknite na „{{int:resetpass-submit-cancel}}“ a nastavte si ho neskôr.",
        "passwordreset": "Reset hesla",
        "passwordreset-text-one": "Pre získanie nového hesla vyplňte tento formulár.",
-       "passwordreset-text-many": "{{PLURAL:$1|Pre získanie nového hesla zadajte jeden z údajov.}}",
+       "passwordreset-text-many": "{{PLURAL:$1|Pre získanie nového hesla emailom, zadajte jeden z údajov.}}",
        "passwordreset-legend": "Obnoviť heslo",
        "passwordreset-disabled": "Obnovenie hesla bolo na tejto wiki zakázané.",
        "passwordreset-emaildisabled": "E-mailové funkcie boli na tejto wiki vypnuté.",
        "preview": "Náhľad",
        "showpreview": "Zobraziť náhľad",
        "showdiff": "Zobraziť rozdiely",
-       "anoneditwarning": "'''Upozornenie:''' Nie ste prihlásený.\nVaša IP adresa bude zaznamenaná v histórii úprav tejto stránky.",
+       "blankarticle": "<strong>Upozornenie:</strong> Stránka, ktorú sa chystáte založiť, je prázdna. Pokiaľ ešte raz kliknete na „{{int:savearticle}}“, bude založená úplne bez obsahu.",
+       "anoneditwarning": "<strong>Upozornenie:</strong> Nie ste prihlásený.\nAk uložíte akúkoľvek úpravu vaša IP adresa bude zverejnená v histórii tejto stránky. Ak sa <strong>[$1 prihlásite]</strong> alebo si <strong>[$2 vytvoríte účet]</strong>, budú vaše úpravy priradené k vášmu používateľskému menu a získate i ďalšie výhody.",
        "anonpreviewwarning": "''Nie ste prihlásený. Uložením zaznamenáte svoju IP adresu do histórie úprav tejto stránky.''",
        "missingsummary": "'''Pripomienka:''' Neposkytli ste zhrnutie úprav. Ak kliknete znova na Uložiť, vaše úpravy sa uložia bez zhrnutia úprav.",
        "missingcommenttext": "Prosím, dolu napíšte komentár.",
        "edit-gone-missing": "Nebolo možné aktualizovať stránku.\nZdá sa, že bola zmazaná.",
        "edit-conflict": "Konflikt pri upravovaní.",
        "edit-no-change": "Vaša úprava bola ignorovaná, pretože ste v texte nič nezmenili.",
+       "postedit-confirmation-created": "Stránka bola vytvorená.",
+       "postedit-confirmation-restored": "Stránka bola obnovená.",
        "postedit-confirmation-saved": "Vaša úprava bola uložená.",
        "edit-already-exists": "Nebolo možné vytvoriť novú stránku.\nUž existuje.",
        "defaultmessagetext": "Predvolený text správy",
        "parser-template-recursion-depth-warning": "Bol prekročený limit rekurzie šablón ($1)",
        "language-converter-depth-warning": "Bolo prekročené obmedzenie hĺbky ($1) jazykového konvertora",
        "node-count-exceeded-category": "Stránky s priveľkým počtom uzlov",
-       "node-count-exceeded-warning": "Stránka prekročila povolený počet uzlov",
+       "node-count-exceeded-category-desc": "Tato stránka prekračuje maximálny počet uzlov.",
+       "node-count-exceeded-warning": "Stránka prekročila počet uzlov",
        "expansion-depth-exceeded-category": "Stránky s priveľkou hĺbkou expanzie",
+       "expansion-depth-exceeded-category-desc": "Stránka prekročila maximálnu hĺbku expanzie.",
        "expansion-depth-exceeded-warning": "Stránka prekročila povolenú hĺbku expanzie",
        "parser-unstrip-loop-warning": "Zistené zacyklenie volania rozširovacej značky",
        "parser-unstrip-recursion-limit": "Prektočený limit rekurzie volania rozširovacej značky ($1)",
        "undo-success": "Úpravu je možné vrátiť. Prosím skontrolujte tento rozdiel, čím overíte, že táto úprava je tá, ktorú chcete, a následne uložte zmeny, čím ukončíte vrátenie.",
        "undo-failure": "Úpravu nie je možné vrátiť kvôli konfliktným medziľahlým úpravám.",
        "undo-norev": "Túto úpravu nie je možné vrátiť, pretože neexistuje alebo bola zmazaná.",
+       "undo-nochange": "Zdá se, že úprava už bola zrušená.",
        "undo-summary": "Revízia $1 používateľa [[Special:Contributions/$2|$2]] ([[User talk:$2|diskusia]]) bola vrátená",
        "undo-summary-username-hidden": "Vrátiť revíziu $1, ktorú vykonal skrytý používateľ",
        "cantcreateaccounttitle": "Nie je možné vytvoriť účet",
        "right-move": "Presúvať stránky",
        "right-move-subpages": "Presunúť stránky aj s podstránkami",
        "right-move-rootuserpages": "Presunúť koreňové stránky používateľa",
+       "right-move-categorypages": "Premiestňovanie stránok kategórií",
        "right-movefile": "Presunúť súbory",
        "right-suppressredirect": "Nevytvoriť presmerovanie zo starého názvu pri presúvaní stránky",
        "right-upload": "Nahrávať súbory",
        "action-createpage": "vytvárať stránky",
        "action-createtalk": "vytvárať diskusné stránky",
        "action-createaccount": "vytvoriť tento používateľský účet",
+       "action-history": "zobraziť históriu tejto stránky",
        "action-minoredit": "označiť túto úpravu ako drobnú",
        "action-move": "presunúť túto stránku",
        "action-move-subpages": "presunúť túto stránku a jej podtránky",
        "action-move-rootuserpages": "presunúť koreňové stránky používateľa",
+       "action-move-categorypages": "premiestňovať stránky kategórií",
        "action-movefile": "presunúť tento súbor",
        "action-upload": "nahrať tento súbor",
        "action-reupload": "prepísať tento existujúci súbor",
        "recentchanges-label-plusminus": "Veľkosť stránky sa zmenila o toľkoto bajtov",
        "recentchanges-legend-heading": "'''Legenda:'''",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (pozri tiež [[Special:NewPages|zoznam nových stránok]])",
-       "rcnotefrom": "Nižšie sú zobrazené úpravy od <strong>$2</strong> (do <strong>$1</strong>).",
+       "rcnotefrom": "Nižšie {{PLURAL:$5|je zobrazená úprava|sú zobrazené úpravy}} od <strong>$2</strong> (do <strong>$1</strong>).",
        "rclistfrom": "Zobraziť nové úpravy počnúc od $3 $2",
        "rcshowhideminor": "$1 drobné úpravy",
        "rcshowhideminor-show": "Zobraziť",
        "querypage-disabled": "Táto špeciálna stránka bola zakázaná z výkonnostných dôvodov.",
        "booksources": "Knižné zdroje",
        "booksources-search-legend": "Vyhľadávať knižné zdroje",
+       "booksources-search": "Hľadať",
        "booksources-text": "Nižšie je zoznam odkazov na iné stránky, ktoré predávajú nové a použité knihy a tiež môžu obsahovať ďalšie informácie o knihách, ktoré hľadáte:",
        "booksources-invalid-isbn": "Zdá sa, že dané ISBN nie je platné. Skontrolujte, či ste neurobili chybu pri kopírovaní z pôvodného zdroja.",
        "specialloguserlabel": "Pôvodca:",
        "import": "Import stránok",
        "importinterwiki": "Transwiki import",
        "import-interwiki-text": "Zvoľte wiki a názov stránky, ktorá sa má importovať.\nDátumy revízií a mená používateľov budú zachované.\nVšetky transwiki importy sa zaznamenávajú v [[Special:Log/import|Zázname importov]].",
+       "import-interwiki-sourcewiki": "Zdrojová wiki:",
+       "import-interwiki-sourcepage": "Zdrojová stránka:",
        "import-interwiki-history": "Skopírovať všetky historické revízie tejto stránky",
        "import-interwiki-templates": "Vložiť všetky šablóny",
        "import-interwiki-submit": "Importovať",
        "importuploaderrortemp": "Nahranie alebo import súboru zlyhal. Dočasný adresár chýba.",
        "import-parse-failure": "Chyba syntaktickej analýzy pri XML importe",
        "import-noarticle": "Žiadny článok na import!",
-       "import-nonewrevisions": "Všetky revízie boli predtým importované.",
+       "import-nonewrevisions": "Žiadne revízie neboli importované (buď už boli všetky  importované skôr, alebo boli preskočené kvôli chybám).",
        "xml-error-string": "$1 na riadku $2, stĺpec $3 (bajt $4): $5",
        "import-upload": "Nahrať XML údaje",
        "import-token-mismatch": "Strata údajov relácie. Prosím, skúste to znova.",
        "newimages-summary": "Táto špeciálna stránka zobrazuje posledné nahrané súbory.",
        "newimages-legend": "Filter",
        "newimages-label": "Názov súboru (alebo jeho časť):",
+       "newimages-showbots": "Zobraziť súbory nahrané botmi",
        "noimages": "Niet čo zobraziť.",
        "ilsubmit": "Hľadať",
        "bydate": "podľa dátumu",
        "autosumm-replace": "Nahrádzam stránku textom „$1“",
        "autoredircomment": "Presmerovanie na [[$1]]",
        "autosumm-new": "Vytvorená stránka „$1“",
+       "autosumm-newblank": "Vytvorená prázdna stránka",
        "lag-warn-normal": "Úpravy za {{PLURAL:$1|poslednú sekundu|posledné $1 sekundy|posledných $1 sekúnd}} nemusia byť v tomto zozname zobrazené.",
        "lag-warn-high": "Kvôli dlhšej odozve databázového servera nemusia byť úpravy za {{PLURAL:$1|poslednú sekundu|posledné $1 sekundy|posledných $1 sekúnd}} v tomto zozname zobrazené.",
        "watchlistedit-normal-title": "Upraviť zoznam sledovaných stránok",
        "watchlistedit-raw-done": "Váš zoznam sledovaných stránok bol aktualizovaný.",
        "watchlistedit-raw-added": "{{PLURAL:$1|Jedna položka bola pridaná|$1 položky boli pridané|$1 položiek bolo pridaných}}:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|Jedna položka bola odstránená|$1 položky boli odstránené|$1 položiek bolo odstránených}}:",
+       "watchlistedit-clear-title": "Vyprázdnenie zoznamu sledovaných stránok",
+       "watchlistedit-clear-legend": "Vyprázdniť zoznam sledovaných stránok",
+       "watchlistedit-clear-explain": "Z vášho zoznamu sledovaných stránok budú odstránené všetky názvy",
        "watchlistedit-clear-titles": "Názvy:",
+       "watchlistedit-clear-submit": "Vyprázdniť zoznam sledovaných stránok (natrvalo!)",
+       "watchlistedit-clear-done": "Váš zoznam sledovaných stránok bol vyprázdnený.",
+       "watchlistedit-clear-removed": "{{PLURAL:$1|Bol odstránený jeden názov|Boli odstránené $1 názvy|Bolo odstránených $1 názvov}}:",
        "watchlisttools-view": "Zobraziť súvisiace zmeny",
        "watchlisttools-edit": "Zobraziť a upraviť zoznam sledovaných stránok",
        "watchlisttools-raw": "Upraviť nespracovaný zoznam sledovaných stránok",
        "pagelang-use-default": "Použiť predvolený jazyk",
        "pagelang-select-lang": "Vybrať jazyk",
        "right-pagelang": "Zmeniť jazyk stránky",
-       "default-skin-not-found": "Uups! Základná tapeta pre Vašu wiki, popísanú v <code dir=\"ltr\">$wgDefaultSkin</code> ako <code>$1</code>, nie je dostupná. \n\nVaša inštalácia pravdepodobne obsahuje nasledovné tapety. Pozri [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] pre viac informácii o ich aktivácii a zvoľte základnú.\n\n$2\n\n; Ak ste MediaWiki len teraz nainštalovali\n; Zrejme ste to nainštalovali z gitu alebo priamo zo zdrojového kódu inou metódou. Je to očakávané. Skúste nainštalovať nejaké tapety z [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org's skin directory];\n:*Stiahnutím [https://www.mediawiki.org/wiki/Download tarball installer], ktorý ponúka viacero tapiet a rozšírení. Skopírovať a nalepiť možno priamo z <code>skins/</code>.\n:*Klonovanie jednej zo <code>mediawiki/skins/*</code> schránok cez git do <code dir=\"ltr\">skins/</code> priečinku Vašej Media Wiki inštalácie.\n: S existujúcou git schránkou, ak ste vývojár MediaWiki, by nemal byť konflikt.\n\n: Ak ste upgradeovali MediaWiki\n: MediaWiki 1.24 a novšie už tapety automaticky neaktivujú. (see [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]). Nasledovný kód môžete skopírovať do <code>LocalSettings.php</code> pre aktivovanie všetkých dostupných tapiet.\n\n<pre dir=\"ltr\">$3</pre>\n\n; Ak ste upravili <code>LocalSettings.php</code>:\n: Skontrolujte chyby."
+       "default-skin-not-found": "Uups! Základná tapeta pre Vašu wiki, popísanú v <code dir=\"ltr\">$wgDefaultSkin</code> ako <code>$1</code>, nie je dostupná. \n\nVaša inštalácia pravdepodobne obsahuje nasledovné tapety. Pozri [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] pre viac informácii o ich aktivácii a zvoľte základnú.\n\n$2\n\n; Ak ste MediaWiki len teraz nainštalovali\n; Zrejme ste to nainštalovali z gitu alebo priamo zo zdrojového kódu inou metódou. Je to očakávané. Skúste nainštalovať nejaké tapety z [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org's skin directory];\n:*Stiahnutím [https://www.mediawiki.org/wiki/Download tarball installer], ktorý ponúka viacero tapiet a rozšírení. Skopírovať a nalepiť možno priamo z <code>skins/</code>.\n:*Klonovanie jednej zo <code>mediawiki/skins/*</code> schránok cez git do <code dir=\"ltr\">skins/</code> priečinku Vašej Media Wiki inštalácie.\n: S existujúcou git schránkou, ak ste vývojár MediaWiki, by nemal byť konflikt.\n\n: Ak ste upgradeovali MediaWiki\n: MediaWiki 1.24 a novšie už tapety automaticky neaktivujú. (see [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]). Nasledovný kód môžete skopírovať do <code>LocalSettings.php</code> pre aktivovanie všetkých dostupných tapiet.\n\n<pre dir=\"ltr\">$3</pre>\n\n; Ak ste upravili <code>LocalSettings.php</code>:\n: Skontrolujte chyby.",
+       "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (povolený)",
+       "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''zakázaný''')",
+       "mediastatistics": "Štatistika súborov",
+       "mediastatistics-table-count": "Počet súborov",
+       "mediastatistics-table-totalbytes": "Celková veľkosť",
+       "mediastatistics-header-unknown": "Neznáme",
+       "mediastatistics-header-bitmap": "Rastrové obrázky",
+       "mediastatistics-header-drawing": "Kresby (vektorové obrázky)",
+       "mediastatistics-header-audio": "Audio",
+       "mediastatistics-header-video": "Videá",
+       "mediastatistics-header-multimedia": "Multimédiá",
+       "mediastatistics-header-office": "Kancelárske súbory",
+       "mediastatistics-header-text": "Text",
+       "mediastatistics-header-executable": "Spustiteľné súbory",
+       "mediastatistics-header-archive": "Komprimované formáty"
 }
index 0946e62..85b079d 100644 (file)
        "pagelang-select-lang": "Изабери језик",
        "right-pagelang": "мењање језика странице",
        "action-pagelang": "промену језика странице",
+       "mediastatistics-summary": "Статистике о типовима послатих датотека. Овде су урачунате само најновије верзије датотека. Старе или обрисане верзије нису урачунате.",
        "mediastatistics-table-mimetype": "MIME тип",
-       "mediastatistics-table-count": "Број датотека"
+       "mediastatistics-table-extensions": "Могуће екстензије",
+       "mediastatistics-table-count": "Број датотека",
+       "mediastatistics-table-totalbytes": "Укупна величина",
+       "mediastatistics-header-bitmap": "Битмап слике",
+       "mediastatistics-header-drawing": "Цртежи (векторске слике)",
+       "mediastatistics-header-audio": "Аудио",
+       "mediastatistics-header-video": "Видео",
+       "mediastatistics-header-office": "Канцеларија"
 }
index 6c134b4..c7fe57a 100644 (file)
        "pagelang-language": "Jezik",
        "pagelang-select-lang": "Izaberi jezik",
        "right-pagelang": "menjanje jezika stranice",
-       "action-pagelang": "promenu jezika stranice"
+       "action-pagelang": "promenu jezika stranice",
+       "mediastatistics-table-mimetype": "MIME tip",
+       "mediastatistics-table-count": "Broj datoteka"
 }
index c02ecf5..3b186d9 100644 (file)
        "tooltip-recreate": "Återskapa sidan fast den har tagits bort",
        "tooltip-upload": "Starta uppladdning",
        "tooltip-rollback": "\"Tillbakarullning\" tar med en knapptryckning bort ändringar som gjorts av den som senast redigerade sidan",
-       "tooltip-undo": "\"Gör ogjord\" återställer denna redigering och öppnar redigeringsrutan med förhandsgranskning.\nDen ger möjlighet att skriva en motivering i redigeringssammanfattningen.",
+       "tooltip-undo": "\"Gör ogjord\" återställer denna redigering och öppnar redigeringsrutan med förhandsgranskning. Det ger möjlighet att skriva en motivering i redigeringssammanfattningen.",
        "tooltip-preferences-save": "Spara inställningar",
        "tooltip-summary": "Skriv en kort sammanfattning",
        "interlanguage-link-title": "$1 - $2",
index 73006fd..942c445 100644 (file)
@@ -9,17 +9,18 @@
                        "Nataev",
                        "Sociologist",
                        "Xexdof",
-                       "Arystanbek"
+                       "Arystanbek",
+                       "6ahodir"
                ]
        },
        "tog-underline": "Havolalarning tagiga chizish:",
-       "tog-hideminor": "Yangi oʻzgarishlar roʻyxatida kichik tahrirlarni yashirish",
-       "tog-hidepatrolled": "Yangi oʻzgarishlar roʻyxatida tekshirilgan tahrirlarni yashirish",
-       "tog-newpageshidepatrolled": "Yangi sahifalar roʻyxatida tekshirilgan sahifalarni yashirish",
+       "tog-hideminor": "Yangi oʻzgarishlar roʻyxatidan kichik tahrirlarni yashirish",
+       "tog-hidepatrolled": "Yangi oʻzgarishlar roʻyxatidan tekshirilgan tahrirlarni yashirish",
+       "tog-newpageshidepatrolled": "Yangi sahifalar roʻyxatidan tekshirilgan sahifalarni yashirish",
        "tog-extendwatchlist": "Kengaytirilgan kuzatuv roʻyxati: faqat oxirgi paytdagi emas, barcha oʻzgarishlar koʻrsatiladi",
        "tog-usenewrc": "Yangi oʻzgarishlar va kuzatuv roʻyxatidagi sahifalarni guruhlarga boʻlish (JavaScript orqali)",
        "tog-numberheadings": "Sarlavhalarni avtomatik raqamlash",
-       "tog-showtoolbar": "Yuqoridagi tahrirlash asboblarini koʻrsatish",
+       "tog-showtoolbar": "Tahrirlash asboblarini koʻrsatish",
        "tog-editondblclick": "Sichqonchaning chap tugmasini ikki marta bosib tahrirlashni boshlash",
        "tog-editsectiononrightclick": "Boʻlim sarlavhasiga sichqonchaning oʻng tugmasini bosib tahrirlashni boshlash",
        "tog-watchcreations": "Men yaratgan sahifalar va yuklagan fayllar kuzatuv roʻyxatimga qoʻshilsin",
        "thu": "Pay",
        "fri": "Jum",
        "sat": "Shn",
-       "january": "yanvar",
-       "february": "fevral",
-       "march": "mart",
-       "april": "aprel",
-       "may_long": "may",
-       "june": "iyun",
-       "july": "iyul",
-       "august": "avgust",
-       "september": "sentabr",
-       "october": "oktabr",
-       "november": "noyabr",
-       "december": "dekabr",
-       "january-gen": "yanvar",
-       "february-gen": "fevral",
-       "march-gen": "mart",
-       "april-gen": "aprel",
-       "may-gen": "may",
-       "june-gen": "iyun",
-       "july-gen": "iyul",
-       "august-gen": "avgust",
-       "september-gen": "sentabr",
-       "october-gen": "oktabr",
-       "november-gen": "noyabr",
-       "december-gen": "dekabr",
-       "jan": "yan",
-       "feb": "fev",
-       "mar": "mar",
-       "apr": "apr",
-       "may": "may",
-       "jun": "iyn",
-       "jul": "iyl",
-       "aug": "avg",
-       "sep": "sen",
-       "oct": "okt",
-       "nov": "noy",
-       "dec": "dek",
+       "january": "Yanvar",
+       "february": "Fevral",
+       "march": "Mart",
+       "april": "Aprel",
+       "may_long": "May",
+       "june": "Iyun",
+       "july": "Iyul",
+       "august": "Avgust",
+       "september": "Sentabr",
+       "october": "Oktabr",
+       "november": "Noyabr",
+       "december": "Dekabr",
+       "january-gen": "Yanvar",
+       "february-gen": "Fevral",
+       "march-gen": "Mart",
+       "april-gen": "Aprel",
+       "may-gen": "May",
+       "june-gen": "Iyun",
+       "july-gen": "Iyul",
+       "august-gen": "Avgust",
+       "september-gen": "Sentabr",
+       "october-gen": "Oktabr",
+       "november-gen": "Noyabr",
+       "december-gen": "Dekabr",
+       "jan": "Yan",
+       "feb": "Fev",
+       "mar": "Mar",
+       "apr": "Apr",
+       "may": "May",
+       "jun": "Jyn",
+       "jul": "Iyl",
+       "aug": "Avg",
+       "sep": "Sen",
+       "oct": "Okt",
+       "nov": "Noy",
+       "dec": "Dek",
        "january-date": "Yanvar $1",
        "february-date": "Fevral $1",
        "march-date": "Mart $1",
        "november-date": "Noyabr $1",
        "december-date": "Dekabr $1",
        "pagecategories": "{{PLURAL:$1|Turkum}}",
-       "category_header": "\"$1\" turkumidagi maqolalar.",
+       "category_header": "\"$1\" turkumidagi sahifalar",
        "subcategories": "Ostturkumlar",
        "category-media-header": "\"$1\" turkumidagi fayllar",
        "category-empty": "''Ushbu turkumda hozircha sahifa yoki fayllar yoʻq.''",
        "anontalk": "Ushbu IP-manzil munozarasi",
        "navigation": "Saytda harakatlanish",
        "and": "&#32;va",
-       "qbfind": "Qidiruv",
-       "qbbrowse": "Koʻrish",
+       "qbfind": "Topish",
+       "qbbrowse": "Koʻrib chiqish",
        "qbedit": "Tahrirlash",
        "qbpageoptions": "Ushbu sahifa moslamalari",
-       "qbmyoptions": "Moslamalarim",
+       "qbmyoptions": "Mening sahifalarim",
        "faq": "TSS",
-       "faqpage": "Project:TSS",
+       "faqpage": "Loyiha:TSS",
        "actions": "Amallar",
        "namespaces": "Nomfazolar",
        "variants": "Variantlar",
        "watchlist-details": "Sizning kuzatuv roʻyxatingizda hozirda {{PLURAL:$1|bitta sahifa|$1ta sahifa}} mavjud (munozara sahifalarini hisobga olmaganda).",
        "wlheader-showupdated": "Siz oxirgi marta kirganingizdan keyin oʻzgartirilgan sahifalar '''qalin''' yozuv bilan ajratib koʻrsatilgan.",
        "wlnote": "Below {{PLURAL:$1|is the last change|are the last '''$1''' changes}} in the last {{PLURAL:$2|hour|'''$2''' hours}}, as of $3, $4.",
-       "wlshowlast": "Oxirgi $1 soatdagi $2 kundagi tahrirlarni koʻrsat",
+       "wlshowlast": "Oxirgi $1 soatdagi $2 kundagi tahrirlarni koʻrsatish",
        "watchlist-options": "Kuzatuv roʻyxati moslamalari",
        "watching": "Kuzatish...",
        "unwatching": "Kuzatuv ro'yxatidan o'chirish...",
index 6d6c6da..b62b7ee 100644 (file)
@@ -16,7 +16,8 @@
                        "Duolaimi",
                        "Impersonator 1",
                        "LNDDYL",
-                       "TheChampionMan1234"
+                       "TheChampionMan1234",
+                       "Fitoschido"
                ]
        },
        "tog-underline": "鏈接下橫線:",
        "databaseerror-text": "數據庫討信出錯。\n嘸數說明軟件裏有一個bug。",
        "databaseerror-textcl": "數據庫討信出錯。",
        "databaseerror-query": "討信:$1",
-       "databaseerror-function": "功能ː $1",
+       "databaseerror-function": "功能: $1",
        "databaseerror-error": "出錯:$1",
        "laggedslavemode": "警告: 页面可能弗包含最近个更新。",
        "readonly": "數據庫鎖牢",
index 4bec076..0fc3378 100644 (file)
                ]
        },
        "tog-underline": "連結顯示底線:",
-       "tog-hideminor": "隱藏最近變更以來的小編輯",
-       "tog-hidepatrolled": "隱藏最近變更中巡查過的編輯",
+       "tog-hideminor": "隱藏近期變更以來的小編輯",
+       "tog-hidepatrolled": "隱藏近期變更中巡查過的編輯",
        "tog-newpageshidepatrolled": "隱藏新頁面清單中巡查過的頁面",
        "tog-extendwatchlist": "展開監視清單顯示包含最近以外的所有變更",
-       "tog-usenewrc": "依最近變更與監視清單頁面分類顯示變更",
+       "tog-usenewrc": "依近期變更與監視清單頁面分類顯示變更",
        "tog-numberheadings": "標題自動編號",
        "tog-showtoolbar": "顯示編輯工具列",
        "tog-editondblclick": "開啟滑鼠雙擊編輯頁面",
        "userpage-userdoesnotexist": "使用者帳號 \"$1\" 尚未註冊。\n若您要建立/編輯此頁面,請先檢查是否正確。",
        "userpage-userdoesnotexist-view": "使用者帳號 \"$1\" 尚未註冊。",
        "blocked-notice-logextract": "此使用者目前已被封鎖。\n以下為最近的封鎖紀錄以供參考:",
-       "clearyourcache": "<strong>注意:</strong>在您儲存之後您必須清除瀏覽器快取才可看到最新的變動。\n* <strong>Firefox / Safari:</strong>按住 <em>Shift</em> 時點選 <em>重新整理</em>,或按 <em>Ctrl-F5</em> 或 <em>Ctrl-R</em>(Mac 則為 <em>⌘-R</em>)\n* <strong>Google Chrome:</strong>按 <em>Ctrl-Shift-R</em>(Mac 則為 <em>⌘-Shift-R</em>)\n* <strong>Internet Explorer:</strong>按住 <em>Ctrl</em> 時點選 <em>重新整理</em>,或按 <em>Ctrl-F5</em>\n* <strong>Opera:</strong>進入 <em>工具 → 偏好設定</em> 中清除快取。",
+       "clearyourcache": "<strong>注意:</strong>在您儲存之後您必須清除瀏覽器快取才可看到最新的變動。\n* <strong>Firefox / Safari:</strong>按住 <em>Shift</em> 時點選 <em>重新整理</em>,或按 <em>Ctrl-F5</em> 或 <em>Ctrl-R</em> (Mac 則為 <em>⌘-R</em>) \n* <strong>Google Chrome:</strong>按 <em>Ctrl-Shift-R</em> (Mac 則為 <em>⌘-Shift-R</em>) \n* <strong>Internet Explorer:</strong>按住 <em>Ctrl</em> 時點選 <em>重新整理</em>,或按 <em>Ctrl-F5</em>\n* <strong>Opera:</strong>進入 <em>工具 → 偏好設定</em> 中清除快取。",
        "usercssyoucanpreview": "<strong>提示:</strong>在儲存之前使用 \"{{int:showpreview}}\" 按鈕來測試您的新 CSS。",
        "userjsyoucanpreview": "<strong>提示:</strong>在儲存之前使用 \"{{int:showpreview}}\" 按鈕來測試您的新 JavaScript。",
        "usercsspreview": "<strong>您目前正預覽您的使用者 CSS,CSS 還尚未儲存!</strong>",
        "search-suggest": "您指的是不是:$1",
        "search-interwiki-caption": "姐妹專案",
        "search-interwiki-default": "來自 $1 的結果:",
-       "search-interwiki-more": "(更多)",
+       "search-interwiki-more": "(更多)",
        "search-relatedarticle": "相關",
        "searchrelated": "相關",
        "searchall": "全部",
        "recentchangesdays": "近期變更的顯示天數:",
        "recentchangesdays-max": "最多 $1 {{PLURAL:$1|天}}",
        "recentchangescount": "預設顯示的編輯數:",
-       "prefs-help-recentchangescount": "這包含最近變更、頁面歷史以及日誌。",
+       "prefs-help-recentchangescount": "這包含近期變更、頁面歷史以及日誌。",
        "prefs-help-watchlist-token2": "訂閱您的監視清單所需的密鑰。\n任何人只要知道密鑰就能夠讀取您的監視清單,所以請勿任意與它人共享。\n若有需要 [[Special:ResetTokens|您可重設密鑰]]。",
        "savedprefs": "已儲存您的偏好設定。",
        "timezonelegend": "時區:",
        "right-importupload": "由檔案上傳匯入頁面",
        "right-patrol": "標示其他人的編輯爲已巡查",
        "right-autopatrol": "將自己的編輯自動標示為已巡查",
-       "right-patrolmarks": "檢視最近變更的巡查標記",
+       "right-patrolmarks": "檢視近期變更的巡查標記",
        "right-unwatchedpages": "檢視未監視的頁面",
        "right-mergehistory": "合併頁面歷史",
        "right-userrights": "編輯所有使用者的權限",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (請參考 [[Special:NewPages|最新頁面]])",
        "recentchanges-legend-plusminus": "(<em>±123</em>)",
        "rcnotefrom": "以下{{PLURAL:$5|為}}自 <strong>$3 $4</strong> 以來的變更 (最多顯示 <strong>$1</strong> 筆)。",
-       "rclistfrom": "顯示自 $3 $2 以來的最近變更",
+       "rclistfrom": "顯示自 $3 $2 以來的近期變更",
        "rcshowhideminor": "$1 小修訂",
        "rcshowhideminor-show": "顯示",
        "rcshowhideminor-hide": "隱藏",
        "upload_directory_read_only": "網頁伺服器沒有上傳目錄 ($1) 的寫入權限。",
        "uploaderror": "上傳錯誤",
        "upload-recreate-warning": "<strong>警告:曾有檔案使用此名稱已被刪除或者移動至它處。</strong>\n\n在此提供刪除與移動日誌方便作為參考:",
-       "uploadtext": "使用下面的表單來上傳檔案。\n要檢視或搜尋以前上傳的檔案,可至 [[Special:FileList|檔案上傳清單]],(重新)上傳會在 [[Special:Log/upload|上傳日誌]] 中記錄,而刪除則會在 [[Special:Log/delete|刪除日誌]] 中記錄。\n\n要在頁面中引用檔案,可使用以下其中一種方式連結:\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code></strong> 顯示完整尺寸的圖片\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|alt text]]</nowiki></code></strong> 會在左方放置一張 200 像素寬的圖片於框中,並顯示 \"alt text\" 作為描述\n* <strong><code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code></strong> 直接連結到圖片而不顯示預覽",
+       "uploadtext": "使用下面的表單來上傳檔案。\n要檢視或搜尋以前上傳的檔案,可至 [[Special:FileList|檔案上傳清單]],(重新) 上傳會在 [[Special:Log/upload|上傳日誌]] 中記錄,而刪除則會在 [[Special:Log/delete|刪除日誌]] 中記錄。\n\n要在頁面中引用檔案,可使用以下其中一種方式連結:\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code></strong> 顯示完整尺寸的圖片\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|alt text]]</nowiki></code></strong> 會在左方放置一張 200 像素寬的圖片於框中,並顯示 \"alt text\" 作為描述\n* <strong><code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code></strong> 直接連結到圖片而不顯示預覽",
        "upload-permitted": "允許的檔案類型:$1。",
        "upload-preferred": "建議的檔案類型:$1。",
        "upload-prohibited": "禁止的檔案類型:$1。",
        "filename-tooshort": "檔案名稱過短。",
        "filetype-banned": "此類型檔案已禁止使用。",
        "verification-error": "此檔案未通過驗證。",
-       "hookaborted": "æ\82¨æ\89\80å\98\97試ç\9a\84ä¿®æ\94¹è¢«æ\93´å±\95套件中止。",
+       "hookaborted": "æ\82¨æ\89\80å\98\97試ç\9a\84ä¿®æ\94¹è¢«æ\93´å\85\85套件中止。",
        "illegal-filename": "不允許使用的檔案名稱。",
        "overwrite": "不允許覆蓋現有檔案。",
        "unknown-error": "發生不明錯誤。",
        "backend-fail-stream": "無法傳輸檔案 \"$1\"。",
        "backend-fail-backup": "無法備份檔案 \"$1\"。",
        "backend-fail-notexists": "檔案 $1 不存在。",
-       "backend-fail-hashes": "無法取得檔案雜湊值(Hash)進行比較。",
+       "backend-fail-hashes": "無法取得檔案雜湊值 (Hash) 進行比較。",
        "backend-fail-notsame": "於 \"$1\" 已存在另一個不相同的檔案。",
        "backend-fail-invalidpath": "\"$1\" 不是有效的儲存路徑。",
        "backend-fail-delete": "無法刪除檔案 \"$1\"。",
        "uploadstash-refresh": "更新檔案清單",
        "invalid-chunk-offset": "無效區塊位置",
        "img-auth-accessdenied": "拒絕存取",
-       "img-auth-nopathinfo": "缺少 PATH_INFO 參。\n您的伺服器環境未傳遞此資訊,\n您可能使用 CGI-based 的伺服器,不支援 img_auth。\n請參考 https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization。",
+       "img-auth-nopathinfo": "缺少 PATH_INFO 參。\n您的伺服器環境未傳遞此資訊,\n您可能使用 CGI-based 的伺服器,不支援 img_auth。\n請參考 https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization。",
        "img-auth-notindir": "已設定的上傳目錄清單中不存在您指定的路徑。",
        "img-auth-badtitle": "無法使用 \"$1\" 建立有效的標題。",
        "img-auth-nologinnWL": "您尚未登入,且 \"$1\" 並未在允許清單上。",
        "deletereasonotherlist": "其它原因",
        "deletereason-dropdown": "* 常見的刪除原因\n** 濫發廣告訊息\n** 破壞\n** 侵犯版權\n** 作者請求\n** 損壞的重新導向連結",
        "delete-edit-reasonlist": "編輯刪除原因",
-       "delete-toobig": "這個頁面有一個十分大量的編輯歷史,超過$1次修訂。刪除此類頁面的動作已經被限制,以防止在{{SITENAME}}上的意外擾亂。",
-       "delete-warning-toobig": "這個頁面有一個十分大量的編輯歷史,超過$1次修訂。刪除它可能會擾亂{{SITENAME}}的資料庫操作;在繼續此動作前請小心。",
+       "delete-toobig": "此頁面含有大量的編輯歷史,超過 $1 次修訂。\n已限制刪除此類頁面的動作,以避免意外中斷 {{SITENAME}} 的運作。",
+       "delete-warning-toobig": "此頁面含有大量的編輯歷史,超過 $1 次修訂。\n刪除該頁面可能會中斷 {{SITENAME}} 的資料庫運作;\n請小心執行此動作。",
        "deleteprotected": "此頁面已受保護,您無法刪除此頁面。",
        "deleting-backlinks-warning": "<strong>警告:</strong>您正要刪除的頁面有[[Special:WhatLinksHere/{{FULLPAGENAME}}|其他頁面]]連結或引用。",
        "rollback": "還原編輯",
        "ip_range_invalid": "無效的 IP 範圍。",
        "ip_range_toolarge": "不允許封鎖範圍大於 /$1。",
        "proxyblocker": "代理伺服器封鎖器",
-       "proxyblockreason": "因您的 IP 位址是開放代理伺服器,已被封鎖。\n請聯繫您的網服務供應商或您所在組織的技術支援,告知他們此嚴重的安全性問題。",
+       "proxyblockreason": "因您的 IP 位址是開放代理伺服器,已被封鎖。\n請聯繫您的網服務供應商或您所在組織的技術支援,告知他們此嚴重的安全性問題。",
        "sorbsreason": "您的 IP 位址在 {{SITENAME}} 使用的 DNSBL 列為開放代理伺服器。",
        "sorbs_create_account_reason": "您連線到 {{SITENAME}} 的 IP 位址被 DNSBL 列為開放代理伺服器。\n您不能建立帳號。",
        "xffblockreason": "您的 IP 位址使用 X-Forwarded-For 標頭,您或您使用的代理伺服器已被封鎖。\n封鎖的原因為:$1",
        "tooltip-n-randompage": "隨機進入一個頁面",
        "tooltip-n-help": "尋求協助的地方",
        "tooltip-t-whatlinkshere": "列出所有連結此頁面的頁面",
-       "tooltip-t-recentchangeslinked": "此頁面連結到其他頁面的最近變更",
+       "tooltip-t-recentchangeslinked": "此頁面連結到其他頁面的近期變更",
        "tooltip-feed-rss": "訂閱此頁面的 RSS feed",
        "tooltip-feed-atom": "訂閱此頁面的 Atom feed",
        "tooltip-t-contributions": "此使用者的貢獻清單",
        "pageinfo-lasttime": "最近編輯日期",
        "pageinfo-edits": "編輯總次數",
        "pageinfo-authors": "作者總數",
-       "pageinfo-recent-edits": "最近編輯次數 (過去$1內)",
+       "pageinfo-recent-edits": "最近編輯次數 (過去 $1 內)",
        "pageinfo-recent-authors": "最近作者數",
        "pageinfo-magic-words": "魔術{{PLURAL:$1|字}} ($1)",
-       "pageinfo-hidden-categories": "隱藏分類($1)",
+       "pageinfo-hidden-categories": "隱藏分類 ($1)",
        "pageinfo-templates": "引用樣版 ($1)",
        "pageinfo-transclusions": "頁面被引用於 ($1)",
        "pageinfo-toolboxlink": "頁面資訊",
        "markaspatrolledtext": "標記此頁面為已巡查",
        "markedaspatrolled": "己標記為已巡查",
        "markedaspatrolledtext": "已標記選擇的修訂 [[:$1]] 為已巡查。",
-       "rcpatroldisabled": "最近變更巡查已停用",
+       "rcpatroldisabled": "近期變更巡查已停用",
        "rcpatroldisabledtext": "最新變更巡查的功能目前已停用。",
        "markedaspatrollederror": "無法標記為已巡查",
        "markedaspatrollederrortext": "您需指定要標記為已巡查的修訂。",
        "metadata-help": "此檔案包含額外的資訊,可能由數位相機或掃描機所建立的。\n若修改此檔案,部份資訊將無法保留。",
        "metadata-expand": "顯示詳細資料",
        "metadata-collapse": "隱藏詳細資料",
-       "metadata-fields": "在本訊息中所列出的 EXIF 元數據域將包含在圖片顯示頁面,當元數據表損壞時只顯示以下訊息。\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",
+       "metadata-fields": "在本訊息中所列出的 EXIF 詮釋資料域將包含在圖片顯示頁面,當詮釋資料表損壞時只顯示以下訊息。\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-bitspersample": "每像素位元",
        "exif-samplesperpixel": "像素數量",
        "exif-planarconfiguration": "資料排列",
        "exif-ycbcrsubsampling": "黃色轉洋紅二次抽樣比率",
-       "exif-ycbcrpositioning": "黃色和洋紅配置",
+       "exif-ycbcrpositioning": "亮度與彩度偏移",
        "exif-xresolution": "水平解析度",
        "exif-yresolution": "垂直解析度",
        "exif-stripoffsets": "影像資料位置",
        "exif-rating": "評分 (共 5 分)",
        "exif-rightscertificate": "版權管理證書",
        "exif-copyrighted": "版權狀態",
-       "exif-copyrightowner": "ç\89\88æ¬\8aæ\8c\81有人",
+       "exif-copyrightowner": "ç\89\88æ¬\8aæ\89\80有人",
        "exif-usageterms": "使用條款",
        "exif-webstatement": "線上版權聲明",
        "exif-originaldocumentid": "原始文件唯一識別碼",
        "monthsall": "全部",
        "confirmemail": "確認電子郵件位址",
        "confirmemail_noemail": "您尚未於 [[Special:Preferences|偏好設定]] 輸入一個有效的電子郵件位址。",
-       "confirmemail_text": "{{SITENAME}}è¦\81æ±\82æ\82¨å\9c¨ä½¿ç\94¨é\83µä»¶å\8a\9fè\83½ä¹\8bå\89\8dé©\97è­\89æ\82¨ç\9a\84é\83µç®±ä½\8då\9d\80ã\80\82\né»\9eé\81¸ä»¥ä¸\8bæ\8c\89é\88\95å\8f¯å\90\91æ\82¨ç\9a\84é\83µç®±å\82³é\80\81ä¸\80å°\81確èª\8dé\83µä»¶ã\80\82該é\83µä»¶å\8c\85å\90«æ\9c\89ä¸\80è¡\8c代碼é\80£çµ\90ï¼\9b\nè«\8bå\9c¨æ\82¨ç\9a\84ç\80\8f覽å\99¨ä¸­è¼\89å\85¥æ­¤é\80£çµ\90以確èª\8dæ\82¨ç\9a\84é\83µç®±位址是有效的。",
+       "confirmemail_text": "{{SITENAME}}è¦\81æ±\82æ\82¨å\9c¨ä½¿ç\94¨é\83µä»¶å\8a\9fè\83½ä¹\8bå\89\8dé©\97è­\89æ\82¨ç\9a\84é\9b»å­\90é\83µä»¶ä½\8då\9d\80ã\80\82\né»\9eé\81¸ä»¥ä¸\8bæ\8c\89é\88\95å\8f¯å\90\91æ\82¨ç\9a\84é\9b»å­\90é\83µä»¶å\82³é\80\81ä¸\80å°\81確èª\8dé\83µä»¶ã\80\82該é\83µä»¶å\8c\85å\90«æ\9c\89ä¸\80è¡\8c代碼é\80£çµ\90ï¼\9b\nè«\8bå\9c¨æ\82¨ç\9a\84ç\80\8f覽å\99¨ä¸­è¼\89å\85¥æ­¤é\80£çµ\90以確èª\8dæ\82¨ç\9a\84é\9b»å­\90é\83µä»¶位址是有效的。",
        "confirmemail_pending": "確認碼已傳送至您的電子郵件,\n若您才剛建立好您的帳號,可能需要稍後幾分鐘才能收到。\n若沒有收到,請再重新申請一次確認碼。",
        "confirmemail_send": "電子郵件寄送確認代碼",
        "confirmemail_sent": "已寄出確認電子郵件。",
-       "confirmemail_oncreate": "一個確認代碼已經被傳送到您的郵箱。該代碼並不要求您進行登入,\n但若您要啟用在此 wiki 上的任何基於電子郵件的功能,您必須先提交此代碼。",
-       "confirmemail_sendfailed": "{{SITENAME}}ç\84¡æ³\95å\82³é\80\81確èª\8dé\83µä»¶ï¼\8cè«\8b檢æ\9f¥é\83µç®±位址是否包含非法字元。\n\n郵件傳送員回應: $1",
+       "confirmemail_oncreate": "確認代碼已傳送至您的電子郵件位址。\n登入動作不需要使用此代碼,但開啟在 Wiki 中任何以電子郵件為基礎的功能會需要先提供此代碼。",
+       "confirmemail_sendfailed": "{{SITENAME}}ç\84¡æ³\95å\82³é\80\81確èª\8dé\83µä»¶ï¼\8cè«\8b檢æ\9f¥é\9b»å­\90é\83µä»¶位址是否包含非法字元。\n\n郵件傳送員回應: $1",
        "confirmemail_invalid": "無效的確認碼,該代碼可能已經過期。",
        "confirmemail_needlogin": "請 $1 以確認您的電子郵件地址。",
-       "confirmemail_success": "æ\82¨ç\9a\84é\83µç®±已經被確認。您現在可以[[Special:UserLogin|登入]]並使用此網站了。",
+       "confirmemail_success": "æ\82¨ç\9a\84é\9b»å­\90é\83µä»¶已經被確認。您現在可以[[Special:UserLogin|登入]]並使用此網站了。",
        "confirmemail_loggedin": "已確認您的電子郵件地址。",
        "confirmemail_subject": "{{SITENAME}} 電子郵件地址確認",
        "confirmemail_body": "不明人士 (可能是您自己,來自 IP 位址 $1)  已在 {{SITENAME}} 註冊了一個帳號 \"$2\" 並使用了此電子郵件位址。\n\n請確認這個帳號是屬於您的,並使用瀏覽器開啟下方連結以啟用在 {{SITENAME}} 上的電子郵件功能:\n\n$3\n\n若您 *未* 註冊此帳號,\n請開啟下方連結取消電子郵件確認:\n\n$5\n\n此確認代碼會於 $4 過期。",
        "version-extensions": "已安裝的擴充套件",
        "version-skins": "已安裝的外觀",
        "version-specialpages": "特殊頁面",
-       "version-parserhooks": "解析器連結(Hook)",
+       "version-parserhooks": "解析器連結 (Hook)",
        "version-variables": "變數",
        "version-antispam": "垃圾訊息防止",
        "version-other": "其他",
        "version-mediahandlers": "媒體處理器",
-       "version-hooks": "連結(Hooks)",
+       "version-hooks": "連結 (Hooks)",
        "version-parser-extensiontags": "解析器擴充標籤",
        "version-parser-function-hooks": "語法函數連結",
        "version-hook-name": "連結名稱",
        "redirect-file": "檔案名稱",
        "redirect-not-exists": "查無值",
        "fileduplicatesearch": "搜尋重覆檔案",
-       "fileduplicatesearch-summary": "依據雜湊值(Hash)來搜尋重複的檔案。",
+       "fileduplicatesearch-summary": "依據雜湊值 (Hash) 來搜尋重複的檔案。",
        "fileduplicatesearch-legend": "搜尋重覆",
        "fileduplicatesearch-filename": "檔案名稱:",
        "fileduplicatesearch-submit": "搜尋",
        "specialpages-group-maintenance": "維護報表",
        "specialpages-group-other": "其它特殊頁面",
        "specialpages-group-login": "登入 / 建立帳號",
-       "specialpages-group-changes": "最近變更與日誌",
+       "specialpages-group-changes": "近期變更與日誌",
        "specialpages-group-media": "媒體上傳與報表",
        "specialpages-group-users": "使用者與權限",
        "specialpages-group-highuse": "常用頁面",
        "tag-filter-submit": "搜尋",
        "tag-list-wrapper": "([[Special:Tags|標籤]]:$2)",
        "tags-title": "標籤",
-       "tags-intro": "這個頁面列示出在軟件中已標示的編輯,以及它們的解釋。",
+       "tags-intro": "此頁面列出所有可用來標示編輯的標籤,以及這些標籤的含意。",
        "tags-tag": "標籤名稱",
        "tags-display-header": "在更改清單中的出現方式",
        "tags-description-header": "完整含意說明",
        "mediastatistics-header-text": "純文字",
        "mediastatistics-header-executable": "可執行",
        "mediastatistics-header-archive": "已壓縮格式",
+       "json-warn-trailing-comma": "已移除 $1 個 JSON 結尾的{{PLURAL:$1|逗號|逗號}}",
        "json-error-unknown": "JSON 發生問題。錯誤:$1",
        "json-error-depth": "已超出堆疊深度限制",
        "json-error-state-mismatch": "無效或格式不正確的 JSON",
index acb2020..d62cd4c 100644 (file)
@@ -388,6 +388,7 @@ $specialPageAliases = array(
        'Allmessages'               => array( 'AllMessages' ),
        'AllMyUploads'              => array( 'AllMyUploads', 'AllMyFiles' ),
        'Allpages'                  => array( 'AllPages' ),
+       'ApiHelp'                   => array( 'ApiHelp' ),
        'Ancientpages'              => array( 'AncientPages' ),
        'Badtitle'                  => array( 'Badtitle' ),
        'Blankpage'                 => array( 'BlankPage' ),
@@ -536,7 +537,7 @@ $preloadedMessages = array(
        'accesskey-ca-history',
        'accesskey-ca-nstab-main',
        'accesskey-ca-talk',
-       'accesskey-ca-view',
+       'accesskey-ca-viewsource',
        'accesskey-n-currentevents',
        'accesskey-n-help',
        'accesskey-n-mainpage-description',
@@ -545,16 +546,20 @@ $preloadedMessages = array(
        'accesskey-n-recentchanges',
        'accesskey-p-logo',
        'accesskey-pt-login',
+       'accesskey-pt-createaccount',
        'accesskey-search',
        'accesskey-search-fulltext',
        'accesskey-search-go',
        'accesskey-t-info',
        'accesskey-t-permalink',
+       'accesskey-t-print',
        'accesskey-t-recentchangeslinked',
        'accesskey-t-specialpages',
        'accesskey-t-whatlinkshere',
        'actions',
        'anonnotice',
+       'brackets',
+       'comma-separator',
        'currentevents',
        'currentevents-url',
        'disclaimerpage',
@@ -576,7 +581,6 @@ $preloadedMessages = array(
        'navigation',
        'nav-login-createaccount',
        'nstab-main',
-       'nstab-talk',
        'opensearch-desc',
        'pagecategories',
        'pagecategorieslink',
@@ -598,6 +602,7 @@ $preloadedMessages = array(
        'search',
        'searcharticle',
        'searchbutton',
+       'searchsuggest-search',
        'sidebar',
        'navigation-heading',
        'site-atom-feed',
@@ -610,7 +615,7 @@ $preloadedMessages = array(
        'tooltip-ca-history',
        'tooltip-ca-nstab-main',
        'tooltip-ca-talk',
-       'tooltip-ca-view',
+       'tooltip-ca-viewsource',
        'tooltip-n-currentevents',
        'tooltip-n-help',
        'tooltip-n-mainpage-description',
@@ -618,14 +623,14 @@ $preloadedMessages = array(
        'tooltip-n-randompage',
        'tooltip-n-recentchanges',
        'tooltip-p-logo',
-       'tooltip-p-navigation',
-       'tooltip-p-tb',
        'tooltip-pt-login',
+       'tooltip-pt-createaccount',
        'tooltip-search',
        'tooltip-search-fulltext',
        'tooltip-search-go',
        'tooltip-t-info',
        'tooltip-t-permalink',
+       'tooltip-t-print',
        'tooltip-t-recentchangeslinked',
        'tooltip-t-specialpages',
        'tooltip-t-whatlinkshere',
@@ -636,5 +641,6 @@ $preloadedMessages = array(
        'viewcount',
        'views',
        'whatlinkshere',
+       'word-separator',
 );
 
index 7c2e8b3..acc937e 100644 (file)
@@ -772,6 +772,17 @@ return array(
                'raw' => true,
                'targets' => array( 'desktop', 'mobile' ),
        ),
+       'mediawiki.apihelp' => array(
+               'styles' => 'resources/src/mediawiki/mediawiki.apihelp.css',
+               'targets' => array( 'desktop' ),
+               'dependencies' => array(
+                       'mediawiki.hlist',
+               ),
+       ),
+       'mediawiki.apipretty' => array(
+               'styles' => 'resources/src/mediawiki/mediawiki.apipretty.css',
+               'targets' => array( 'desktop', 'mobile' ),
+       ),
        'mediawiki.api' => array(
                'scripts' => 'resources/src/mediawiki.api/mediawiki.api.js',
                'dependencies' => 'mediawiki.util',
index 6b0bf99..55f2f89 100644 (file)
@@ -25,5 +25,9 @@
 
 .mw-changeslist-legend dd {
        margin-left: 1.5em;
+}
+
+.mw-changeslist-legend dt,
+.mw-changeslist-legend dd {
        line-height: 1.3em;
 }
diff --git a/resources/src/mediawiki/mediawiki.apihelp.css b/resources/src/mediawiki/mediawiki.apihelp.css
new file mode 100644 (file)
index 0000000..d127232
--- /dev/null
@@ -0,0 +1,86 @@
+.apihelp-header {
+       clear: both;
+       margin-bottom: 0.1em;
+}
+
+div.apihelp-linktrail {
+       font-size: smaller;
+}
+
+.apihelp-block {
+       margin-top: 0.5em;
+}
+
+.apihelp-block-head {
+       font-weight: bold;
+}
+
+.apihelp-flags {
+       font-size: smaller;
+       float: right;
+       border: 1px solid black;
+       padding: 0.25em;
+       width: 20em;
+}
+
+.apihelp-deprecated, .apihelp-flag-deprecated,
+.apihelp-flag-internal strong {
+       font-weight: bold;
+       color: red;
+}
+
+.apihelp-empty {
+       color: #888;
+}
+
+.apihelp-help-urls ul {
+       list-style-image: none;
+       list-style-type: none;
+       margin-left: 0;
+}
+
+.apihelp-parameters dl,
+.apihelp-examples dl,
+.apihelp-permissions dl {
+       margin-left: 2em;
+}
+
+.apihelp-parameters dt {
+       float: left;
+       clear: left;
+       min-width: 10em;
+       white-space: nowrap;
+       line-height: 1.5em;
+}
+
+.apihelp-parameters dt:after {
+       content: ':\A0'
+}
+
+.apihelp-parameters dd {
+       margin: 0 0 0.5em 10em;
+       line-height: 1.5em;
+}
+
+.apihelp-parameters dd p:first-child {
+       margin-top: 0;
+}
+
+.apihelp-parameters dd.info {
+       margin-left: 12em;
+       text-indent: -2em;
+}
+
+.apihelp-examples dt {
+       font-weight: normal;
+}
+
+.api-main-links {
+       text-align: center;
+}
+.api-main-links ul:before {
+       content: '[';
+}
+.api-main-links ul:after {
+       content: ']';
+}
diff --git a/resources/src/mediawiki/mediawiki.apipretty.css b/resources/src/mediawiki/mediawiki.apipretty.css
new file mode 100644 (file)
index 0000000..fe5e634
--- /dev/null
@@ -0,0 +1,11 @@
+h1.firstHeading {
+       display: none;
+}
+
+.api-pretty-header {
+       font-size: small;
+}
+
+.api-pretty-content {
+       white-space: pre-wrap;
+}
index 780cf9e..4bf6deb 100644 (file)
 class ApiMainTest extends ApiTestCase {
 
        /**
-        * Test that the API will accept a FauxRequest and execute. The help action
-        * (default) throws a UsageException. Just validate we're getting proper XML
-        *
-        * @expectedException UsageException
+        * Test that the API will accept a FauxRequest and execute.
         */
        public function testApi() {
                $api = new ApiMain(
-                       new FauxRequest( array( 'action' => 'help', 'format' => 'xml' ) )
+                       new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) )
                );
                $api->execute();
-               $api->getPrinter()->setBufferResult( true );
-               $api->printResult( false );
-               $resp = $api->getPrinter()->getBuffer();
-
-               libxml_use_internal_errors( true );
-               $sxe = simplexml_load_string( $resp );
-               $this->assertNotInternalType( "bool", $sxe );
-               $this->assertThat( $sxe, $this->isInstanceOf( "SimpleXMLElement" ) );
+               $data = $api->getResultData();
+               $this->assertInternalType( 'array', $data );
+               $this->assertArrayHasKey( 'query', $data );
        }
 
        public static function provideAssert() {
index 13da33c..d04766b 100644 (file)
@@ -20,7 +20,7 @@ class PrefixUniquenessTest extends MediaWikiTestCase {
                        $class = get_class( $module );
 
                        $prefix = $module->getModulePrefix();
-                       if ( isset( $prefixes[$prefix] ) ) {
+                       if ( $prefix !== '' && isset( $prefixes[$prefix] ) ) {
                                $this->fail( "Module prefix '{$prefix}' is shared between {$class} and {$prefixes[$prefix]}" );
                        }
                        $prefixes[$module->getModulePrefix()] = $class;
index 5f6d53c..af77570 100644 (file)
@@ -16,15 +16,12 @@ abstract class ApiFormatTestBase extends ApiTestCase {
                $module = $data[3];
 
                $printer = $module->createPrinterByName( $format );
-               $printer->setUnescapeAmps( false );
-
-               $printer->initPrinter( false );
 
                ob_start();
+               $printer->initPrinter( false );
                $printer->execute();
-               $out = ob_get_clean();
-
                $printer->closePrinter();
+               $out = ob_get_clean();
 
                return $out;
        }
index 347cd6f..46f1b7b 100644 (file)
@@ -62,7 +62,8 @@ class ApiQueryContinue2Test extends ApiQueryContinueTestBase {
                        );
                };
                // generator + 1 prop + 1 list
-               $data = $this->query( $mk( 99, 99, true ), 1, 'g1p', false );
+               $data = $this->query( $mk( 99, 99, true ), 1, 'g1p', false ) +
+                       array( 'batchcomplete' => '' );
                $this->checkC( $data, $mk( 1, 1, true ), 6, 'g1p-11t' );
                $this->checkC( $data, $mk( 2, 2, true ), 3, 'g1p-22t' );
                $this->checkC( $data, $mk( 1, 1, false ), 6, 'g1p-11f' );
index 0379790..328d839 100644 (file)
@@ -68,7 +68,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
                                'aplimit' => "$l",
                        );
                };
-               $data = $this->query( $mk( 99 ), 1, '1L', false );
+               $data = $this->query( $mk( 99 ), 1, '1L', false ) +
+                       array( 'batchcomplete' => '' );
 
                // 1 list
                $this->checkC( $data, $mk( 1 ), 5, '1L-1' );
@@ -95,7 +96,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
                        );
                };
                // 2 lists
-               $data = $this->query( $mk( 99, 99 ), 1, '2L', false );
+               $data = $this->query( $mk( 99, 99 ), 1, '2L', false ) +
+                       array( 'batchcomplete' => '' );
                $this->checkC( $data, $mk( 1, 1 ), 5, '2L-11' );
                $this->checkC( $data, $mk( 2, 2 ), 3, '2L-22' );
                $this->checkC( $data, $mk( 3, 3 ), 2, '2L-33' );
@@ -119,7 +121,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
                        );
                };
                // generator + 1 prop
-               $data = $this->query( $mk( 99, 99 ), 1, 'G1P', false );
+               $data = $this->query( $mk( 99, 99 ), 1, 'G1P', false ) +
+                       array( 'batchcomplete' => '' );
                $this->checkC( $data, $mk( 1, 1 ), 11, 'G1P-11' );
                $this->checkC( $data, $mk( 2, 2 ), 6, 'G1P-22' );
                $this->checkC( $data, $mk( 3, 3 ), 4, 'G1P-33' );
@@ -144,7 +147,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
                        );
                };
                // generator + 2 props
-               $data = $this->query( $mk( 99, 99, 99 ), 1, 'G2P', false );
+               $data = $this->query( $mk( 99, 99, 99 ), 1, 'G2P', false ) +
+                       array( 'batchcomplete' => '' );;
                $this->checkC( $data, $mk( 1, 1, 1 ), 16, 'G2P-111' );
                $this->checkC( $data, $mk( 2, 2, 2 ), 9, 'G2P-222' );
                $this->checkC( $data, $mk( 3, 3, 3 ), 6, 'G2P-333' );
@@ -177,7 +181,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
                        );
                };
                // generator + 1 prop + 1 list
-               $data = $this->query( $mk( 99, 99, 99 ), 1, 'G1P1L', false );
+               $data = $this->query( $mk( 99, 99, 99 ), 1, 'G1P1L', false ) +
+                       array( 'batchcomplete' => '' );
                $this->checkC( $data, $mk( 1, 1, 1 ), 11, 'G1P1L-111' );
                $this->checkC( $data, $mk( 2, 2, 2 ), 6, 'G1P1L-222' );
                $this->checkC( $data, $mk( 3, 3, 3 ), 4, 'G1P1L-333' );
@@ -214,7 +219,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
                        );
                };
                // generator + 1 prop + 1 list
-               $data = $this->query( $mk( 99, 99, 99, 99, 99 ), 1, 'G2P2L1M', false );
+               $data = $this->query( $mk( 99, 99, 99, 99, 99 ), 1, 'G2P2L1M', false ) +
+                       array( 'batchcomplete' => '' );
                $this->checkC( $data, $mk( 1, 1, 1, 1, 1 ), 16, 'G2P2L1M-11111' );
                $this->checkC( $data, $mk( 2, 2, 2, 2, 2 ), 9, 'G2P2L1M-22222' );
                $this->checkC( $data, $mk( 3, 3, 3, 3, 3 ), 6, 'G2P2L1M-33333' );
@@ -244,7 +250,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
                        );
                };
                // generator + 1 prop
-               $data = $this->query( $mk( 99, true, 99, true ), 1, 'G=P', false );
+               $data = $this->query( $mk( 99, true, 99, true ), 1, 'G=P', false ) +
+                       array( 'batchcomplete' => '' );
 
                $this->checkC( $data, $mk( 1, true, 1, true ), 4, 'G=P-1t1t' );
                $this->checkC( $data, $mk( 2, true, 2, true ), 2, 'G=P-2t2t' );
@@ -290,7 +297,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
                        );
                };
                // generator + 1 list
-               $data = $this->query( $mk( 99, true, 99, true ), 1, 'G=L', false );
+               $data = $this->query( $mk( 99, true, 99, true ), 1, 'G=L', false ) +
+                       array( 'batchcomplete' => '' );
 
                $this->checkC( $data, $mk( 1, true, 1, true ), 5, 'G=L-1t1t' );
                $this->checkC( $data, $mk( 2, true, 2, true ), 3, 'G=L-2t2t' );
index 7171ee5..f0c829c 100644 (file)
@@ -99,6 +99,10 @@ class ORMTableTest extends MediaWikiTestCase {
 
 class PageORMTableForTesting extends ORMTable {
 
+       public function __construct() {
+               $this->fieldPrefix = 'page_';
+       }
+
        /**
         * @see ORMTable::getName
         *
@@ -138,13 +142,4 @@ class PageORMTableForTesting extends ORMTable {
                        'title' => 'str',
                );
        }
-
-       /**
-        * @see ORMTable::getFieldPrefix
-        *
-        * @return string
-        */
-       protected function getFieldPrefix() {
-               return 'page_';
-       }
 }
index c9459c9..ca31cf9 100644 (file)
@@ -150,6 +150,10 @@ class TestORMRow extends ORMRow {
 
 class TestORMTable extends ORMTable {
 
+       public function __construct() {
+               $this->fieldPrefix = 'test_';
+       }
+
        /**
         * Returns the name of the database table objects of this type are stored in.
         *
@@ -204,15 +208,4 @@ class TestORMTable extends ORMTable {
                        'time' => 'str', // TS_MW
                );
        }
-
-       /**
-        * Gets the db field prefix.
-        *
-        * @since 1.20
-        *
-        * @return string
-        */
-       protected function getFieldPrefix() {
-               return 'test_';
-       }
 }
index 29c3052..abff3e6 100644 (file)
@@ -273,7 +273,7 @@ class FakeDatabaseUpdater extends DatabaseUpdater {
                return true;
        }
 
-       public function setAppliedUpdates( $version, $updates ) {
+       public function setAppliedUpdates( $version, $updates = array() ) {
                parent::setAppliedUpdates( $version, $updates );
        }
 }