Merge "Use WikiPage::loadPageData() to reload data from the master."
authorAaron Schulz <aschulz@wikimedia.org>
Thu, 26 Jul 2012 21:45:26 +0000 (21:45 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 26 Jul 2012 21:45:26 +0000 (21:45 +0000)
42 files changed:
RELEASE-NOTES-1.20
includes/AutoLoader.php
includes/DefaultSettings.php
includes/ZhConversion.php
includes/db/IORMRow.php
includes/db/IORMTable.php
includes/db/ORMResult.php
includes/db/ORMRow.php
includes/db/ORMTable.php
includes/filerepo/FileRepo.php
includes/media/Generic.php [deleted file]
includes/media/ImageHandler.php [new file with mode: 0644]
includes/media/MediaHandler.php [new file with mode: 0644]
includes/objectcache/MemcachedClient.php
includes/parser/CoreParserFunctions.php
includes/parser/Parser.php
includes/zhtable/toCN.manual
includes/zhtable/tradphrases.manual
languages/Names.php
languages/messages/MessagesEn.php
languages/messages/MessagesKk_cn.php
languages/messages/MessagesKu_arab.php
languages/messages/MessagesTru.php [new file with mode: 0644]
maintenance/jsparse.php
maintenance/lag.php
maintenance/mctest.php
maintenance/mergeMessageFileList.php
maintenance/migrateUserGroup.php
maintenance/minify.php
maintenance/moveBatch.php
maintenance/namespaceDupes.php
maintenance/nextJobDB.php
maintenance/nukeNS.php
maintenance/nukePage.php
maintenance/orphans.php
maintenance/syncFileBackend.php
resources/mediawiki/mediawiki.Uri.js
skins/common/commonElements.css
skins/common/shared.css
tests/phpunit/MediaWikiTestCase.php
tests/qunit/suites/resources/mediawiki/mediawiki.Uri.test.js
thumb.php

index b859eb1..2521804 100644 (file)
@@ -99,6 +99,8 @@ upgrade PHP if you have not done so prior to upgrading MediaWiki.
   instead of the site content language
 * (bug 37926) Deleterevision will no longer allow users to delete log entries,
   the new deletelogentry permission is required for this.
+* (bug 14237) Allow PAGESINCATEGORY to distinguish between 'all', 'pages', 'files'
+  and 'subcats'
 
 === Bug fixes in 1.20 ===
 * (bug 30245) Use the correct way to construct a log page title.
@@ -150,7 +152,6 @@ upgrade PHP if you have not done so prior to upgrading MediaWiki.
   who don't have access to /tmp can specify an alternative.
 * (bug 27283) SqlBagOStuff breaks PostgreSQL transactions.
 * (bug 35727) mw.Api ajax() should put token parameter last.
-* (bug 260) Handle <pre> overflow automatically with a scroll bar.
 * (bug 37708) mw.Uri.clone() should make a deep copy.
 * (bug 38024) ResourceLoader should not create empty stylesheets for modules
   that don't have stylesheets.
@@ -216,6 +217,7 @@ changes to languages because of Bugzilla reports.
 * (bug 35541) Namespace gender aliases for Croatian (hr).
 * (bug 36012) Space in $separatorTransformTable should be non-breaking in
   Portuguese, Esperanto and Udmurt.
+* Turoyo (tru) added.
 
 === Other changes in 1.20 ===
 * The user_token field is now left empty until a user attempts to login and
index 6c37d1a..2987b31 100644 (file)
@@ -689,11 +689,11 @@ $wgAutoloadLocalClasses = array(
        'FormatMetadata' => 'includes/media/FormatMetadata.php',
        'GIFHandler' => 'includes/media/GIF.php',
        'GIFMetadataExtractor' => 'includes/media/GIFMetadataExtractor.php',
-       'ImageHandler' => 'includes/media/Generic.php',
+       'ImageHandler' => 'includes/media/ImageHandler.php',
        'IPTC' => 'includes/media/IPTC.php',
        'JpegHandler' => 'includes/media/Jpeg.php',
        'JpegMetadataExtractor' => 'includes/media/JpegMetadataExtractor.php',
-       'MediaHandler' => 'includes/media/Generic.php',
+       'MediaHandler' => 'includes/media/MediaHandler.php',
        'MediaTransformError' => 'includes/media/MediaTransformOutput.php',
        'MediaTransformOutput' => 'includes/media/MediaTransformOutput.php',
        'PNGHandler' => 'includes/media/PNG.php',
index d7feab8..abf25dc 100644 (file)
@@ -358,9 +358,11 @@ $wgImgAuthPublicTest = true;
  *
  * For most core repos:
  *   - zones            Associative array of zone names that each map to an array with:
- *                          container : backend container name the zone is in
- *                          directory : root path within container for the zone
- *                          url       : base URL to the root of the zone
+ *                          container  : backend container name the zone is in
+ *                          directory  : root path within container for the zone
+ *                          url        : base URL to the root of the zone
+ *                          handlerUrl : base script handled URL to the root of the zone
+ *                                       (see FileRepo::getZoneHandlerUrl() function)
  *                      Zones default to using "<repo name>-<zone name>" as the container name
  *                      and default to using the container root as the zone's root directory.
  *                      Nesting of zone locations within other zones should be avoided.
index 0595923..b98f521 100644 (file)
@@ -7061,6 +7061,7 @@ $zh2Hant = array(
 '皇庄' => '皇莊',
 '皓发' => '皓髮',
 '皮制服' => '皮制服',
+'皮肤' => '皮膚',
 '皮里春秋' => '皮裡春秋',
 '皮里阳秋' => '皮裡陽秋',
 '皮制' => '皮製',
@@ -8409,6 +8410,7 @@ $zh2Hant = array(
 '跌扑' => '跌扑',
 '跌荡' => '跌蕩',
 '路签' => '路籤',
+'路面' => '路面',
 '跳梁小丑' => '跳樑小丑',
 '跳荡' => '跳蕩',
 '跳表' => '跳錶',
@@ -18192,7 +18194,6 @@ $zh2CN = array(
 '攜帶型' => '便携式',
 '資訊理論' => '信息论',
 '母音' => '元音',
-'游標' => '光标',
 '光碟' => '光盘',
 '光碟機' => '光驱',
 '柯林頓' => '克林顿',
@@ -18455,4 +18456,4 @@ $zh2SG = array(
 '笨豬跳' => '绑紧跳',
 '蹦极跳' => '绑紧跳',
 '笑星' => '谐星',
-);
\ No newline at end of file
+);
index a530620..e99ba6c 100644 (file)
@@ -5,6 +5,8 @@
  * aims to be both simple and very flexible. It is centered around an associative
  * array of fields and various methods to do common interaction with the database.
  *
+ * Documentation inline and at https://www.mediawiki.org/wiki/Manual:ORMTable
+ *
  * 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
index 684f4b4..99413f9 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 /**
  * Interface for objects representing a single database table.
+ * Documentation inline and at https://www.mediawiki.org/wiki/Manual:ORMTable
  *
  * 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
index 3f2d803..2a5837a 100644 (file)
@@ -3,6 +3,8 @@
  * ORMIterator that takes a ResultWrapper object returned from
  * a select operation returning IORMRow objects (ie IORMTable::select).
  *
+ * Documentation inline and at https://www.mediawiki.org/wiki/Manual:ORMTable
+ *
  * 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
index 6f19fe1..303f3a2 100644 (file)
@@ -5,6 +5,8 @@
  * aims to be both simple and very flexible. It is centered around an associative
  * array of fields and various methods to do common interaction with the database.
  *
+ * Documentation inline and at https://www.mediawiki.org/wiki/Manual:ORMTable
+ *
  * 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
index 1c9497a..a4396af 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 /**
  * Abstract base class for representing a single database table.
+ * Documentation inline and at https://www.mediawiki.org/wiki/Manual:ORMTable
  *
  * 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
@@ -590,7 +591,7 @@ abstract class ORMTable implements IORMTable {
        /**
         * @see ORMTable::newRowFromFromDBResult
         *
-        * @deprecated use newRowFromFromDBResult instead
+        * @deprecated use newRowFromDBResult instead
         * @since 1.20
         *
         * @param stdClass $result
index 5a55096..32ef5a9 100644 (file)
@@ -216,6 +216,28 @@ class FileRepo {
                }
        }
 
+       /**
+        * Get the thumb zone URL configured to be handled by scripts like thumb_handler.php.
+        * This is probably only useful for internal requests, such as from a fast frontend server
+        * to a slower backend server.
+        *
+        * Large sites may use a different host name for uploads than for wikis. In any case, the
+        * wiki configuration is needed in order to use thumb.php. To avoid extracting the wiki ID
+        * from the URL path, one can configure thumb_handler.php to recognize a special path on the
+        * same host name as the wiki that is used for viewing thumbnails.
+        *
+        * @param $zone String: one of: public, deleted, temp, thumb
+        * @return String or false
+        */
+       public function getZoneHandlerUrl( $zone ) {
+               if ( isset( $this->zones[$zone]['handlerUrl'] )
+                       && in_array( $zone, array( 'public', 'temp', 'thumb' ) ) )
+               {
+                       return $this->zones[$zone]['handlerUrl'];
+               }
+               return false;
+       }
+
        /**
         * Get the backend storage path corresponding to a virtual URL.
         * Use this function wisely.
diff --git a/includes/media/Generic.php b/includes/media/Generic.php
deleted file mode 100644 (file)
index bd4d865..0000000
+++ /dev/null
@@ -1,780 +0,0 @@
-<?php
-/**
- * Media-handling base classes and generic functionality.
- *
- * 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 Media
- */
-
-/**
- * Base media handler class
- *
- * @ingroup Media
- */
-abstract class MediaHandler {
-       const TRANSFORM_LATER = 1;
-       const METADATA_GOOD = true;
-       const METADATA_BAD = false;
-       const METADATA_COMPATIBLE = 2; // for old but backwards compatible.
-       /**
-        * Instance cache
-        */
-       static $handlers = array();
-
-       /**
-        * Get a MediaHandler for a given MIME type from the instance cache
-        *
-        * @param $type string
-        *
-        * @return MediaHandler
-        */
-       static function getHandler( $type ) {
-               global $wgMediaHandlers;
-               if ( !isset( $wgMediaHandlers[$type] ) ) {
-                       wfDebug( __METHOD__ . ": no handler found for $type.\n");
-                       return false;
-               }
-               $class = $wgMediaHandlers[$type];
-               if ( !isset( self::$handlers[$class] ) ) {
-                       self::$handlers[$class] = new $class;
-                       if ( !self::$handlers[$class]->isEnabled() ) {
-                               self::$handlers[$class] = false;
-                       }
-               }
-               return self::$handlers[$class];
-       }
-
-       /**
-        * Get an associative array mapping magic word IDs to parameter names.
-        * Will be used by the parser to identify parameters.
-        */
-       abstract function getParamMap();
-
-       /**
-        * Validate a thumbnail parameter at parse time.
-        * Return true to accept the parameter, and false to reject it.
-        * If you return false, the parser will do something quiet and forgiving.
-        *
-        * @param $name
-        * @param $value
-        */
-       abstract function validateParam( $name, $value );
-
-       /**
-        * Merge a parameter array into a string appropriate for inclusion in filenames
-        *
-        * @param $params array
-        */
-       abstract function makeParamString( $params );
-
-       /**
-        * Parse a param string made with makeParamString back into an array
-        *
-        * @param $str string
-        */
-       abstract function parseParamString( $str );
-
-       /**
-        * Changes the parameter array as necessary, ready for transformation.
-        * Should be idempotent.
-        * Returns false if the parameters are unacceptable and the transform should fail
-        * @param $image
-        * @param $params
-        */
-       abstract function normaliseParams( $image, &$params );
-
-       /**
-        * Get an image size array like that returned by getimagesize(), or false if it
-        * can't be determined.
-        *
-        * @param $image File: the image object, or false if there isn't one
-        * @param $path String: the filename
-        * @return Array Follow the format of PHP getimagesize() internal function. See http://www.php.net/getimagesize
-        */
-       abstract function getImageSize( $image, $path );
-
-       /**
-        * Get handler-specific metadata which will be saved in the img_metadata field.
-        *
-        * @param $image File: the image object, or false if there isn't one.
-        *   Warning, FSFile::getPropsFromPath might pass an (object)array() instead (!)
-        * @param $path String: the filename
-        * @return String
-        */
-       function getMetadata( $image, $path ) { return ''; }
-
-       /**
-       * Get metadata version.
-       *
-       * This is not used for validating metadata, this is used for the api when returning
-       * metadata, since api content formats should stay the same over time, and so things
-       * using ForiegnApiRepo can keep backwards compatibility
-       *
-       * All core media handlers share a common version number, and extensions can
-       * use the GetMetadataVersion hook to append to the array (they should append a unique
-       * string so not to get confusing). If there was a media handler named 'foo' with metadata
-       * version 3 it might add to the end of the array the element 'foo=3'. if the core metadata
-       * version is 2, the end version string would look like '2;foo=3'.
-       *
-       * @return string version string
-       */
-       static function getMetadataVersion () {
-               $version = Array( '2' ); // core metadata version
-               wfRunHooks('GetMetadataVersion', Array(&$version));
-               return implode( ';', $version);
-        }
-
-       /**
-       * Convert metadata version.
-       *
-       * By default just returns $metadata, but can be used to allow
-       * media handlers to convert between metadata versions.
-       *
-       * @param $metadata Mixed String or Array metadata array (serialized if string)
-       * @param $version Integer target version
-       * @return Array serialized metadata in specified version, or $metadata on fail.
-       */
-       function convertMetadataVersion( $metadata, $version = 1 ) {
-               if ( !is_array( $metadata ) ) {
-
-                       //unserialize to keep return parameter consistent.
-                       wfSuppressWarnings();
-                       $ret = unserialize( $metadata );
-                       wfRestoreWarnings();
-                       return $ret;
-               }
-               return $metadata;
-       }
-
-       /**
-        * Get a string describing the type of metadata, for display purposes.
-        *
-        * @return string
-        */
-       function getMetadataType( $image ) { return false; }
-
-       /**
-        * Check if the metadata string is valid for this handler.
-        * If it returns MediaHandler::METADATA_BAD (or false), Image
-        * will reload the metadata from the file and update the database.
-        * MediaHandler::METADATA_GOOD for if the metadata is a-ok,
-        * MediaHanlder::METADATA_COMPATIBLE if metadata is old but backwards
-        * compatible (which may or may not trigger a metadata reload).
-        * @return bool
-        */
-       function isMetadataValid( $image, $metadata ) {
-               return self::METADATA_GOOD;
-       }
-
-
-       /**
-        * Get a MediaTransformOutput object representing an alternate of the transformed
-        * output which will call an intermediary thumbnail assist script.
-        *
-        * Used when the repository has a thumbnailScriptUrl option configured.
-        *
-        * Return false to fall back to the regular getTransform().
-        * @return bool
-        */
-       function getScriptedTransform( $image, $script, $params ) {
-               return false;
-       }
-
-       /**
-        * Get a MediaTransformOutput object representing the transformed output. Does not
-        * actually do the transform.
-        *
-        * @param $image File: the image object
-        * @param $dstPath String: filesystem destination path
-        * @param $dstUrl String: Destination URL to use in output HTML
-        * @param $params Array: Arbitrary set of parameters validated by $this->validateParam()
-        * @return MediaTransformOutput
-        */
-       final function getTransform( $image, $dstPath, $dstUrl, $params ) {
-               return $this->doTransform( $image, $dstPath, $dstUrl, $params, self::TRANSFORM_LATER );
-       }
-
-       /**
-        * Get a MediaTransformOutput object representing the transformed output. Does the
-        * transform unless $flags contains self::TRANSFORM_LATER.
-        *
-        * @param $image File: the image object
-        * @param $dstPath String: filesystem destination path
-        * @param $dstUrl String: destination URL to use in output HTML
-        * @param $params Array: arbitrary set of parameters validated by $this->validateParam()
-        * @param $flags Integer: a bitfield, may contain self::TRANSFORM_LATER
-        *
-        * @return MediaTransformOutput
-        */
-       abstract function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 );
-
-       /**
-        * Get the thumbnail extension and MIME type for a given source MIME type
-        * @return array thumbnail extension and MIME type
-        */
-       function getThumbType( $ext, $mime, $params = null ) {
-               $magic = MimeMagic::singleton();
-               if ( !$ext || $magic->isMatchingExtension( $ext, $mime ) === false ) {
-                       // The extension is not valid for this mime type and we do
-                       // recognize the mime type
-                       $extensions = $magic->getExtensionsForType( $mime );
-                       if ( $extensions ) {
-                               return array( strtok( $extensions, ' ' ), $mime );
-                       }
-               }
-
-               // The extension is correct (true) or the mime type is unknown to
-               // MediaWiki (null)
-               return array( $ext, $mime );
-       }
-
-       /**
-        * True if the handled types can be transformed
-        * @return bool
-        */
-       function canRender( $file ) { return true; }
-       /**
-        * True if handled types cannot be displayed directly in a browser
-        * but can be rendered
-        * @return bool
-        */
-       function mustRender( $file ) { return false; }
-       /**
-        * True if the type has multi-page capabilities
-        * @return bool
-        */
-       function isMultiPage( $file ) { return false; }
-       /**
-        * Page count for a multi-page document, false if unsupported or unknown
-        * @return bool
-        */
-       function pageCount( $file ) { return false; }
-       /**
-        * The material is vectorized and thus scaling is lossless
-        * @return bool
-        */
-       function isVectorized( $file ) { return false; }
-       /**
-        * False if the handler is disabled for all files
-        * @return bool
-        */
-       function isEnabled() { return true; }
-
-       /**
-        * Get an associative array of page dimensions
-        * Currently "width" and "height" are understood, but this might be
-        * expanded in the future.
-        * Returns false if unknown or if the document is not multi-page.
-        *
-        * @param $image File
-        * @param $page Unused, left for backcompatibility?
-        * @return array
-        */
-       function getPageDimensions( $image, $page ) {
-               $gis = $this->getImageSize( $image, $image->getLocalRefPath() );
-               return array(
-                       'width' => $gis[0],
-                       'height' => $gis[1]
-               );
-       }
-
-       /**
-        * Generic getter for text layer.
-        * Currently overloaded by PDF and DjVu handlers
-        * @return bool
-        */
-       function getPageText( $image, $page ) {
-               return false;
-       }
-
-       /**
-        * Get an array structure that looks like this:
-        *
-        * array(
-        *    'visible' => array(
-        *       'Human-readable name' => 'Human readable value',
-        *       ...
-        *    ),
-        *    'collapsed' => array(
-        *       'Human-readable name' => 'Human readable value',
-        *       ...
-        *    )
-        * )
-        * The UI will format this into a table where the visible fields are always
-        * visible, and the collapsed fields are optionally visible.
-        *
-        * The function should return false if there is no metadata to display.
-        */
-
-       /**
-        * @todo FIXME: I don't really like this interface, it's not very flexible
-        * I think the media handler should generate HTML instead. It can do
-        * all the formatting according to some standard. That makes it possible
-        * to do things like visual indication of grouped and chained streams
-        * in ogg container files.
-        * @return bool
-        */
-       function formatMetadata( $image ) {
-               return false;
-       }
-
-       /** sorts the visible/invisible field.
-        * Split off from ImageHandler::formatMetadata, as used by more than
-        * one type of handler.
-        *
-        * This is used by the media handlers that use the FormatMetadata class
-        *
-        * @param $metadataArray Array metadata array
-        * @return array for use displaying metadata.
-        */
-       function formatMetadataHelper( $metadataArray ) {
-                $result = array(
-                       'visible' => array(),
-                       'collapsed' => array()
-               );
-
-               $formatted = FormatMetadata::getFormattedData( $metadataArray );
-               // Sort fields into visible and collapsed
-               $visibleFields = $this->visibleMetadataFields();
-               foreach ( $formatted as $name => $value ) {
-                       $tag = strtolower( $name );
-                       self::addMeta( $result,
-                               in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed',
-                               'exif',
-                               $tag,
-                               $value
-                       );
-               }
-               return $result;
-       }
-
-       /**
-        * Get a list of metadata items which should be displayed when
-        * the metadata table is collapsed.
-        *
-        * @return array of strings
-        * @access protected
-        */
-       function visibleMetadataFields() {
-               $fields = array();
-               $lines = explode( "\n", wfMsgForContent( 'metadata-fields' ) );
-               foreach( $lines as $line ) {
-                       $matches = array();
-                       if( preg_match( '/^\\*\s*(.*?)\s*$/', $line, $matches ) ) {
-                               $fields[] = $matches[1];
-                       }
-               }
-               $fields = array_map( 'strtolower', $fields );
-               return $fields;
-       }
-
-
-       /**
-        * This is used to generate an array element for each metadata value
-        * That array is then used to generate the table of metadata values
-        * on the image page
-        *
-        * @param &$array Array An array containing elements for each type of visibility
-        * and each of those elements being an array of metadata items. This function adds
-        * a value to that array.
-        * @param $visibility string ('visible' or 'collapsed') if this value is hidden
-        * by default.
-        * @param $type String type of metadata tag (currently always 'exif')
-        * @param $id String the name of the metadata tag (like 'artist' for example).
-        * its name in the table displayed is the message "$type-$id" (Ex exif-artist ).
-        * @param $value String thingy goes into a wikitext table; it used to be escaped but
-        * that was incompatible with previous practise of customized display
-        * with wikitext formatting via messages such as 'exif-model-value'.
-        * So the escaping is taken back out, but generally this seems a confusing
-        * interface.
-        * @param $param String value to pass to the message for the name of the field
-        * as $1. Currently this parameter doesn't seem to ever be used.
-        *
-        * Note, everything here is passed through the parser later on (!)
-        */
-       protected static function addMeta( &$array, $visibility, $type, $id, $value, $param = false ) {
-               $msg = wfMessage( "$type-$id", $param );
-               if ( $msg->exists() ) {
-                       $name = $msg->text();
-               } else {
-                       // This is for future compatibility when using instant commons.
-                       // So as to not display as ugly a name if a new metadata
-                       // property is defined that we don't know about
-                       // (not a major issue since such a property would be collapsed
-                       // by default).
-                       wfDebug( __METHOD__ . ' Unknown metadata name: ' . $id . "\n" );
-                       $name = wfEscapeWikiText( $id );
-               }
-               $array[$visibility][] = array(
-                       'id' => "$type-$id",
-                       'name' => $name,
-                       'value' => $value
-               );
-       }
-
-       /**
-        * @param $file File
-        * @return string
-        */
-       function getShortDesc( $file ) {
-               global $wgLang;
-               return htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
-       }
-
-       /**
-        * @param $file File
-        * @return string
-        */
-       function getLongDesc( $file ) {
-               global $wgLang;
-               return wfMessage( 'file-info', htmlspecialchars( $wgLang->formatSize( $file->getSize() ) ),
-                       $file->getMimeType() )->parse();
-       }
-
-       /**
-        * @param $file File
-        * @return string
-        */
-       static function getGeneralShortDesc( $file ) {
-               global $wgLang;
-               return $wgLang->formatSize( $file->getSize() );
-       }
-
-       /**
-        * @param $file File
-        * @return string
-        */
-       static function getGeneralLongDesc( $file ) {
-               global $wgLang;
-               return wfMessage( 'file-info', $wgLang->formatSize( $file->getSize() ),
-                       $file->getMimeType() )->parse();
-       }
-
-       /**
-        * Calculate the largest thumbnail width for a given original file size
-        * such that the thumbnail's height is at most $maxHeight.
-        * @param $boxWidth Integer Width of the thumbnail box.
-        * @param $boxHeight Integer Height of the thumbnail box.
-        * @param $maxHeight Integer Maximum height expected for the thumbnail.
-        * @return Integer.
-        */
-       public static function fitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) {
-               $idealWidth = $boxWidth * $maxHeight / $boxHeight;
-               $roundedUp = ceil( $idealWidth );
-               if( round( $roundedUp * $boxHeight / $boxWidth ) > $maxHeight ) {
-                       return floor( $idealWidth );
-               } else {
-                       return $roundedUp;
-               }
-       }
-
-       function getDimensionsString( $file ) {
-               return '';
-       }
-
-       /**
-        * Modify the parser object post-transform
-        */
-       function parserTransformHook( $parser, $file ) {}
-
-       /**
-        * File validation hook called on upload.
-        *
-        * If the file at the given local path is not valid, or its MIME type does not
-        * match the handler class, a Status object should be returned containing
-        * relevant errors.
-        *
-        * @param $fileName string The local path to the file.
-        * @return Status object
-        */
-       function verifyUpload( $fileName ) {
-               return Status::newGood();
-       }
-
-       /**
-        * Check for zero-sized thumbnails. These can be generated when
-        * no disk space is available or some other error occurs
-        *
-        * @param $dstPath string The location of the suspect file
-        * @param $retval int Return value of some shell process, file will be deleted if this is non-zero
-        * @return bool True if removed, false otherwise
-        */
-       function removeBadFile( $dstPath, $retval = 0 ) {
-               if( file_exists( $dstPath ) ) {
-                       $thumbstat = stat( $dstPath );
-                       if( $thumbstat['size'] == 0 || $retval != 0 ) {
-                               $result = unlink( $dstPath );
-
-                               if ( $result ) {
-                                       wfDebugLog( 'thumbnail',
-                                               sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() succeeded',
-                                                       $thumbstat['size'], $dstPath ) );
-                               } else {
-                                       wfDebugLog( 'thumbnail',
-                                               sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() failed',
-                                                       $thumbstat['size'], $dstPath ) );
-                               }
-                               return true;
-                       }
-               }
-               return false;
-       }
-
-       /**
-        * Remove files from the purge list
-        *
-        * @param array $files
-        * @param array $options
-        */
-       public function filterThumbnailPurgeList( &$files, $options ) {
-               // Do nothing
-       }
-}
-
-/**
- * Media handler abstract base class for images
- *
- * @ingroup Media
- */
-abstract class ImageHandler extends MediaHandler {
-
-       /**
-        * @param $file File
-        * @return bool
-        */
-       function canRender( $file ) {
-               return ( $file->getWidth() && $file->getHeight() );
-       }
-
-       function getParamMap() {
-               return array( 'img_width' => 'width' );
-       }
-
-       function validateParam( $name, $value ) {
-               if ( in_array( $name, array( 'width', 'height' ) ) ) {
-                       if ( $value <= 0 ) {
-                               return false;
-                       } else {
-                               return true;
-                       }
-               } else {
-                       return false;
-               }
-       }
-
-       function makeParamString( $params ) {
-               if ( isset( $params['physicalWidth'] ) ) {
-                       $width = $params['physicalWidth'];
-               } elseif ( isset( $params['width'] ) ) {
-                       $width = $params['width'];
-               } else {
-                       throw new MWException( 'No width specified to '.__METHOD__ );
-               }
-               # Removed for ProofreadPage
-               #$width = intval( $width );
-               return "{$width}px";
-       }
-
-       function parseParamString( $str ) {
-               $m = false;
-               if ( preg_match( '/^(\d+)px$/', $str, $m ) ) {
-                       return array( 'width' => $m[1] );
-               } else {
-                       return false;
-               }
-       }
-
-       function getScriptParams( $params ) {
-               return array( 'width' => $params['width'] );
-       }
-
-       /**
-        * @param $image File
-        * @param  $params
-        * @return bool
-        */
-       function normaliseParams( $image, &$params ) {
-               $mimeType = $image->getMimeType();
-
-               if ( !isset( $params['width'] ) ) {
-                       return false;
-               }
-
-               if ( !isset( $params['page'] ) ) {
-                       $params['page'] = 1;
-               } else  {
-                       if ( $params['page'] > $image->pageCount() ) {
-                               $params['page'] = $image->pageCount();
-                       }
-
-                       if ( $params['page'] < 1 ) {
-                               $params['page'] = 1;
-                       }
-               }
-
-               $srcWidth = $image->getWidth( $params['page'] );
-               $srcHeight = $image->getHeight( $params['page'] );
-
-               if ( isset( $params['height'] ) && $params['height'] != -1 ) {
-                       # Height & width were both set
-                       if ( $params['width'] * $srcHeight > $params['height'] * $srcWidth ) {
-                               # Height is the relative smaller dimension, so scale width accordingly
-                               $params['width'] = self::fitBoxWidth( $srcWidth, $srcHeight, $params['height'] );
-
-                               if ( $params['width'] == 0 ) {
-                                       # Very small image, so we need to rely on client side scaling :(
-                                       $params['width'] = 1;
-                               }
-
-                               $params['physicalWidth'] = $params['width'];
-                       } else {
-                               # Height was crap, unset it so that it will be calculated later
-                               unset( $params['height'] );
-                       }
-               }
-
-               if ( !isset( $params['physicalWidth'] ) ) {
-                       # Passed all validations, so set the physicalWidth
-                       $params['physicalWidth'] = $params['width'];
-               }
-
-               # Because thumbs are only referred to by width, the height always needs
-               # to be scaled by the width to keep the thumbnail sizes consistent,
-               # even if it was set inside the if block above
-               $params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight,
-                       $params['physicalWidth'] );
-
-               # Set the height if it was not validated in the if block higher up
-               if ( !isset( $params['height'] ) || $params['height'] == -1 ) {
-                       $params['height'] = $params['physicalHeight'];
-               }
-
-
-               if ( !$this->validateThumbParams( $params['physicalWidth'],
-                               $params['physicalHeight'], $srcWidth, $srcHeight, $mimeType ) ) {
-                       return false;
-               }
-               return true;
-       }
-
-       /**
-        * Validate thumbnail parameters and fill in the correct height
-        *
-        * @param $width Integer: specified width (input/output)
-        * @param $height Integer: height (output only)
-        * @param $srcWidth Integer: width of the source image
-        * @param $srcHeight Integer: height of the source image
-        * @param $mimeType
-        * @return bool False to indicate that an error should be returned to the user.
-        */
-       function validateThumbParams( &$width, &$height, $srcWidth, $srcHeight, $mimeType ) {
-               $width = intval( $width );
-
-               # Sanity check $width
-               if( $width <= 0) {
-                       wfDebug( __METHOD__.": Invalid destination width: $width\n" );
-                       return false;
-               }
-               if ( $srcWidth <= 0 ) {
-                       wfDebug( __METHOD__.": Invalid source width: $srcWidth\n" );
-                       return false;
-               }
-
-               $height = File::scaleHeight( $srcWidth, $srcHeight, $width );
-               if ( $height == 0 ) {
-                       # Force height to be at least 1 pixel
-                       $height = 1;
-               }
-               return true;
-       }
-
-       /**
-        * @param $image File
-        * @param  $script
-        * @param  $params
-        * @return bool|ThumbnailImage
-        */
-       function getScriptedTransform( $image, $script, $params ) {
-               if ( !$this->normaliseParams( $image, $params ) ) {
-                       return false;
-               }
-               $url = $script . '&' . wfArrayToCGI( $this->getScriptParams( $params ) );
-               $page = isset( $params['page'] ) ? $params['page'] : false;
-
-               if( $image->mustRender() || $params['width'] < $image->getWidth() ) {
-                       return new ThumbnailImage( $image,
-                               $url, $params['width'], $params['height'], false, $page );
-               }
-       }
-
-       function getImageSize( $image, $path ) {
-               wfSuppressWarnings();
-               $gis = getimagesize( $path );
-               wfRestoreWarnings();
-               return $gis;
-       }
-
-       function isAnimatedImage( $image ) {
-               return false;
-       }
-
-       /**
-        * @param $file File
-        * @return string
-        */
-       function getShortDesc( $file ) {
-               global $wgLang;
-               $nbytes = htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
-               $widthheight = wfMessage( 'widthheight' )->numParams( $file->getWidth(), $file->getHeight() )->escaped();
-
-               return "$widthheight ($nbytes)";
-       }
-
-       /**
-        * @param $file File
-        * @return string
-        */
-       function getLongDesc( $file ) {
-               global $wgLang;
-               $pages = $file->pageCount();
-               $size = htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
-               if ( $pages === false || $pages <= 1 ) {
-                       $msg = wfMessage( 'file-info-size' )->numParams( $file->getWidth(),
-                               $file->getHeight() )->params( $size,
-                               $file->getMimeType() )->parse();
-               } else {
-                       $msg = wfMessage( 'file-info-size-pages' )->numParams( $file->getWidth(),
-                               $file->getHeight() )->params( $size,
-                               $file->getMimeType() )->numParams( $pages )->parse();
-               }
-               return $msg;
-       }
-
-       /**
-        * @param $file File
-        * @return string
-        */
-       function getDimensionsString( $file ) {
-               $pages = $file->pageCount();
-               if ( $pages > 1 ) {
-                       return wfMessage( 'widthheightpage' )->numParams( $file->getWidth(), $file->getHeight(), $pages )->text();
-               } else {
-                       return wfMessage( 'widthheight' )->numParams( $file->getWidth(), $file->getHeight() )->text();
-               }
-       }
-}
diff --git a/includes/media/ImageHandler.php b/includes/media/ImageHandler.php
new file mode 100644 (file)
index 0000000..69f51be
--- /dev/null
@@ -0,0 +1,255 @@
+<?php
+/**
+ * Media-handling base classes and generic functionality.
+ *
+ * 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 Media
+ */
+
+/**
+ * Media handler abstract base class for images
+ *
+ * @ingroup Media
+ */
+abstract class ImageHandler extends MediaHandler {
+
+       /**
+        * @param $file File
+        * @return bool
+        */
+       function canRender( $file ) {
+               return ( $file->getWidth() && $file->getHeight() );
+       }
+
+       function getParamMap() {
+               return array( 'img_width' => 'width' );
+       }
+
+       function validateParam( $name, $value ) {
+               if ( in_array( $name, array( 'width', 'height' ) ) ) {
+                       if ( $value <= 0 ) {
+                               return false;
+                       } else {
+                               return true;
+                       }
+               } else {
+                       return false;
+               }
+       }
+
+       function makeParamString( $params ) {
+               if ( isset( $params['physicalWidth'] ) ) {
+                       $width = $params['physicalWidth'];
+               } elseif ( isset( $params['width'] ) ) {
+                       $width = $params['width'];
+               } else {
+                       throw new MWException( 'No width specified to '.__METHOD__ );
+               }
+               # Removed for ProofreadPage
+               #$width = intval( $width );
+               return "{$width}px";
+       }
+
+       function parseParamString( $str ) {
+               $m = false;
+               if ( preg_match( '/^(\d+)px$/', $str, $m ) ) {
+                       return array( 'width' => $m[1] );
+               } else {
+                       return false;
+               }
+       }
+
+       function getScriptParams( $params ) {
+               return array( 'width' => $params['width'] );
+       }
+
+       /**
+        * @param $image File
+        * @param  $params
+        * @return bool
+        */
+       function normaliseParams( $image, &$params ) {
+               $mimeType = $image->getMimeType();
+
+               if ( !isset( $params['width'] ) ) {
+                       return false;
+               }
+
+               if ( !isset( $params['page'] ) ) {
+                       $params['page'] = 1;
+               } else  {
+                       if ( $params['page'] > $image->pageCount() ) {
+                               $params['page'] = $image->pageCount();
+                       }
+
+                       if ( $params['page'] < 1 ) {
+                               $params['page'] = 1;
+                       }
+               }
+
+               $srcWidth = $image->getWidth( $params['page'] );
+               $srcHeight = $image->getHeight( $params['page'] );
+
+               if ( isset( $params['height'] ) && $params['height'] != -1 ) {
+                       # Height & width were both set
+                       if ( $params['width'] * $srcHeight > $params['height'] * $srcWidth ) {
+                               # Height is the relative smaller dimension, so scale width accordingly
+                               $params['width'] = self::fitBoxWidth( $srcWidth, $srcHeight, $params['height'] );
+
+                               if ( $params['width'] == 0 ) {
+                                       # Very small image, so we need to rely on client side scaling :(
+                                       $params['width'] = 1;
+                               }
+
+                               $params['physicalWidth'] = $params['width'];
+                       } else {
+                               # Height was crap, unset it so that it will be calculated later
+                               unset( $params['height'] );
+                       }
+               }
+
+               if ( !isset( $params['physicalWidth'] ) ) {
+                       # Passed all validations, so set the physicalWidth
+                       $params['physicalWidth'] = $params['width'];
+               }
+
+               # Because thumbs are only referred to by width, the height always needs
+               # to be scaled by the width to keep the thumbnail sizes consistent,
+               # even if it was set inside the if block above
+               $params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight,
+                       $params['physicalWidth'] );
+
+               # Set the height if it was not validated in the if block higher up
+               if ( !isset( $params['height'] ) || $params['height'] == -1 ) {
+                       $params['height'] = $params['physicalHeight'];
+               }
+
+
+               if ( !$this->validateThumbParams( $params['physicalWidth'],
+                               $params['physicalHeight'], $srcWidth, $srcHeight, $mimeType ) ) {
+                       return false;
+               }
+               return true;
+       }
+
+       /**
+        * Validate thumbnail parameters and fill in the correct height
+        *
+        * @param $width Integer: specified width (input/output)
+        * @param $height Integer: height (output only)
+        * @param $srcWidth Integer: width of the source image
+        * @param $srcHeight Integer: height of the source image
+        * @param $mimeType
+        * @return bool False to indicate that an error should be returned to the user.
+        */
+       function validateThumbParams( &$width, &$height, $srcWidth, $srcHeight, $mimeType ) {
+               $width = intval( $width );
+
+               # Sanity check $width
+               if( $width <= 0) {
+                       wfDebug( __METHOD__.": Invalid destination width: $width\n" );
+                       return false;
+               }
+               if ( $srcWidth <= 0 ) {
+                       wfDebug( __METHOD__.": Invalid source width: $srcWidth\n" );
+                       return false;
+               }
+
+               $height = File::scaleHeight( $srcWidth, $srcHeight, $width );
+               if ( $height == 0 ) {
+                       # Force height to be at least 1 pixel
+                       $height = 1;
+               }
+               return true;
+       }
+
+       /**
+        * @param $image File
+        * @param  $script
+        * @param  $params
+        * @return bool|ThumbnailImage
+        */
+       function getScriptedTransform( $image, $script, $params ) {
+               if ( !$this->normaliseParams( $image, $params ) ) {
+                       return false;
+               }
+               $url = $script . '&' . wfArrayToCGI( $this->getScriptParams( $params ) );
+               $page = isset( $params['page'] ) ? $params['page'] : false;
+
+               if( $image->mustRender() || $params['width'] < $image->getWidth() ) {
+                       return new ThumbnailImage( $image,
+                               $url, $params['width'], $params['height'], false, $page );
+               }
+       }
+
+       function getImageSize( $image, $path ) {
+               wfSuppressWarnings();
+               $gis = getimagesize( $path );
+               wfRestoreWarnings();
+               return $gis;
+       }
+
+       function isAnimatedImage( $image ) {
+               return false;
+       }
+
+       /**
+        * @param $file File
+        * @return string
+        */
+       function getShortDesc( $file ) {
+               global $wgLang;
+               $nbytes = htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
+               $widthheight = wfMessage( 'widthheight' )->numParams( $file->getWidth(), $file->getHeight() )->escaped();
+
+               return "$widthheight ($nbytes)";
+       }
+
+       /**
+        * @param $file File
+        * @return string
+        */
+       function getLongDesc( $file ) {
+               global $wgLang;
+               $pages = $file->pageCount();
+               $size = htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
+               if ( $pages === false || $pages <= 1 ) {
+                       $msg = wfMessage( 'file-info-size' )->numParams( $file->getWidth(),
+                               $file->getHeight() )->params( $size,
+                               $file->getMimeType() )->parse();
+               } else {
+                       $msg = wfMessage( 'file-info-size-pages' )->numParams( $file->getWidth(),
+                               $file->getHeight() )->params( $size,
+                               $file->getMimeType() )->numParams( $pages )->parse();
+               }
+               return $msg;
+       }
+
+       /**
+        * @param $file File
+        * @return string
+        */
+       function getDimensionsString( $file ) {
+               $pages = $file->pageCount();
+               if ( $pages > 1 ) {
+                       return wfMessage( 'widthheightpage' )->numParams( $file->getWidth(), $file->getHeight(), $pages )->text();
+               } else {
+                       return wfMessage( 'widthheight' )->numParams( $file->getWidth(), $file->getHeight() )->text();
+               }
+       }
+}
diff --git a/includes/media/MediaHandler.php b/includes/media/MediaHandler.php
new file mode 100644 (file)
index 0000000..e883b7f
--- /dev/null
@@ -0,0 +1,547 @@
+<?php
+/**
+ * Media-handling base classes and generic functionality.
+ *
+ * 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 Media
+ */
+
+/**
+ * Base media handler class
+ *
+ * @ingroup Media
+ */
+abstract class MediaHandler {
+       const TRANSFORM_LATER = 1;
+       const METADATA_GOOD = true;
+       const METADATA_BAD = false;
+       const METADATA_COMPATIBLE = 2; // for old but backwards compatible.
+       /**
+        * Instance cache
+        */
+       static $handlers = array();
+
+       /**
+        * Get a MediaHandler for a given MIME type from the instance cache
+        *
+        * @param $type string
+        *
+        * @return MediaHandler
+        */
+       static function getHandler( $type ) {
+               global $wgMediaHandlers;
+               if ( !isset( $wgMediaHandlers[$type] ) ) {
+                       wfDebug( __METHOD__ . ": no handler found for $type.\n");
+                       return false;
+               }
+               $class = $wgMediaHandlers[$type];
+               if ( !isset( self::$handlers[$class] ) ) {
+                       self::$handlers[$class] = new $class;
+                       if ( !self::$handlers[$class]->isEnabled() ) {
+                               self::$handlers[$class] = false;
+                       }
+               }
+               return self::$handlers[$class];
+       }
+
+       /**
+        * Get an associative array mapping magic word IDs to parameter names.
+        * Will be used by the parser to identify parameters.
+        */
+       abstract function getParamMap();
+
+       /**
+        * Validate a thumbnail parameter at parse time.
+        * Return true to accept the parameter, and false to reject it.
+        * If you return false, the parser will do something quiet and forgiving.
+        *
+        * @param $name
+        * @param $value
+        */
+       abstract function validateParam( $name, $value );
+
+       /**
+        * Merge a parameter array into a string appropriate for inclusion in filenames
+        *
+        * @param $params array
+        */
+       abstract function makeParamString( $params );
+
+       /**
+        * Parse a param string made with makeParamString back into an array
+        *
+        * @param $str string
+        */
+       abstract function parseParamString( $str );
+
+       /**
+        * Changes the parameter array as necessary, ready for transformation.
+        * Should be idempotent.
+        * Returns false if the parameters are unacceptable and the transform should fail
+        * @param $image
+        * @param $params
+        */
+       abstract function normaliseParams( $image, &$params );
+
+       /**
+        * Get an image size array like that returned by getimagesize(), or false if it
+        * can't be determined.
+        *
+        * @param $image File: the image object, or false if there isn't one
+        * @param $path String: the filename
+        * @return Array Follow the format of PHP getimagesize() internal function. See http://www.php.net/getimagesize
+        */
+       abstract function getImageSize( $image, $path );
+
+       /**
+        * Get handler-specific metadata which will be saved in the img_metadata field.
+        *
+        * @param $image File: the image object, or false if there isn't one.
+        *   Warning, FSFile::getPropsFromPath might pass an (object)array() instead (!)
+        * @param $path String: the filename
+        * @return String
+        */
+       function getMetadata( $image, $path ) { return ''; }
+
+       /**
+       * Get metadata version.
+       *
+       * This is not used for validating metadata, this is used for the api when returning
+       * metadata, since api content formats should stay the same over time, and so things
+       * using ForiegnApiRepo can keep backwards compatibility
+       *
+       * All core media handlers share a common version number, and extensions can
+       * use the GetMetadataVersion hook to append to the array (they should append a unique
+       * string so not to get confusing). If there was a media handler named 'foo' with metadata
+       * version 3 it might add to the end of the array the element 'foo=3'. if the core metadata
+       * version is 2, the end version string would look like '2;foo=3'.
+       *
+       * @return string version string
+       */
+       static function getMetadataVersion () {
+               $version = Array( '2' ); // core metadata version
+               wfRunHooks('GetMetadataVersion', Array(&$version));
+               return implode( ';', $version);
+        }
+
+       /**
+       * Convert metadata version.
+       *
+       * By default just returns $metadata, but can be used to allow
+       * media handlers to convert between metadata versions.
+       *
+       * @param $metadata Mixed String or Array metadata array (serialized if string)
+       * @param $version Integer target version
+       * @return Array serialized metadata in specified version, or $metadata on fail.
+       */
+       function convertMetadataVersion( $metadata, $version = 1 ) {
+               if ( !is_array( $metadata ) ) {
+
+                       //unserialize to keep return parameter consistent.
+                       wfSuppressWarnings();
+                       $ret = unserialize( $metadata );
+                       wfRestoreWarnings();
+                       return $ret;
+               }
+               return $metadata;
+       }
+
+       /**
+        * Get a string describing the type of metadata, for display purposes.
+        *
+        * @return string
+        */
+       function getMetadataType( $image ) { return false; }
+
+       /**
+        * Check if the metadata string is valid for this handler.
+        * If it returns MediaHandler::METADATA_BAD (or false), Image
+        * will reload the metadata from the file and update the database.
+        * MediaHandler::METADATA_GOOD for if the metadata is a-ok,
+        * MediaHanlder::METADATA_COMPATIBLE if metadata is old but backwards
+        * compatible (which may or may not trigger a metadata reload).
+        * @return bool
+        */
+       function isMetadataValid( $image, $metadata ) {
+               return self::METADATA_GOOD;
+       }
+
+
+       /**
+        * Get a MediaTransformOutput object representing an alternate of the transformed
+        * output which will call an intermediary thumbnail assist script.
+        *
+        * Used when the repository has a thumbnailScriptUrl option configured.
+        *
+        * Return false to fall back to the regular getTransform().
+        * @return bool
+        */
+       function getScriptedTransform( $image, $script, $params ) {
+               return false;
+       }
+
+       /**
+        * Get a MediaTransformOutput object representing the transformed output. Does not
+        * actually do the transform.
+        *
+        * @param $image File: the image object
+        * @param $dstPath String: filesystem destination path
+        * @param $dstUrl String: Destination URL to use in output HTML
+        * @param $params Array: Arbitrary set of parameters validated by $this->validateParam()
+        * @return MediaTransformOutput
+        */
+       final function getTransform( $image, $dstPath, $dstUrl, $params ) {
+               return $this->doTransform( $image, $dstPath, $dstUrl, $params, self::TRANSFORM_LATER );
+       }
+
+       /**
+        * Get a MediaTransformOutput object representing the transformed output. Does the
+        * transform unless $flags contains self::TRANSFORM_LATER.
+        *
+        * @param $image File: the image object
+        * @param $dstPath String: filesystem destination path
+        * @param $dstUrl String: destination URL to use in output HTML
+        * @param $params Array: arbitrary set of parameters validated by $this->validateParam()
+        * @param $flags Integer: a bitfield, may contain self::TRANSFORM_LATER
+        *
+        * @return MediaTransformOutput
+        */
+       abstract function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 );
+
+       /**
+        * Get the thumbnail extension and MIME type for a given source MIME type
+        * @return array thumbnail extension and MIME type
+        */
+       function getThumbType( $ext, $mime, $params = null ) {
+               $magic = MimeMagic::singleton();
+               if ( !$ext || $magic->isMatchingExtension( $ext, $mime ) === false ) {
+                       // The extension is not valid for this mime type and we do
+                       // recognize the mime type
+                       $extensions = $magic->getExtensionsForType( $mime );
+                       if ( $extensions ) {
+                               return array( strtok( $extensions, ' ' ), $mime );
+                       }
+               }
+
+               // The extension is correct (true) or the mime type is unknown to
+               // MediaWiki (null)
+               return array( $ext, $mime );
+       }
+
+       /**
+        * True if the handled types can be transformed
+        * @return bool
+        */
+       function canRender( $file ) { return true; }
+       /**
+        * True if handled types cannot be displayed directly in a browser
+        * but can be rendered
+        * @return bool
+        */
+       function mustRender( $file ) { return false; }
+       /**
+        * True if the type has multi-page capabilities
+        * @return bool
+        */
+       function isMultiPage( $file ) { return false; }
+       /**
+        * Page count for a multi-page document, false if unsupported or unknown
+        * @return bool
+        */
+       function pageCount( $file ) { return false; }
+       /**
+        * The material is vectorized and thus scaling is lossless
+        * @return bool
+        */
+       function isVectorized( $file ) { return false; }
+       /**
+        * False if the handler is disabled for all files
+        * @return bool
+        */
+       function isEnabled() { return true; }
+
+       /**
+        * Get an associative array of page dimensions
+        * Currently "width" and "height" are understood, but this might be
+        * expanded in the future.
+        * Returns false if unknown or if the document is not multi-page.
+        *
+        * @param $image File
+        * @param $page Unused, left for backcompatibility?
+        * @return array
+        */
+       function getPageDimensions( $image, $page ) {
+               $gis = $this->getImageSize( $image, $image->getLocalRefPath() );
+               return array(
+                       'width' => $gis[0],
+                       'height' => $gis[1]
+               );
+       }
+
+       /**
+        * Generic getter for text layer.
+        * Currently overloaded by PDF and DjVu handlers
+        * @return bool
+        */
+       function getPageText( $image, $page ) {
+               return false;
+       }
+
+       /**
+        * Get an array structure that looks like this:
+        *
+        * array(
+        *    'visible' => array(
+        *       'Human-readable name' => 'Human readable value',
+        *       ...
+        *    ),
+        *    'collapsed' => array(
+        *       'Human-readable name' => 'Human readable value',
+        *       ...
+        *    )
+        * )
+        * The UI will format this into a table where the visible fields are always
+        * visible, and the collapsed fields are optionally visible.
+        *
+        * The function should return false if there is no metadata to display.
+        */
+
+       /**
+        * @todo FIXME: I don't really like this interface, it's not very flexible
+        * I think the media handler should generate HTML instead. It can do
+        * all the formatting according to some standard. That makes it possible
+        * to do things like visual indication of grouped and chained streams
+        * in ogg container files.
+        * @return bool
+        */
+       function formatMetadata( $image ) {
+               return false;
+       }
+
+       /** sorts the visible/invisible field.
+        * Split off from ImageHandler::formatMetadata, as used by more than
+        * one type of handler.
+        *
+        * This is used by the media handlers that use the FormatMetadata class
+        *
+        * @param $metadataArray Array metadata array
+        * @return array for use displaying metadata.
+        */
+       function formatMetadataHelper( $metadataArray ) {
+                $result = array(
+                       'visible' => array(),
+                       'collapsed' => array()
+               );
+
+               $formatted = FormatMetadata::getFormattedData( $metadataArray );
+               // Sort fields into visible and collapsed
+               $visibleFields = $this->visibleMetadataFields();
+               foreach ( $formatted as $name => $value ) {
+                       $tag = strtolower( $name );
+                       self::addMeta( $result,
+                               in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed',
+                               'exif',
+                               $tag,
+                               $value
+                       );
+               }
+               return $result;
+       }
+
+       /**
+        * Get a list of metadata items which should be displayed when
+        * the metadata table is collapsed.
+        *
+        * @return array of strings
+        * @access protected
+        */
+       function visibleMetadataFields() {
+               $fields = array();
+               $lines = explode( "\n", wfMsgForContent( 'metadata-fields' ) );
+               foreach( $lines as $line ) {
+                       $matches = array();
+                       if( preg_match( '/^\\*\s*(.*?)\s*$/', $line, $matches ) ) {
+                               $fields[] = $matches[1];
+                       }
+               }
+               $fields = array_map( 'strtolower', $fields );
+               return $fields;
+       }
+
+
+       /**
+        * This is used to generate an array element for each metadata value
+        * That array is then used to generate the table of metadata values
+        * on the image page
+        *
+        * @param &$array Array An array containing elements for each type of visibility
+        * and each of those elements being an array of metadata items. This function adds
+        * a value to that array.
+        * @param $visibility string ('visible' or 'collapsed') if this value is hidden
+        * by default.
+        * @param $type String type of metadata tag (currently always 'exif')
+        * @param $id String the name of the metadata tag (like 'artist' for example).
+        * its name in the table displayed is the message "$type-$id" (Ex exif-artist ).
+        * @param $value String thingy goes into a wikitext table; it used to be escaped but
+        * that was incompatible with previous practise of customized display
+        * with wikitext formatting via messages such as 'exif-model-value'.
+        * So the escaping is taken back out, but generally this seems a confusing
+        * interface.
+        * @param $param String value to pass to the message for the name of the field
+        * as $1. Currently this parameter doesn't seem to ever be used.
+        *
+        * Note, everything here is passed through the parser later on (!)
+        */
+       protected static function addMeta( &$array, $visibility, $type, $id, $value, $param = false ) {
+               $msg = wfMessage( "$type-$id", $param );
+               if ( $msg->exists() ) {
+                       $name = $msg->text();
+               } else {
+                       // This is for future compatibility when using instant commons.
+                       // So as to not display as ugly a name if a new metadata
+                       // property is defined that we don't know about
+                       // (not a major issue since such a property would be collapsed
+                       // by default).
+                       wfDebug( __METHOD__ . ' Unknown metadata name: ' . $id . "\n" );
+                       $name = wfEscapeWikiText( $id );
+               }
+               $array[$visibility][] = array(
+                       'id' => "$type-$id",
+                       'name' => $name,
+                       'value' => $value
+               );
+       }
+
+       /**
+        * @param $file File
+        * @return string
+        */
+       function getShortDesc( $file ) {
+               global $wgLang;
+               return htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
+       }
+
+       /**
+        * @param $file File
+        * @return string
+        */
+       function getLongDesc( $file ) {
+               global $wgLang;
+               return wfMessage( 'file-info', htmlspecialchars( $wgLang->formatSize( $file->getSize() ) ),
+                       $file->getMimeType() )->parse();
+       }
+
+       /**
+        * @param $file File
+        * @return string
+        */
+       static function getGeneralShortDesc( $file ) {
+               global $wgLang;
+               return $wgLang->formatSize( $file->getSize() );
+       }
+
+       /**
+        * @param $file File
+        * @return string
+        */
+       static function getGeneralLongDesc( $file ) {
+               global $wgLang;
+               return wfMessage( 'file-info', $wgLang->formatSize( $file->getSize() ),
+                       $file->getMimeType() )->parse();
+       }
+
+       /**
+        * Calculate the largest thumbnail width for a given original file size
+        * such that the thumbnail's height is at most $maxHeight.
+        * @param $boxWidth Integer Width of the thumbnail box.
+        * @param $boxHeight Integer Height of the thumbnail box.
+        * @param $maxHeight Integer Maximum height expected for the thumbnail.
+        * @return Integer.
+        */
+       public static function fitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) {
+               $idealWidth = $boxWidth * $maxHeight / $boxHeight;
+               $roundedUp = ceil( $idealWidth );
+               if( round( $roundedUp * $boxHeight / $boxWidth ) > $maxHeight ) {
+                       return floor( $idealWidth );
+               } else {
+                       return $roundedUp;
+               }
+       }
+
+       function getDimensionsString( $file ) {
+               return '';
+       }
+
+       /**
+        * Modify the parser object post-transform
+        */
+       function parserTransformHook( $parser, $file ) {}
+
+       /**
+        * File validation hook called on upload.
+        *
+        * If the file at the given local path is not valid, or its MIME type does not
+        * match the handler class, a Status object should be returned containing
+        * relevant errors.
+        *
+        * @param $fileName string The local path to the file.
+        * @return Status object
+        */
+       function verifyUpload( $fileName ) {
+               return Status::newGood();
+       }
+
+       /**
+        * Check for zero-sized thumbnails. These can be generated when
+        * no disk space is available or some other error occurs
+        *
+        * @param $dstPath string The location of the suspect file
+        * @param $retval int Return value of some shell process, file will be deleted if this is non-zero
+        * @return bool True if removed, false otherwise
+        */
+       function removeBadFile( $dstPath, $retval = 0 ) {
+               if( file_exists( $dstPath ) ) {
+                       $thumbstat = stat( $dstPath );
+                       if( $thumbstat['size'] == 0 || $retval != 0 ) {
+                               $result = unlink( $dstPath );
+
+                               if ( $result ) {
+                                       wfDebugLog( 'thumbnail',
+                                               sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() succeeded',
+                                                       $thumbstat['size'], $dstPath ) );
+                               } else {
+                                       wfDebugLog( 'thumbnail',
+                                               sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() failed',
+                                                       $thumbstat['size'], $dstPath ) );
+                               }
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Remove files from the purge list
+        *
+        * @param array $files
+        * @param array $options
+        */
+       public function filterThumbnailPurgeList( &$files, $options ) {
+               // Do nothing
+       }
+}
index eda57c0..ec67a39 100644 (file)
@@ -895,10 +895,7 @@ class MWMemcached {
        function _load_items( $sock, &$ret ) {
                while ( 1 ) {
                        $decl = fgets( $sock );
-                       if( $decl === false ) {
-                               $this->_debugprint( "Error reading socket for a memcached response\n" );
-                               return 0;
-                       } elseif ( $decl == "END\r\n" ) {
+                       if ( $decl == "END\r\n" ) {
                                return true;
                        } elseif ( preg_match( '/^VALUE (\S+) (\d+) (\d+)\r\n$/', $decl, $match ) ) {
                                list( $rkey, $flags, $len ) = array( $match[1], $match[2], $match[3] );
@@ -942,12 +939,7 @@ class MWMemcached {
                                }
 
                        } else {
-                               $peer = $peerAddress = $peerPort = '';
-                               $gotPeer = socket_getpeername( $sock, $peerAddress, $peerPort );
-                               if( $gotPeer ) {
-                                       $peer = " from [$peerAddress:$peerPort";
-                               }
-                               $this->_debugprint( "Error parsing memcached response{$peer}\n" );
+                               $this->_debugprint( "Error parsing memcached response\n" );
                                return 0;
                        }
                }
index 912de41..322cb13 100644 (file)
@@ -565,29 +565,64 @@ class CoreParserFunctions {
        }
 
        /**
-        * Return the number of pages in the given category, or 0 if it's nonexis-
-        * tent.  This is an expensive parser function and can't be called too many
-        * times per page.
+        * Return the number of pages, files or subcats in the given category,
+        * or 0 if it's nonexistent. This is an expensive parser function and
+        * can't be called too many times per page.
         * @return string
         */
-       static function pagesincategory( $parser, $name = '', $raw = null ) {
+       static function pagesincategory( $parser, $name = '', $arg1 = null, $arg2 = null ) {
+               static $magicWords = null;
+               if ( is_null( $magicWords ) ) {
+                       $magicWords = new MagicWordArray( array(
+                               'pagesincategory_all',
+                               'pagesincategory_pages',
+                               'pagesincategory_subcats',
+                               'pagesincategory_files'
+                       ) );
+               }
                static $cache = array();
-               $category = Category::newFromName( $name );
 
-               if( !is_object( $category ) ) {
-                       $cache[$name] = 0;
+               // split the given option to its variable
+               if( self::isRaw( $arg1 ) ) {
+                       //{{pagesincategory:|raw[|type]}}
+                       $raw = $arg1;
+                       $type = $magicWords->matchStartToEnd( $arg2 );
+               } else {
+                       //{{pagesincategory:[|type[|raw]]}}
+                       $type = $magicWords->matchStartToEnd( $arg1 );
+                       $raw = $arg2;
+               }
+               if( !$type ) { //backward compatibility
+                       $type = 'pagesincategory_all';
+               }
+
+               $title = Title::makeTitleSafe( NS_CATEGORY, $name );
+               if( !$title ) { # invalid title
                        return self::formatRaw( 0, $raw );
                }
 
-               # Normalize name for cache
-               $name = $category->getName();
+               // Normalize name for cache
+               $name = $title->getDBkey();
 
-               $count = 0;
-               if( isset( $cache[$name] ) ) {
-                       $count = $cache[$name];
-               } elseif( $parser->incrementExpensiveFunctionCount() ) {
-                       $count = $cache[$name] = (int)$category->getPageCount();
+               if( !isset( $cache[$name] ) ) {
+                       $category = Category::newFromTitle( $title );
+
+                       $allCount = $subcatCount = $fileCount = $pagesCount = 0;
+                       if( $parser->incrementExpensiveFunctionCount() ) {
+                               // $allCount is the total number of cat members,
+                               // not the count of how many members are normal pages.
+                               $allCount = (int)$category->getPageCount();
+                               $subcatCount = (int)$category->getSubcatCount();
+                               $fileCount = (int)$category->getFileCount();
+                               $pagesCount = $allCount - $subcatCount - $fileCount;
+                       }
+                       $cache[$name]['pagesincategory_all'] = $allCount;
+                       $cache[$name]['pagesincategory_pages'] = $pagesCount;
+                       $cache[$name]['pagesincategory_subcats'] = $subcatCount;
+                       $cache[$name]['pagesincategory_files'] = $fileCount;
                }
+
+               $count = $cache[$name][$type];
                return self::formatRaw( $count, $raw );
        }
 
@@ -754,40 +789,34 @@ class CoreParserFunctions {
        }
 
        // Usage {{filepath|300}}, {{filepath|nowiki}}, {{filepath|nowiki|300}} or {{filepath|300|nowiki}}
+       // or {{filepath|300px}}, {{filepath|200x300px}}, {{filepath|nowiki|200x300px}}, {{filepath|200x300px|nowiki}}
        public static function filepath( $parser, $name='', $argA='', $argB='' ) {
                $file = wfFindFile( $name );
-               $size = '';
-               $argA_int = intval( $argA );
-               $argB_int = intval( $argB );
-
-               if ( $argB_int > 0 ) {
-                       // {{filepath: | option | size }}
-                       $size = $argB_int;
-                       $option = $argA;
-
-               } elseif ( $argA_int > 0 ) {
-                       // {{filepath: | size [|option] }}
-                       $size = $argA_int;
-                       $option = $argB;
+               $isNowiki = false;
 
+               if( $argA == 'nowiki' ) {
+                       // {{filepath: | option [| size] }}
+                       $isNowiki = true;
+                       $parsedWidthParam = $parser->parseWidthParam( $argB );
                } else {
-                       // {{filepath: [|option] }}
-                       $option = $argA;
+                       // {{filepath: [| size [|option]] }}
+                       $parsedWidthParam = $parser->parseWidthParam( $argA );
+                       $isNowiki = ($argB == 'nowiki');
                }
 
                if ( $file ) {
                        $url = $file->getFullUrl();
 
                        // If a size is requested...
-                       if ( is_integer( $size ) ) {
-                               $mto = $file->transform( array( 'width' => $size ) );
+                       if ( count( $parsedWidthParam ) ) {
+                               $mto = $file->transform( $parsedWidthParam );
                                // ... and we can
                                if ( $mto && !$mto->isError() ) {
                                        // ... change the URL to point to a thumbnail.
                                        $url = wfExpandUrl( $mto->getUrl(), PROTO_RELATIVE );
                                }
                        }
-                       if ( $option == 'nowiki' ) {
+                       if ( $isNowiki ) {
                                return array( $url, 'nowiki' => true );
                        }
                        return $url;
index 94af6a8..291db7a 100644 (file)
@@ -5042,27 +5042,22 @@ class Parser {
 
                                # Special case; width and height come in one variable together
                                if ( $type === 'handler' && $paramName === 'width' ) {
-                                       $m = array();
-                                       # (bug 13500) In both cases (width/height and width only),
-                                       # permit trailing "px" for backward compatibility.
-                                       if ( preg_match( '/^([0-9]*)x([0-9]*)\s*(?:px)?\s*$/', $value, $m ) ) {
-                                               $width = intval( $m[1] );
-                                               $height = intval( $m[2] );
+                                       $parsedWidthParam = $this->parseWidthParam( $value );
+                                       if( isset( $parsedWidthParam['width'] ) ) {
+                                               $width = $parsedWidthParam['width'];
                                                if ( $handler->validateParam( 'width', $width ) ) {
                                                        $params[$type]['width'] = $width;
                                                        $validated = true;
                                                }
+                                       }
+                                       if( isset( $parsedWidthParam['height'] ) ) {
+                                               $height = $parsedWidthParam['height'];
                                                if ( $handler->validateParam( 'height', $height ) ) {
                                                        $params[$type]['height'] = $height;
                                                        $validated = true;
                                                }
-                                       } elseif ( preg_match( '/^[0-9]*\s*(?:px)?\s*$/', $value ) ) {
-                                               $width = intval( $value );
-                                               if ( $handler->validateParam( 'width', $width ) ) {
-                                                       $params[$type]['width'] = $width;
-                                                       $validated = true;
-                                               }
-                                       } # else no validation -- bug 13436
+                                       }
+                                       # else no validation -- bug 13436
                                } else {
                                        if ( $type === 'handler' ) {
                                                # Validate handler parameter
@@ -5781,4 +5776,32 @@ class Parser {
        function isValidHalfParsedText( $data ) {
                return isset( $data['version'] ) && $data['version'] == self::HALF_PARSED_VERSION;
        }
+
+       /**
+        * Parsed a width param of imagelink like 300px or 200x300px
+        *
+        * @param $value String
+        *
+        * @return array
+        * @since 1.20
+        */
+       public function parseWidthParam( $value ) {
+               $parsedWidthParam = array();
+               if( $value === '' ) {
+                       return $parsedWidthParam;
+               }
+               $m = array();
+               # (bug 13500) In both cases (width/height and width only),
+               # permit trailing "px" for backward compatibility.
+               if ( preg_match( '/^([0-9]*)x([0-9]*)\s*(?:px)?\s*$/', $value, $m ) ) {
+                       $width = intval( $m[1] );
+                       $height = intval( $m[2] );
+                       $parsedWidthParam['width'] = $width;
+                       $parsedWidthParam['height'] = $height;
+               } elseif ( preg_match( '/^[0-9]*\s*(?:px)?\s*$/', $value ) ) {
+                       $width = intval( $value );
+                       $parsedWidthParam['width'] = $width;
+               }
+               return $parsedWidthParam;
+       }
 }
index 41680d1..243f61b 100644 (file)
@@ -9,7 +9,6 @@
 乙太網      以太网
 點陣圖      位图
 常式 例程
-游標 光标
 光碟 光盘
 光碟機      光驱
 全形 全角
index 922b7de..9a9534f 100644 (file)
 細如髮
 繫於一髮
 膚髮
+皮膚
 生華髮
 蒼髮
 被髮佯狂
 棺材裡
 注釋
 月面
+路面
 修杰楷
 修杰麟
 學裡
index bc1809f..8f158a4 100644 (file)
        'tokipona' => 'Toki Pona',      # Toki Pona
        'tpi' => 'Tok Pisin',   # Tok Pisin
        'tr' => 'Türkçe',     # Turkish
+       'tru' => 'Ṫuroyo', # Turoyo
        'ts' => 'Xitsonga',             # Tsonga
        'tt' => 'татарча/tatarça',      # Tatar (multiple scripts - defaults to Cyrillic)
        'tt-cyrl' => 'татарча',  # Tatar (Cyrillic script) (default)
index 48ec9b9..461db78 100644 (file)
@@ -356,6 +356,10 @@ $magicWords = array(
        'url_query'              => array( 0,    'QUERY' ),
        'defaultsort_noerror'    => array( 0,    'noerror' ),
        'defaultsort_noreplace'  => array( 0,    'noreplace' ),
+       'pagesincategory_all'    => array( 0,    'all' ),
+       'pagesincategory_pages'  => array( 0,    'pages' ),
+       'pagesincategory_subcats' => array( 0,   'subcats' ),
+       'pagesincategory_files'  => array( 0,    'files' ),
 );
 
 /**
index fba4e9f..eeafab8 100644 (file)
@@ -9,5 +9,7 @@
  *
  */
 
+$rtl = true;
+
 # Inherit everything for now
 $fallback = 'kk-arab, kk-cyrl';
index 78e9481..a17741f 100644 (file)
@@ -13,6 +13,8 @@
  * @author Marmzok
  */
 
+$rtl = true;
+
 $fallback = 'ckb';
 
 $digitTransformTable = array(
diff --git a/languages/messages/MessagesTru.php b/languages/messages/MessagesTru.php
new file mode 100644 (file)
index 0000000..c3b8cb9
--- /dev/null
@@ -0,0 +1,881 @@
+<?php
+/** Ṫuroyo (Ṫuroyo)
+ *
+ * See MessagesQqq.php for message documentation incl. usage of parameters
+ * To improve a translation please visit http://translatewiki.net
+ *
+ * @ingroup Language
+ * @file
+ *
+ * @author Ariyo
+ */
+
+$messages = array(
+# User preference toggles
+'tog-oldsig' => 'Imḍa du3do:',
+
+'underline-always' => 'Kulnaqa',
+'underline-never'  => 'Hiç',
+
+# Dates
+'sunday'        => 'Yawme dḤuşabo',
+'monday'        => 'Yawme dTre',
+'tuesday'       => 'Yawme dTloṭo',
+'wednesday'     => 'Yawme dArb³o',
+'thursday'      => 'Yawme dḤamşo',
+'friday'        => 'Yawme d3rufto',
+'saturday'      => 'Yawme dŞabṭo',
+'sun'           => 'Yawme dḤuşabo',
+'mon'           => 'Yawme dTre',
+'tue'           => 'Yawme dTloṭo',
+'wed'           => 'Yawme dArb³o',
+'thu'           => 'Yawme dḤamşo',
+'fri'           => 'Yawme d3rufto',
+'sat'           => 'Yawme dŞabṭo',
+'january'       => 'Konun ḥroy',
+'february'      => 'Şboṫ',
+'march'         => 'Oḍor',
+'april'         => 'Nison',
+'may_long'      => 'İyor',
+'june'          => 'Ḥziron',
+'july'          => 'Tamuz',
+'august'        => 'Ob',
+'september'     => 'Eylül',
+'october'       => 'Teşrin qḍim',
+'november'      => 'Teşrin ḥroy',
+'december'      => 'Konun qḍim',
+'january-gen'   => 'Konun ḥroy',
+'february-gen'  => 'Şboṫ',
+'march-gen'     => 'Oḍor',
+'april-gen'     => 'Nison',
+'may-gen'       => 'İyor',
+'june-gen'      => 'Ḥziron',
+'july-gen'      => 'Tamuz',
+'august-gen'    => 'Ob',
+'september-gen' => 'Eylül',
+'october-gen'   => 'Teşrin qḍim',
+'november-gen'  => 'Teşrin ḥroy',
+'december-gen'  => 'Konun qḍim',
+'jan'           => 'Konun II',
+'feb'           => 'Şboṫ',
+'mar'           => 'Oḍor',
+'apr'           => 'Nison',
+'may'           => 'İyor',
+'jun'           => 'Ḥziron',
+'jul'           => 'Tamuz',
+'aug'           => 'Ob',
+'sep'           => 'Eylül',
+'oct'           => 'Teşrin I',
+'nov'           => 'Teşrin II',
+'dec'           => 'Konun I',
+
+# Categories related messages
+'pagecategories'         => '{{PLURAL:$1|Sedro|Sedre}}',
+'category_header'        => 'Faṭoṭe bu Sedro "$1"',
+'subcategories'          => 'Sedre na³ime',
+'category-media-header'  => 'Mediya buSedro "$1"',
+'category-empty'         => 'U³do layto Faṭo aw Mediya buSedrano.',
+'hidden-categories'      => '{{PLURAL:$1|Hidden category|Hidden categories}}',
+'category-subcat-count'  => '{{PLURAL:$2|This category has only the following subcategory.|This category has the following {{PLURAL:$1|subcategory|$1 subcategories}}, out of $2 total.}}',
+'category-article-count' => '{{PLURAL:$2|This category contains only the following page.|The following {{PLURAL:$1|page is|$1 pages are}} in this category, out of $2 total.}}',
+'category-file-count'    => '{{PLURAL:$2|This category contains only the following file.|The following {{PLURAL:$1|file is|$1 files are}} in this category, out of $2 total.}}',
+'listingcontinuesabbrev' => 'mdawam',
+'noindex-category'       => 'Noindexed pages',
+
+'about'         => '3al',
+'newwindow'     => '(gmıftaḥ bKawṭo ḥaṭto)',
+'cancel'        => 'Mbaṫel',
+'moredotdotdot' => 'Heşa...',
+'mypage'        => 'iFaṭayḍi',
+'mytalk'        => 'uMamlayḍi',
+'navigation'    => 'Navigasyon',
+'and'           => '&#32;u',
+
+# Cologne Blue skin
+'qbfind'         => 'Ḥzay',
+'qbbrowse'       => 'Krax',
+'qbedit'         => 'Mşaḥlaf',
+'qbpageoptions'  => 'iFaṭaṭe',
+'qbmyoptions'    => 'aFaṭoṭayḍi',
+'qbspecialpages' => 'Faṭoṭe dilonoye',
+'faq'            => 'Şuwole',
+'faqpage'        => 'Project:FAQ',
+
+# Vector skin
+'vector-action-addsection' => 'Maḥat Fusoqo ḥaṭo',
+'vector-action-delete'     => 'Slag',
+'vector-action-move'       => 'Mtaxar',
+'vector-action-protect'    => 'Mastar',
+'vector-view-create'       => 'Xlaq',
+'vector-view-edit'         => 'Mşaḥlaf',
+'vector-view-history'      => 'Maktabzabno',
+'vector-view-view'         => 'Qray',
+'vector-view-viewsource'   => 'Maḥway li aMabu³e.',
+'actions'                  => 'Dubore',
+'namespaces'               => 'Dukṭo luIşmo',
+'variants'                 => 'Variants',
+
+'errorpagetitle'    => 'Fawdo',
+'returnto'          => 'D³ar l$1',
+'tagline'           => 'men {{SITENAME}}',
+'help'              => '3udrono',
+'search'            => 'krax',
+'searchbutton'      => 'Krax',
+'go'                => 'Zux',
+'searcharticle'     => 'Zux',
+'history'           => 'Maktabzabno diFaṭo',
+'history_short'     => 'Maktabzabno',
+'updatedmarker'     => 'aŞuḥlofe datsimi miNaqa du3boroayḍi ḥaroyo',
+'printableversion'  => 'Printable version',
+'permalink'         => 'Asiruṭo aminoyto',
+'print'             => 'Ṫba³',
+'view'              => 'Qray',
+'edit'              => 'Mşaḥlaf',
+'create'            => 'Xlaq',
+'editthispage'      => 'Mşaḥlaf iFaṭaṭe',
+'create-this-page'  => 'Xlaq iFaṭaṭe',
+'delete'            => 'Slag',
+'deletethispage'    => 'Slag iFaṭaṭe',
+'protect'           => 'Mastar',
+'protect_change'    => 'mşaḥlaf',
+'protectthispage'   => 'Mastar iFaṭaṭe',
+'newpage'           => 'Faṭo ḥaṭto',
+'talkpage'          => 'Sım Droşo 3al iFaṭaṭe',
+'talkpagelinktext'  => 'Mamlo',
+'specialpage'       => 'Faṭo dilonoyto',
+'personaltools'     => 'aMonayḍi',
+'postcomment'       => 'Fusoqo ḥaṭo',
+'articlepage'       => 'Ḥur baḤbişoṭo',
+'talk'              => 'Droşo',
+'views'             => 'Ḥzayoṭo',
+'toolbox'           => 'Mone',
+'viewtalkpage'      => 'Ḥur buDroşo',
+'otherlanguages'    => 'bLeşone ḥrene',
+'redirectedfrom'    => '(Redirected from $1)',
+'lastmodifiedat'    => 'uŞuḥlofo ḥaroyo diFaṭaṭe bu Zabnano wa:  $1 $2 .',
+'jumpto'            => 'Zux l',
+'jumptonavigation'  => 'Navigasyon',
+'jumptosearch'      => 'Kruxyo',
+'pool-errorunknown' => 'Fawdo nuxroyo',
+
+# All link text and link target definitions of links into project namespace that get used by other message strings, with the exception of user group pages (see grouppage) and the disambiguation template definition (see disambiguations).
+'aboutsite'            => '3al {{SITENAME}}',
+'aboutpage'            => 'Project: 3al',
+'copyrightpage'        => '{{ns:project}}:Ḥaqat duKaṭowo',
+'currentevents'        => 'Gedşe du³do',
+'currentevents-url'    => 'Project:Gedşe du3do',
+'disclaimers'          => 'Disclaimers',
+'disclaimerpage'       => 'Project: Disclaimer gawonoyo',
+'edithelp'             => 'Editing help',
+'edithelppage'         => 'Help:Mşaḥlaf',
+'helppage'             => 'Help: Ḥbişoṭo',
+'mainpage'             => 'Faṭo rişoyto',
+'mainpage-description' => 'Faṭo rişoyto',
+'portal'               => 'Portal diJama³a',
+'portal-url'           => 'Project: Portal diJama³a',
+'privacy'              => 'Setoro daMawd³onwoṭo',
+'privacypage'          => 'Project: Setoro daMawd³onwoṭo',
+
+'badaccess-group0' => 'Hat latlux uFsoso dkolozım dsaymat iḤarakaṭe.',
+
+'ok'                      => 'Tamam',
+'retrievedfrom'           => 'men "$1"',
+'youhavenewmessages'      => 'Kıtlux $1 ($2) .',
+'newmessageslink'         => 'Ṫebe ḥaṭe',
+'newmessagesdifflink'     => 'Degoşo ḥaroyo',
+'youhavenewmessagesmulti' => 'Kitlux Ṫebe ḥaṭe b$1',
+'editsection'             => 'mşaḥlaf',
+'editold'                 => 'mşaḥlaf',
+'viewsourceold'           => 'Maḥway li uMabu³o.',
+'editlink'                => 'mşaḥlaf',
+'viewsourcelink'          => 'Maḥway li uMabu³o.',
+'editsectionhint'         => 'Mşaḥlaf uFusoqano: $1',
+'toc'                     => 'Ḥbişoṭo',
+'showtoc'                 => 'maḥway',
+'hidetoc'                 => 'tlay',
+'collapsible-collapse'    => 'sxar',
+'collapsible-expand'      => 'ftaḥ',
+'feedlinks'               => 'Feed:',
+'site-rss-feed'           => '$1 RSS feed',
+'site-atom-feed'          => '$1 Atom feed',
+'page-rss-feed'           => '"$1" RSS feed',
+'page-atom-feed'          => 'Atom feed l"$1"',
+'red-link-title'          => '$1 (layto iFaṭaṭe)',
+
+# Short words for each namespace, by default used in the namespace tab in monobook
+'nstab-main'      => 'Faṭo',
+'nstab-user'      => 'Faṭo duHadomo',
+'nstab-media'     => 'Faṭo diMediya',
+'nstab-special'   => 'Faṭo dilonoyto',
+'nstab-project'   => 'Faṭo die Proja',
+'nstab-image'     => 'Fayl',
+'nstab-mediawiki' => 'Ṫebo',
+'nstab-template'  => 'Template',
+'nstab-help'      => 'Faṭo d3udrono',
+'nstab-category'  => 'Sedro',
+
+# General errors
+'error'              => 'Fawdo',
+'missing-article'    => 'uSyomo d$1 $2 lo komaḥwe biDatabase.
+
+iFaṭaṭe belki sligo aw mtaxro merke.
+
+Elo iḍa dlo howe hawxa belki ḥselux Fawdo biSoftware. Bo³o haw Ṫebo l[[Special:ListUsers/sysop|Administrator]] u kṭaw u"URL".',
+'missingarticle-rev' => '(Numara duVersyon: $1)',
+'badtitle'           => 'Bad title',
+'badtitletext'       => 'The requested page title was invalid, empty, or an incorrectly linked inter-language or inter-wiki title.
+It may contain one or more characters which cannot be used in titles.',
+'viewsource'         => 'Maḥway li aMabu³e.',
+'namespaceprotected' => "Hat latlux Ḥaq dımşaḥılfat Faṭoṭe bi'''$1''' Dukṭo xliṭo.",
+
+# Virus scanner
+'virus-unknownscanner' => 'Antivirus nuxroyo:',
+
+# Login and logout pages
+'yourname'                => 'Işme duHadomo:',
+'yourpassword'            => 'Qliḍo:',
+'yourpasswordagain'       => 'Naqla ḥreto kṭaw uQliḍo:',
+'remembermypassword'      => 'Dxar uQliḍayḍi buBrowser (buSowudo $1 {{PLURAL:$1|Yawmo|Yawme}})',
+'login'                   => '3bar',
+'nav-login-createaccount' => '3bar / Hway Hadomo',
+'loginprompt'             => 'Glozım maqablat Cookies qanna dqudrat fıtḥat {{SITENAME}}.',
+'userlogin'               => '3bar / Hway Hadomo',
+'userloginnocreate'       => '3bar',
+'logout'                  => 'Nfoqo',
+'userlogout'              => 'Nfoqo',
+'notloggedin'             => 'Heş lo3abirat.',
+'nologin'                 => 'Heş lawit Hadomo? $1',
+'nologinlink'             => 'Hway Hadomo',
+'createaccount'           => 'Hway Hadomo',
+'gotaccount'              => 'Ma hawit ste Hadomo? $1',
+'gotaccountlink'          => '3bar',
+'userlogin-resetlink'     => 'Ṫa³at uQliḍayḍox?',
+'createaccountmail'       => 'buEmail',
+'wrongpassword'           => 'uQliḍayḍux fawdo yo.
+Mjarab Naqla ḥreto.',
+'wrongpasswordempty'      => 'Lo msta³melux uQliḍayḍux.
+Mjarab Naqla ḥreto.',
+'password-name-match'     => 'Glozım towe Frişuṭo beyn uQliḍo u uIşmayḍux.',
+'mailmypassword'          => 'Mşadar li Qliḍo ḥaṭo',
+'loginlanguagelabel'      => 'Leşono: $1',
+
+# Change password dialog
+'resetpass'                 => 'Mşaḥlaf uQliḍo.',
+'oldpassword'               => 'Qliḍo 3atiqo:',
+'newpassword'               => 'Qliḍo ḥaṭo:',
+'retypenew'                 => 'Qliḍo ḥaṭo (disa):',
+'resetpass-submit-loggedin' => 'Mşaḥlaf uQliḍo',
+
+# Special:PasswordReset
+'passwordreset-username' => 'Işme duHadomo:',
+
+# Special:ChangeEmail
+'changeemail-newemail' => 'Email-adres ḥaṭo:',
+
+# Edit page toolbar
+'bold_sample'     => 'Ḥarfe ḥlime',
+'bold_tip'        => 'Ḥarfe ḥlime',
+'italic_sample'   => 'Ḥarfe 3wije',
+'italic_tip'      => 'Ḥarfe 3wije',
+'link_sample'     => 'Link title',
+'link_tip'        => 'Internal link',
+'extlink_sample'  => 'http://www.example.com link title',
+'extlink_tip'     => 'External link (remember http:// prefix)',
+'headline_sample' => 'Headline text',
+'headline_tip'    => 'Level 2 headline',
+'nowiki_sample'   => 'Insert non-formatted text here',
+'nowiki_tip'      => 'uSyomano latyo buFormat',
+'image_tip'       => 'Embedded file',
+'media_tip'       => 'File link',
+'sig_tip'         => 'Mḍay herke u kṭaw iSa³aye muqa yo.',
+'hr_tip'          => 'Horizontal line (use sparingly)',
+
+# Edit pages
+'summary'                          => 'Summary:',
+'minoredit'                        => 'This is a minor edit',
+'watchthis'                        => 'Watch this page',
+'savearticle'                      => 'Mqayad iFaṭaṭe',
+'preview'                          => 'Preview',
+'showpreview'                      => 'Show preview',
+'showdiff'                         => 'Maḥway aŞuḥlofe',
+'anoneditwarning'                  => "'''Diqad''' Heş lo 3abirat.
+uIP-Adresayḍux gmikṭaw buMaktabzabno diFaṭaṭe. Kul Noşo kibe ḥozele u lo komislag.",
+'loginreqtitle'                    => 'Glozım 3obrat',
+'loginreqlink'                     => '3bar',
+'loginreqpagetext'                 => 'Glozım $1 qanna dqudrat ḥozat Faṭoṭe ḥrene.',
+'newarticle'                       => '(Ḥaṭo)',
+'newarticletext'                   => "You have followed a link to a page that does not exist yet.
+To create the page, start typing in the box below (see the [[{{MediaWiki:Helppage}}|help page]] for more info).
+If you are here by mistake, click your browser's '''back''' button.",
+'noarticletext'                    => 'There is currently no text in this page.
+You can [[Special:Search/{{PAGENAME}}|search for this page title]] in other pages,
+<span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} search the related logs],
+or [{{fullurl:{{FULLPAGENAME}}|action=edit}} edit this page]</span>.',
+'noarticletext-nopermission'       => 'There is currently no text in this page.
+You can [[Special:Search/{{PAGENAME}}|search for this page title]] in other pages,
+or <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} search the related logs]</span>.',
+'previewnote'                      => "'''Remember that this is only a preview.'''
+Your changes have not yet been saved!",
+'editing'                          => 'Şuḥlofo d$1',
+'editingsection'                   => 'Mşaḥlaf $1 (Fusoqo)',
+'yourtext'                         => 'uSyomayḍux',
+'yourdiff'                         => 'Frişwoṭo',
+'templatesused'                    => '{{PLURAL:$1|Template|Templates}} used on this page:',
+'template-protected'               => '(protected)',
+'template-semiprotected'           => '(semi-protected)',
+'hiddencategories'                 => 'This page is a member of {{PLURAL:$1|1 hidden category|$1 hidden categories}}:',
+'permissionserrorstext-withaction' => 'You do not have permission to $2, for the following {{PLURAL:$1|reason|reasons}}:',
+'recreate-moveddeleted-warn'       => "'''Warning: You are recreating a page that was previously deleted.'''
+
+You should consider whether it is appropriate to continue editing this page.
+The deletion and move log for this page are provided here for convenience:",
+'moveddeleted-notice'              => 'iFaṭaṭe sligto yo.
+The deletion and move log for the page are provided below for reference.',
+
+# Parser/template warnings
+'post-expand-template-inclusion-warning'  => "'''Warning:''' Template include size is too large.
+Some templates will not be included.",
+'post-expand-template-inclusion-category' => 'Pages where template include size is exceeded',
+'post-expand-template-argument-warning'   => "'''Warning:''' This page contains at least one template argument which has a too large expansion size.
+These arguments have been omitted.",
+'post-expand-template-argument-category'  => 'Pages containing omitted template arguments',
+
+# History pages
+'viewpagelogs'           => 'View logs for this page',
+'currentrev-asof'        => 'Latest revision as of $1',
+'revisionasof'           => 'Versyon 3atiqo diNaqa: $1',
+'revision-info'          => 'Revision as of $1 by $2',
+'previousrevision'       => '←Versyon 3atiqtır',
+'nextrevision'           => 'Versyon ḥaṭtır',
+'currentrevisionlink'    => 'Latest revision',
+'cur'                    => 'du³do',
+'next'                   => 'Ḥreto',
+'last'                   => 'dmeqım',
+'page_first'             => 'Badaye',
+'page_last'              => 'Ḥarayto',
+'histlegend'             => "Diff selection: Mark the radio boxes of the revisions to compare and hit enter or the button at the bottom.<br />
+Legend: '''({{int:cur}})''' = difference with latest revision, '''({{int:last}})''' = difference with preceding revision, '''{{int:minoreditletter}}''' = minor edit.",
+'history-fieldset-title' => 'Krax buMaktabzabno',
+'history-show-deleted'   => 'Bes aSlige',
+'histfirst'              => 'Meqım kulle',
+'histlast'               => 'Ḥaṭo',
+'historysize'            => '({{PLURAL:$1|1 byte|$1 bytes}})',
+'historyempty'           => '(xalyo)',
+
+# Revision feed
+'history-feed-item-nocomment' => '$1  b$2',
+
+# Revision deletion
+'rev-delundel'               => 'maḥway / tlay',
+'rev-showdeleted'            => 'maḥway',
+'revdelete-show-file-submit' => 'Eh',
+'revdelete-radio-same'       => '(lo mşaḥalfat)',
+'revdelete-radio-set'        => 'Eh',
+'revdelete-radio-unset'      => 'Lo',
+'revdel-restore'             => 'change visibility',
+'revdel-restore-deleted'     => 'deleted revisions',
+'revdel-restore-visible'     => 'visible revisions',
+'pagehist'                   => 'Maktabzabno diFaṭo',
+
+# Merge log
+'revertmerge' => 'Unmerge',
+
+# Diffs
+'history-title'           => 'Revision history of "$1"',
+'lineno'                  => 'Serṫo $1:',
+'compareselectedversions' => 'Compare selected revisions',
+'editundo'                => 'slag',
+'diff-multi'              => '({{PLURAL:$1|One intermediate revision|$1 intermediate revisions}} by {{PLURAL:$2|one user|$2 users}} not shown)',
+
+# Search results
+'searchresults'                    => 'Nafqe duKruxyayḍux',
+'searchresults-title'              => 'Nafqe duKruxyo l"$1"',
+'searchsubtitleinvalid'            => "Karixat '''$1'''",
+'prevn'                            => '{{PLURAL:$1|$1}} meqımtır',
+'nextn'                            => '{{PLURAL:$1 ḥaṭtır| $1 ḥaṭtır }}',
+'prevn-title'                      => '{{PLURAL:$1 Nafqo meqımtır|$1 Nafqe meqımtır}}',
+'nextn-title'                      => '{{PLURAL:$1|Nafqo ḥreno|$1 Nafqe ḥrene}}',
+'shown-title'                      => 'maḥway $1 {{PLURAL:$1|Nafqo|Nafqe}} bḥḍo Faṭo',
+'viewprevnext'                     => 'Maḥway ($1 {{int:pipe-separator}} $2) ($3)',
+'searchmenu-legend'                => '3ayar duKruxyo',
+'searchmenu-exists'                => "'''Kito Faṭo herke Işma \"[[:\$1]]\"yo'''",
+'searchmenu-new'                   => 'Kṭaw iFaṭaṭe "[[:$1]]" buWiki.',
+'searchhelp-url'                   => 'Help: Ḥbişoṭo',
+'searchprofile-articles'           => 'Faṭoṭe daḤbişoṭo',
+'searchprofile-project'            => 'Faṭoṭe du3udrono u daProjat',
+'searchprofile-images'             => 'Multimediya',
+'searchprofile-everything'         => 'Kulmede',
+'searchprofile-advanced'           => 'Advanced',
+'searchprofile-articles-tooltip'   => 'Krax b$1',
+'searchprofile-project-tooltip'    => 'Krax b$1',
+'searchprofile-images-tooltip'     => 'Krax Ṥurtoṭe',
+'searchprofile-everything-tooltip' => 'Krax baḤbişoṭo (baFaṭoṭe duDroşo ste)',
+'searchprofile-advanced-tooltip'   => 'Search in custom namespaces',
+'search-result-size'               => '$1 ({{PLURAL:$2|1 Melṭo|$2 Mele}})',
+'search-result-category-size'      => '{{PLURAL:$1|1 Hadomo|$1 Hadome}} ({{PLURAL:$2|1 Sedro taḥtoyo|$2 Sedre taḥtoye}}, {{PLURAL:$3|1 file|$3 files}})',
+'search-redirect'                  => '(Asiruṭo men $1)',
+'search-section'                   => '(Fusoqo $1)',
+'search-suggest'                   => 'Ub³atwa dkıṭwat: $1?',
+'search-interwiki-more'            => '(heşa)',
+'searchrelated'                    => 'related',
+'searchall'                        => 'kulle',
+'showingresultsheader'             => "{{PLURAL:$5|Nafqo '''$1''' of '''$3'''|Nafqe '''$1 - $2''' men '''$3'''}} l'''$4'''",
+'search-nonefound'                 => 'Für deine Suchanfrage wurden keine Ergebnisse gefunden.',
+'powersearch-field'                => 'Krax',
+'powersearch-togglelabel'          => 'Sım Qontrol:',
+'powersearch-toggleall'            => 'Kulle',
+
+# Preferences page
+'preferences'               => '3ayarat',
+'mypreferences'             => 'a3ayaratayḍi',
+'prefs-edits'               => 'Menyono daŞuḥlofe kulle:',
+'prefs-resetpass'           => 'Mşaḥlaf uQliḍo',
+'prefs-email'               => '3ayarat duEmail',
+'saveprefs'                 => 'Mqayad',
+'searchresultshead'         => 'Kruxyo',
+'timezoneregion-africa'     => 'Afriqa',
+'timezoneregion-america'    => 'Ameriqa',
+'timezoneregion-antarctica' => 'Antarctica',
+'timezoneregion-arctic'     => 'Arctic',
+'timezoneregion-asia'       => 'Asia',
+'timezoneregion-atlantic'   => 'Yamo atlantikoyo',
+'timezoneregion-australia'  => 'Australia',
+'timezoneregion-europe'     => 'Awrifi',
+'timezoneregion-indian'     => 'Yamo hindoyo',
+'youremail'                 => 'Adres duEmail',
+'username'                  => 'Işme duHadomo:',
+'prefs-memberingroups'      => 'Hadomo d{{PLURAL:$1|Gudo|Gudoṭo}}:',
+'prefs-registration'        => 'Zabno duSugolo:',
+'yourrealname'              => 'Işmo şariro:',
+'yourlanguage'              => 'Leşono',
+'yournick'                  => 'Imḍa ḥaṭto:',
+'yourgender'                => 'Ğenso:',
+'gender-male'               => 'Dekronoyo',
+'gender-female'             => 'Neqıbṭonoyo',
+'email'                     => 'Email',
+'prefs-help-email'          => 'Latat majbur dkıṭwat uEmail-Adresayḍox, elo glozam inaqla ṫo³at uQliḍayḍox u hakka dlozam dmişadar lox Qliḍo ḥaṭo.',
+'prefs-help-email-others'   => 'Kibux mijğolat 3am Hadome ğer biFaṭo duMamlo u luglozam dumat Işmux.',
+'prefs-signature'           => 'Imḍa',
+
+# User preference: e-mail validation using jQuery
+'email-address-validity-valid' => 'uEmail-Adresayḍux m³adlo yo.',
+
+# Groups
+'group-user' => 'Hadome',
+'group-all'  => '(kulle)',
+
+# Associated actions - in the sentence "You do not have permission to X"
+'action-edit' => 'Mşaḥlaf iFaṭaṭe',
+
+# Recent changes
+'nchanges'                        => '$1 {{PLURAL:$1|Şuḥlofo|Şuḥlofe}}',
+'recentchanges'                   => 'Şuḥlofe ḥaroye',
+'recentchanges-legend'            => '3ayar daŞuḥlofe',
+'recentchanges-summary'           => 'biFaṭaṭe kibox ḥozat aŞuḥlofe ḥaroye.',
+'recentchanges-feed-description'  => 'biFaṭaṭe kibox ḥozat aŞuḥlofe ḥaroye.',
+'recentchanges-label-newpage'     => 'Faṭo ḥaṭto',
+'recentchanges-label-minor'       => 'This is a minor edit',
+'recentchanges-label-bot'         => 'uŞuḥlofano sim muBot.',
+'recentchanges-label-unpatrolled' => 'This edit has not yet been patrolled',
+'rcnote'                          => "Below {{PLURAL:$1|is '''1''' change|are the last '''$1''' changes}} in the last {{PLURAL:$2|day|'''$2''' days}}, as of $5, $4.",
+'rcnotefrom'                      => 'Herke komaḥwın aŞuḥlofe ḥaroye men ""$2"" (hul buSowudo ""$1"").',
+'rclistfrom'                      => 'Maḥway li Şuḥlofe ḥaṭe men $1',
+'rcshowhideminor'                 => '$1 minor edits',
+'rcshowhidebots'                  => '$1 bots',
+'rcshowhideliu'                   => '$1 Hadome d3abiri',
+'rcshowhideanons'                 => '$1 Hadomo nuxroyo',
+'rcshowhidepatr'                  => '$1 patrolled edits',
+'rcshowhidemine'                  => 'aMaṫwoṭayḍi ($1)',
+'rclinks'                         => 'Maḥway li $1 aŞuḥlofe ḥaroye men meqım $2 Yawme hul u³do. <br />$3',
+'diff'                            => 'Frişuṭo',
+'hist'                            => 'Maktabzabno',
+'hide'                            => 'Tlay',
+'show'                            => 'Maḥway',
+'minoreditletter'                 => 'm',
+'newpageletter'                   => 'N',
+'boteditletter'                   => 'b',
+'rc-enhanced-expand'              => 'Maḥway aŞelole',
+'rc-enhanced-hide'                => 'Tlay aŞelole',
+
+# Recent changes linked
+'recentchangeslinked'          => 'Şuḥlofe bFaṭoṭe masre',
+'recentchangeslinked-toolbox'  => 'Şuḥlofe bFaṭoṭe masre',
+'recentchangeslinked-title'    => 'Şuḥlofe bFaṭoṭe dkıtne masre b$1',
+'recentchangeslinked-noresult' => 'No changes on linked pages during the given period.',
+'recentchangeslinked-summary'  => "This is a list of changes made recently to pages linked from a specified page (or to members of a specified category).
+Pages on [[Special:Watchlist|your watchlist]] are '''bold'''.",
+'recentchangeslinked-page'     => 'Işmo diFaṭo',
+'recentchangeslinked-to'       => 'Maḥway li Şuḥlofe dFaṭoṭe dkitne masre lerke.',
+
+# Upload
+'upload'        => 'Mosaq Fayl',
+'uploadlogpage' => 'Upload log',
+'filedesc'      => 'Sfiquṭo',
+'uploadedimage' => 'mosaq "[[$1]]"',
+
+'license'        => 'Fsoso',
+'license-header' => 'Fsoso',
+
+# File description page
+'file-anchor-link'       => 'Fayl',
+'filehist'               => 'Maktabzabno duFayl',
+'filehist-help'          => 'Click on a date/time to view the file as it appeared at that time.',
+'filehist-revert'        => 'revert',
+'filehist-current'       => 'current',
+'filehist-datetime'      => 'Zabno',
+'filehist-thumb'         => 'Thumbnail',
+'filehist-thumbtext'     => 'Thumbnail for version as of $1',
+'filehist-user'          => 'Hadomo',
+'filehist-dimensions'    => 'Dimensions',
+'filehist-comment'       => 'Comment',
+'imagelinks'             => 'File usage',
+'linkstoimage'           => 'The following {{PLURAL:$1|page links|$1 pages link}} to this file:',
+'nolinkstoimage'         => 'There are no pages that link to this file.',
+'sharedupload-desc-here' => 'This file is from $1 and may be used by other projects.
+The description on its [$2 file description page] there is shown below.',
+
+# Random page
+'randompage' => 'Faṭo gedşonoyto',
+
+# Statistics
+'statistics' => 'Mardonwoṭo',
+
+'disambiguationspage' => 'Template:disambig',
+
+'brokenredirects-edit'   => 'mşaḥlaf',
+'brokenredirects-delete' => 'slag',
+
+# Miscellaneous special pages
+'nbytes'        => '$1 {{PLURAL:$1|byte|bytes}}',
+'nmembers'      => '$1 {{PLURAL:$1|Hadomo|Hadome}}',
+'prefixindex'   => 'aFaṭoṭe kulle dkitte Prefiks',
+'usercreated'   => '{{GENDER:$3|kṭule}}  $1 b$2',
+'newpages'      => 'Faṭoṭe ḥaṭe',
+'move'          => 'Mtaxar',
+'pager-newer-n' => '{{PLURAL:$1|1 ḥreno |$1 ḥrene}}',
+'pager-older-n' => '{{PLURAL:$1|3atiqo1|3atiqe $1}}',
+
+# Book sources
+'booksources'               => 'Kruxyo baNumarat duISBN',
+'booksources-search-legend' => 'Krax Mabu³e me Kṭowe',
+'booksources-go'            => 'Zux',
+
+# Special:Log
+'log' => 'Logs',
+
+# Special:AllPages
+'allpages'       => 'aFaṭaṭe kulle',
+'alphaindexline' => '$1  l$2',
+'allarticles'    => 'aFaṭaṭe kulle',
+'allpagesnext'   => 'Ḥreto',
+'allpagessubmit' => 'Zux',
+
+# Special:Categories
+'categories' => 'Sedre',
+
+# Special:DeletedContributions
+'deletedcontributions'             => 'Maṫwoṭo slige',
+'deletedcontributions-title'       => 'Maṫwoṭo slige',
+'sp-deletedcontributions-contribs' => 'Maṫwoṭo',
+
+# Special:LinkSearch
+'linksearch-ok'   => 'Krax',
+'linksearch-line' => '$1 masro yo b$2',
+
+# Special:ListUsers
+'listusers-submit' => 'Maḥway',
+
+# Special:Log/newusers
+'newuserlogpage' => 'User creation log',
+
+# Special:ListGroupRights
+'listgrouprights-group'    => 'Gudo',
+'listgrouprights-rights'   => 'Ḥaqat',
+'listgrouprights-helppage' => 'Help: Ḥaqat diGudo',
+'listgrouprights-members'  => '(Lista daHadome)',
+
+# E-mail user
+'emailuser'     => 'Kṭaw Email luHadomano.',
+'emailusername' => 'Işme duHadomo:',
+'emailfrom'     => 'Men:',
+'emailto'       => 'Lwoṭ:',
+'emailmessage'  => 'Ṫebo:',
+
+# Watchlist
+'watchlist'         => 'My watchlist',
+'mywatchlist'       => 'My watchlist',
+'watchlistfor2'     => 'L$1 $2',
+'watch'             => 'Watch',
+'unwatch'           => 'Unwatch',
+'watchlist-details' => '{{PLURAL:$1|$1 page|$1 pages}} on your watchlist, not counting talk pages.',
+'wlshowlast'        => 'Maḥway li aŞuḥlofe dıtsimi meqım $1 Sa³ayat $2 Yawme $3',
+'watchlist-options' => 'Watchlist options',
+
+# Delete
+'actioncomplete' => 'uDuboro kamıl',
+'actionfailed'   => 'Action failed',
+'dellogpage'     => 'Deletion log',
+
+# Rollback
+'rollbacklink' => 'rollback',
+
+# Protect
+'protectlogpage'   => 'Protection log',
+'protectedarticle' => 'mastar "[[$1]]"',
+
+# Undelete
+'undeletelink'              => 'view/restore',
+'undeleteviewlink'          => 'ḥur',
+'undelete-search-submit'    => 'Krax',
+'undelete-show-file-submit' => 'Eh',
+
+# Namespace form on various pages
+'namespace'      => 'Dukṭo luIşmo',
+'invert'         => 'Invert selection',
+'blanknamespace' => '(Rişoyto)',
+
+# Contributions
+'contributions'       => 'Maṫwoṭo duHadomo:',
+'contributions-title' => 'Maṫwoṭo d$1',
+'mycontris'           => 'aMaṫwoṭayḍi',
+'contribsub2'         => 'd$1 ($2)',
+'uctop'               => '(ḥaroyo)',
+'month'               => 'muYarḥo',
+'year'                => 'hul iŞato:',
+
+'sp-contributions-newbies'  => 'Bes maḥway Maṫwoṭo dHadome ḥaṭe',
+'sp-contributions-blocklog' => 'Block log',
+'sp-contributions-deleted'  => 'Maṫwoṭo slige',
+'sp-contributions-uploads'  => 'Fayl masalqo',
+'sp-contributions-logs'     => 'logs',
+'sp-contributions-talk'     => 'Mamlo',
+'sp-contributions-search'   => 'Krax Maṫwoṭo',
+'sp-contributions-username' => 'IP-Adres aw Işme duHadmomo:',
+'sp-contributions-toponly'  => 'Only show edits that are latest revisions',
+'sp-contributions-submit'   => 'Krax',
+
+# What links here
+'whatlinkshere'            => 'Asirwoṭo biFaṭaṭe',
+'whatlinkshere-title'      => 'Faṭoṭe dkitte Asiruṭo 3am"$1"',
+'whatlinkshere-page'       => 'Faṭo',
+'linkshere'                => "aFaṭoṭani masre ne 3am '''[[:$1]]''':",
+'nolinkshere'              => "Layto Faṭoṭe dkitte Asiruṭo 3am '''[[:$1]]'''.",
+'isredirect'               => 'redirect page',
+'istemplate'               => 'transclusion',
+'isimage'                  => 'Asiruṭo duFayl',
+'whatlinkshere-prev'       => '{{PLURAL:$1|meqımtır|$1 meqımtır}}',
+'whatlinkshere-next'       => '{{PLURAL:$1|ḥreno|$1 ḥrene}}',
+'whatlinkshere-links'      => '← Asirwoṭo',
+'whatlinkshere-hideredirs' => '$1 redirects',
+'whatlinkshere-hidetrans'  => '$1 transclusions',
+'whatlinkshere-hidelinks'  => '$1 Asirwoṭo',
+'whatlinkshere-hideimages' => '$1 Asiruṭo duFayl',
+'whatlinkshere-filters'    => 'Filtrat',
+
+# Block/unblock
+'ipboptions'               => '2 Sa³ayat:2 hours,1 Yawmo:1 day,3 Yawme:3 days,1 Şabṭo:1 week,2 Şabe:2 weeks,1 Yarḥo:1 month,3 Yarḥe:3 months,6 Yarḥe :6 months,1 Şato:1 year,indefinite:infinite',
+'ipblocklist'              => 'Blocked users',
+'ipblocklist-submit'       => 'Krax',
+'blocklink'                => 'Maḥram',
+'unblocklink'              => 'unblock',
+'change-blocklink'         => 'change block',
+'contribslink'             => 'Maṫwoṭo',
+'blocklogpage'             => 'Block log',
+'blocklogentry'            => 'blocked [[$1]] with an expiry time of $2 $3',
+'block-log-flags-nocreate' => 'account creation disabled',
+
+# Move page
+'movelogpage' => 'Move log',
+'revertmove'  => 'revert',
+
+# Export
+'export' => 'Mofaq iFaṭaṭe',
+
+# Namespace 8 related
+'allmessages'               => 'Ṫebo duSistem dMEdiaWiki',
+'allmessagesname'           => 'Işmo',
+'allmessagesdefault'        => 'Syomo standard',
+'allmessages-language'      => 'Leşono',
+'allmessages-filter-submit' => 'Zux',
+
+# Thumbnails
+'thumbnail-more'  => 'Rabtır',
+'thumbnail_error' => 'Error creating thumbnail: $1',
+
+# Tooltip help for the actions
+'tooltip-pt-userpage'             => 'iFaṭaṭyḍox',
+'tooltip-pt-mytalk'               => 'iFaṭayḍux duDroşo',
+'tooltip-pt-preferences'          => 'a3ayaratayḍux',
+'tooltip-pt-watchlist'            => 'Lista dFaṭoṭe dkib³at mşaḥılfat',
+'tooltip-pt-mycontris'            => 'Lista daMaṫwoṭayḍox',
+'tooltip-pt-login'                => 'İnaqa demqaydat ruḥox ṫawo yo, elo letat mejbur',
+'tooltip-pt-logout'               => 'Nfoqo',
+'tooltip-ca-talk'                 => 'Droşo 3al iFaṭo daḤbişoṭo',
+'tooltip-ca-edit'                 => 'Kibux mşaḥılfat iFaṭaṭe, elo bo³o msta³mal uZra³lo duQontrol meqım demqaydat iFaṭo',
+'tooltip-ca-addsection'           => 'Bday Fusoqo ḥaṭo',
+'tooltip-ca-viewsource'           => 'This page is protected.
+You can view its source',
+'tooltip-ca-history'              => 'Past revisions of this page',
+'tooltip-ca-protect'              => 'Mastar iFaṭaṭe',
+'tooltip-ca-delete'               => 'Slag iFaṭaṭe',
+'tooltip-ca-move'                 => 'Mataxar iFaṭaṭe',
+'tooltip-ca-watch'                => 'Add this page to your watchlist',
+'tooltip-ca-unwatch'              => 'Remove this page from your watchlist',
+'tooltip-search'                  => 'Krax{{SITENAME}}',
+'tooltip-search-go'               => 'Zux liFaṭo dkitla tam uIşmano.',
+'tooltip-search-fulltext'         => 'Krax uSyomano baFaṭoṭe',
+'tooltip-p-logo'                  => 'Z³ar iFaṭo rişoyto',
+'tooltip-n-mainpage'              => 'Z³ar iFaṭo rişoyto',
+'tooltip-n-mainpage-description'  => 'Z³ar iFaṭo rişoyto',
+'tooltip-n-portal'                => '3al iProja; mın komisam u ayko u ayko ne a medone.',
+'tooltip-n-currentevents'         => 'Find background information on current events',
+'tooltip-n-recentchanges'         => 'Lista daŞuḥlofe ḥaroye kulle',
+'tooltip-n-randompage'            => 'Ftaḥ Faṭo gedşonoyto',
+'tooltip-n-help'                  => 'Maḥway iFaṭo du3udrono',
+'tooltip-t-whatlinkshere'         => 'Lista daFaṭoṭe kulle dkitte Asiruṭo lerke',
+'tooltip-t-recentchangeslinked'   => 'Şuḥlofe ḥaroye bFaṭoṭe dkitte Asiruṭo lerke',
+'tooltip-feed-atom'               => 'Atom feed diFaṭaṭe',
+'tooltip-t-contributions'         => 'Lista daMaṫwoṭo duHadomano',
+'tooltip-t-emailuser'             => 'Mşadar Email luHadomano',
+'tooltip-t-upload'                => 'Mosaq aFayls',
+'tooltip-t-specialpages'          => 'Lista daFaṭoṭe dilonoye kulle.',
+'tooltip-t-print'                 => 'Printable version of this page',
+'tooltip-t-permalink'             => 'Asiruṭo aminoyto liFaṭaṭe',
+'tooltip-ca-nstab-main'           => 'Maḥway iFaṭo daḤbişoṭo',
+'tooltip-ca-nstab-user'           => 'Maḥway iFaṭo duHadomo',
+'tooltip-ca-nstab-special'        => 'Haṭe Faṭo dilonoyto yo, laybux mşaḥalfatla',
+'tooltip-ca-nstab-project'        => 'Maḥway iFaṭo diProja',
+'tooltip-ca-nstab-image'          => 'Maḥway iFaṭo duFayl',
+'tooltip-ca-nstab-template'       => 'View the template',
+'tooltip-ca-nstab-category'       => 'Maḥway iFaṭo daSedre',
+'tooltip-minoredit'               => 'Mark this as a minor edit',
+'tooltip-save'                    => 'Mqayad uŞuḥlofano',
+'tooltip-preview'                 => 'Preview your changes, please use this before saving!',
+'tooltip-diff'                    => 'Maḥway li aŞuḥlofe buSyomano',
+'tooltip-compareselectedversions' => 'See the differences between the two selected revisions of this page',
+'tooltip-watch'                   => 'Add this page to your watchlist',
+'tooltip-rollback'                => '"Rollback" reverts edit(s) to this page of the last contributor in one click',
+'tooltip-undo'                    => '"Undo" reverts this edit and opens the edit form in preview mode. It allows adding a reason in the summary.',
+'tooltip-summary'                 => 'Enter a short summary',
+
+# Browsing diffs
+'previousdiff' => '← Şuḥlofo 3atiqo',
+'nextdiff'     => 'Hiç lo mşaḥalfat →',
+
+# Media information
+'file-info-size' => '$1 × $2 pixels, file size: $3, MIME type: $4',
+'file-nohires'   => 'No higher resolution available.',
+'svg-long-desc'  => 'SCG Fayl, Rabuṭo $1 × $2 pixel, Rabuṭo duFayl: $3',
+'show-big-image' => 'Tam faṥiḥ',
+
+# Special:NewFiles
+'ilsubmit' => 'Krax',
+
+# Video information, used by Language::formatTimePeriod() to format lengths in the above messages
+'seconds' => '{{PLURAL:$1|$1 Ṥaniye|$1 Ṥaniyat}}',
+'ago'     => 'meqım $1',
+
+# Bad image list
+'bad_image_list' => 'The format is as follows:
+
+Only list items (lines starting with *) are considered.
+The first link on a line must be a link to a bad file.
+Any subsequent links on the same line are considered to be exceptions, i.e. pages where the file may occur inline.',
+
+# Metadata
+'metadata'        => 'Metadata',
+'metadata-help'   => 'This file contains additional information, probably added from the digital camera or scanner used to create or digitize it.
+If the file has been modified from its original state, some details may not fully reflect the modified file.',
+'metadata-fields' => 'Image metadata fields listed in this message will be included on image page display when the metadata table is collapsed.
+Others will be hidden by default.
+* make
+* model
+* datetimeoriginal
+* exposuretime
+* fnumber
+* isospeedratings
+* focallength
+* artist
+* copyright
+* imagedescription
+* gpslatitude
+* gpslongitude
+* gpsaltitude',
+
+# EXIF tags
+'exif-writer'          => 'Kaṭowo',
+'exif-languagecode'    => 'Leşono',
+'exif-cameraownername' => 'uMoro diQamera',
+
+# External editor support
+'edit-externally'      => 'Edit this file using an external application',
+'edit-externally-help' => '(See the [//www.mediawiki.org/wiki/Manual:External_editors setup instructions] for more information)',
+
+# 'all' in various places, this might be different for inflected languages
+'watchlistall2' => 'kulle',
+'namespacesall' => 'kulle',
+'monthsall'     => 'kulle',
+
+# Watchlist editing tools
+'watchlisttools-view' => 'View relevant changes',
+'watchlisttools-edit' => 'View and edit watchlist',
+'watchlisttools-raw'  => 'Edit raw watchlist',
+
+# Core parser functions
+'duplicate-defaultsort' => '\'\'\'Warning:\'\'\' Default sort key "$2" overrides earlier default sort key "$1".',
+
+# Special:FilePath
+'filepath-submit' => 'Zux',
+
+# Special:FileDuplicateSearch
+'fileduplicatesearch-submit' => 'Krax',
+
+# Special:SpecialPages
+'specialpages' => 'Faṭoṭe dilonoye',
+
+# Special:BlankPage
+'blankpage' => 'Faṭo xliṭo',
+
+# External image whitelist
+'external_image_whitelist' => ' #Leave this line exactly as it is<pre>
+#Put regular expression fragments (just the part that goes between the //) below
+#These will be matched with the URLs of external (hotlinked) images
+#Those that match will be displayed as images, otherwise only a link to the image will be shown
+#Lines beginning with # are treated as comments
+#This is case-insensitive
+
+#Put all regex fragments above this line. Leave this line exactly as it is</pre>',
+
+# Special:Tags
+'tag-filter' => '[[Special:Tags|Tag]] filter:',
+
+# Special:ComparePages
+'compare-page1' => 'Faṭo 1',
+'compare-page2' => 'Faṭo 2',
+
+# Database error messages
+'dberr-problems' => 'Şubqono!
+iFaṭaṭe u3do kitla Qaṫre.',
+
+# HTML forms
+'htmlform-submit'              => 'Mqayad',
+'htmlform-selectorother-other' => 'Ḥrene',
+
+# Feedback
+'feedback-message' => 'Ṫebo:',
+'feedback-cancel'  => 'Mbaṫel',
+
+# API errors
+'api-error-unknownerror' => 'Fawdo nuxroyo: $1',
+
+# Durations
+'duration-seconds'   => '$1 {{PLURAL:$1|Ṥaniye|Ṥaniyat}}',
+'duration-minutes'   => '$1 {{PLURAL:$1|Qaṫınto|Qaṫınoṭo}}',
+'duration-hours'     => '$1 {{PLURAL:$1|Sa³aye|Sa³ayat}}',
+'duration-days'      => '$1 {{PLURAL:$1|Yawmo|Yawme}}',
+'duration-weeks'     => '$1 {{PLURAL:$1|Şabṭo|Şabe}}',
+'duration-years'     => '$1 {{PLURAL:$1|Şato|Şnaye}}',
+'duration-decades'   => '$1 {{PLURAL:$1|decade|decades}}',
+'duration-centuries' => '$1 {{PLURAL:$1|Doro|Dore}}',
+
+);
index 2c38ed9..c0a4dba 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * Maintenance script to do test JavaScript validity parses using jsmin+'s parser
+ * Test JavaScript validity parses using jsmin+'s parser
  *
  * 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
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
+ * @file
  * @ingroup Maintenance
  */
 
 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
 
+/**
+ * Maintenance script to do test JavaScript validity parses using jsmin+'s parser
+ *
+ * @ingroup Maintenance
+ */
 class JSParseHelper extends Maintenance {
        var $errs = 0;
 
index dc8bff5..19c549a 100644 (file)
 
 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
 
+/**
+ * Maintenance script to show database lag.
+ *
+ * @ingroup Maintenance
+ */
 class DatabaseLag extends Maintenance {
        public function __construct() {
                parent::__construct();
index 088eaa3..ed8250b 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /**
- * This script makes several 'set', 'incr' and 'get' requests on every
- * memcached server and shows a report.
+ * Makes several 'set', 'incr' and 'get' requests on every memcached
+ * server and shows a report.
  *
  * 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
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
+ * @file
  * @ingroup Maintenance
  */
 
 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
 
+/**
+ * Maintenance script that  makes several 'set', 'incr' and 'get' requests
+ * on every memcached server and shows a report.
+ *
+ * @ingroup Maintenance
+ */
 class mcTest extends Maintenance {
        public function __construct() {
                parent::__construct();
index 6a9baa8..8107016 100644 (file)
@@ -28,6 +28,13 @@ define( 'MW_NO_EXTENSION_MESSAGES', 1 );
 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
 $maintClass = 'MergeMessageFileList';
 $mmfl = false;
+
+/**
+ * Maintenance script that merges $wgExtensionMessagesFiles from various
+ * extensions to produce a single array containing all message files.
+ *
+ * @ingroup Maintenance
+ */
 class MergeMessageFileList extends Maintenance {
 
        function __construct() {
index 297aaf3..451b598 100644 (file)
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
+ * @file
  * @ingroup Maintenance
  */
 
 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
 
+/**
+ * Maintenance script that re-assigns users from an old group to a new one.
+ *
+ * @ingroup Maintenance
+ */
 class MigrateUserGroup extends Maintenance {
        public function __construct() {
                parent::__construct();
index e1fd862..b17d8fe 100644 (file)
 
 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
 
+/**
+ * Maintenance script that minifies a file or set of files.
+ *
+ * @ingroup Maintenance
+ */
 class MinifyScript extends Maintenance {
        var $outDir;
 
index a7739c2..f846994 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * Maintenance script to move a batch of pages
+ * Move a batch of pages.
  *
  * 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
@@ -17,6 +17,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
+ * @file
  * @ingroup Maintenance
  * @author Tim Starling
  *
 
 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
 
+/**
+ * Maintenance script to move a batch of pages.
+ *
+ * @ingroup Maintenance
+ */
 class MoveBatch extends Maintenance {
        public function __construct() {
                parent::__construct();
index 74bd657..e2de686 100644 (file)
@@ -2,7 +2,7 @@
 /**
  * Check for articles to fix after adding/deleting namespaces
  *
- * Copyright (C) 2005-2007 Brion Vibber <brion@pobox.com>
+ * Copyright © 2005-2007 Brion Vibber <brion@pobox.com>
  * http://www.mediawiki.org/
  *
  * This program is free software; you can redistribute it and/or modify
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
+ * @file
  * @ingroup Maintenance
  */
 
 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
 
+/**
+ * Maintenance script that checks for articles to fix after
+ * adding/deleting namespaces.
+ *
+ * @ingroup Maintenance
+ */
 class NamespaceConflictChecker extends Maintenance {
 
        /**
index ac4e723..bee4065 100644 (file)
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
+ * @file
  * @todo Make this work on PostgreSQL and maybe other database servers
  * @ingroup Maintenance
  */
 
 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
 
+/**
+ * Maintenance script that picks a database that has pending jobs.
+ *
+ * @ingroup Maintenance
+ */
 class nextJobDB extends Maintenance {
        public function __construct() {
                parent::__construct();
index 5d4f374..1defe1b 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 /**
  * Remove pages with only 1 revision from the MediaWiki namespace, without
  * flooding recent changes, delete logs, etc.
@@ -28,6 +27,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
+ * @file
  * @ingroup Maintenance
  * @author Steve Sanbeg
  * based on nukePage by Rob Church
 
 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
 
+/**
+ * Maintenance script that removes pages with only one revision from the
+ * MediaWiki namespace.
+ *
+ * @ingroup Maintenance
+ */
 class NukeNS extends Maintenance {
        public function __construct() {
                parent::__construct();
index f63de43..3193d43 100644 (file)
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
+ * @file
  * @ingroup Maintenance
  * @author Rob Church <robchur@gmail.com>
  */
 
 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
 
+/**
+ * Maintenance script that erases a page record from the database.
+ *
+ * @ingroup Maintenance
+ */
 class NukePage extends Maintenance {
        public function __construct() {
                parent::__construct();
index faaadd3..1ab3b99 100644 (file)
@@ -1,11 +1,11 @@
 <?php
 /**
- * Look for 'orphan' revisions hooked to pages which don't exist
- * And 'childless' pages with no revisions.
+ * Look for 'orphan' revisions hooked to pages which don't exist and
+ * 'childless' pages with no revisions.
  * Then, kill the poor widows and orphans.
  * Man this is depressing.
  *
- * Copyright (C) 2005 Brion Vibber <brion@pobox.com>
+ * Copyright © 2005 Brion Vibber <brion@pobox.com>
  * http://www.mediawiki.org/
  *
  * This program is free software; you can redistribute it and/or modify
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
+ * @file
  * @author <brion@pobox.com>
  * @ingroup Maintenance
  */
 
 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
 
+/**
+ * Maintenance script that looks for 'orphan' revisions hooked to pages which
+ * don't exist and 'childless' pages with no revisions.
+ *
+ * @ingroup Maintenance
+ */
 class Orphans extends Maintenance {
        public function __construct() {
                parent::__construct();
                $this->mDescription = "Look for 'orphan' revisions hooked to pages which don't exist\n" .
-                                                               "And 'childless' pages with no revisions\n" .
+                                                               "and 'childless' pages with no revisions\n" .
                                                                "Then, kill the poor widows and orphans\n" .
                                                                "Man this is depressing";
                $this->addOption( 'fix', 'Actually fix broken entries' );
index c4ba66e..2dcf757 100644 (file)
@@ -129,7 +129,7 @@ class SyncFileBackend extends Maintenance {
                        if ( $status->isOK() ) {
                                $lastOKPos = max( $lastOKPos, $lastPosInBatch );
                        } else {
-                               $this->output( print_r( $status->getErrorsArray(), true ) );
+                               $this->error( print_r( $status->getErrorsArray(), true ) );
                                break; // no gaps; everything up to $lastPos must be OK
                        }
 
index b871ac7..95e5e80 100644 (file)
                 * @constructor
                 * @param {Object|String} URI string, or an Object with appropriate properties (especially another URI object to clone).
                 * Object must have non-blank 'protocol', 'host', and 'path' properties.
+                * This parameter is optional. If omitted (or set to undefined, null or empty string), then an object will be created
+                * for the default uri of this constructor (e.g. document.location for mw.Uri in MediaWiki core).
                 * @param {Object|Boolean} Object with options, or (backwards compatibility) a boolean for strictMode
                 * - strictMode {Boolean} Trigger strict mode parsing of the url. Default: false
                 * - overrideKeys {Boolean} Wether to let duplicate query parameters override eachother (true) or automagically
                                overrideKeys: false
                        }, options );
 
-                       if ( uri !== undefined && uri !== null || uri !== '' ) {
+                       if ( uri !== undefined && uri !== null && uri !== '' ) {
                                if ( typeof uri === 'string' ) {
                                        this.parse( uri, options );
                                } else if ( typeof uri === 'object' ) {
                                                this.query = {};
                                        }
                                }
+                       } else {
+                               // If we didn't get a URI in the constructor, use the default one.
+                               return defaultUri.clone();
                        }
 
                        // protocol-relative URLs
index 903a4f7..57f81a0 100644 (file)
@@ -198,12 +198,22 @@ pre, .mw-code {
        border: 1px dashed #2f6fab;
        color: black;
        background-color: #f9f9f9;
-       /* Handle overflow (bug 260) */
-       overflow: auto;
-       /* IE 7 is the first IE to support overflow but got it wrong */
-       /* IE 8+ is fine */
-       *padding-bottom: 21px;
-       *overflow-y: hidden;
+
+       /*
+        * Wrap properly.
+        * - pre-wrap: causes the browser to naturally wrap by displaying
+        *   words on the next line if they don't fit on the same line
+        *   within the box (does not cut off words).
+        * - break-word: forces the browser to wrap anywhere (even within
+        *   a word) if it is (still) too long for the line.
+        * When only using break-word in a <pre>, the browser only uses
+        * the force behavior and as a result almost always cuts half-way
+        * a word. When only using pre-wrap, too-long words will still
+        * cause the page layout to break. The combination is magic :).
+        * See also https://bugzilla.wikimedia.org/show_bug.cgi?id=260#c20
+        */
+       white-space: pre-wrap;
+       word-wrap: break-word;
 }
 
 /* Tables */
index 1b839b5..8c114f0 100644 (file)
@@ -828,12 +828,13 @@ h1:lang(hi),
 h1:lang(kn),
 h1:lang(ml),
 h1:lang(mr),
+h1:lang(my),
 h1:lang(or),
 h1:lang(pa),
 h1:lang(sa),
 h1:lang(ta),
 h1:lang(te) {
-       line-height: 1.5em !important;
+       line-height: 1.6em !important;
 }
 h2:lang(as), h3:lang(as), h4:lang(as), h5:lang(as), h6:lang(as),
 h2:lang(bho), h3:lang(bho), h4:lang(bho), h5:lang(bho), h6:lang(bho),
@@ -844,6 +845,7 @@ h2:lang(hi), h3:lang(hi), h4:lang(hi), h5:lang(hi), h6:lang(hi),
 h2:lang(kn), h3:lang(kn), h4:lang(kn), h5:lang(kn), h6:lang(kn),
 h2:lang(ml), h3:lang(ml), h4:lang(ml), h5:lang(ml), h6:lang(ml),
 h2:lang(mr), h3:lang(mr), h4:lang(mr), h5:lang(mr), h6:lang(mr),
+h2:lang(my), h3:lang(my), h4:lang(my), h5:lang(my), h6:lang(my),
 h2:lang(or), h3:lang(or), h4:lang(or), h5:lang(or), h6:lang(or),
 h2:lang(pa), h3:lang(pa), h4:lang(pa), h5:lang(pa), h6:lang(pa),
 h2:lang(sa), h3:lang(sa), h4:lang(sa), h5:lang(sa), h6:lang(sa),
index 8f18d6e..c96eba0 100644 (file)
@@ -400,16 +400,16 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
         * @param boolean $named If the keys should match
         */
        protected function assertArrayEquals( array $expected, array $actual, $ordered = false, $named = false ) {
-               if ( !$named ) {
-                       $expected = array_values( $expected );
-                       $actual = array_values( $actual );
-               }
-
                if ( !$ordered ) {
                        asort( $expected );
                        asort( $actual );
                }
 
+               if ( !$named ) {
+                       $expected = array_values( $expected );
+                       $actual = array_values( $actual );
+               }
+
                call_user_func_array(
                        array( $this, 'assertEquals' ),
                        array_merge( array( $expected, $actual ), array_slice( func_get_args(), 4 ) )
index 9913fb9..9ab5c78 100644 (file)
@@ -344,27 +344,7 @@ test( 'Handle protocol-relative URLs', function () {
 
 test( 'Bad calls', function () {
        var uri;
-       expect( 5 );
-
-       raises(
-               function () {
-                       new mw.Uri();
-               },
-               function ( e ) {
-                       return e.message === 'Bad constructor arguments';
-               },
-               'throw error on no arguments to constructor'
-       );
-
-       raises(
-               function () {
-                       new mw.Uri( '' );
-               },
-               function ( e ) {
-                       return e.message === 'Bad constructor arguments';
-               },
-               'throw error on empty string as argument to constructor'
-       );
+       expect( 3 );
 
        raises(
                function () {
@@ -415,3 +395,23 @@ test( 'bug 35658', function () {
        equal( href, testProtocol + testServer + ':' + testPort + testPath, 'Root-relative URL gets host, protocol, and port supplied' );
 
 } );
+
+QUnit.test( 'Constructor falls back to default location', function (assert) {
+       var testuri, MyUri, uri;
+       QUnit.expect( 4 );
+
+       testuri = 'http://example.org/w/index.php';
+       MyUri = mw.UriRelative( testuri );
+
+       uri = new MyUri();
+       assert.equal( uri.toString(), testuri, 'no arguments' );
+
+       uri = new MyUri( undefined );
+       assert.equal( uri.toString(), testuri, 'undefined' );
+
+       uri = new MyUri( null );
+       assert.equal( uri.toString(), testuri, 'null' );
+
+       uri = new MyUri( '' );
+       assert.equal( uri.toString(), testuri, 'empty string' );
+} );
index 50d3754..9cfdae4 100644 (file)
--- a/thumb.php
+++ b/thumb.php
@@ -65,19 +65,22 @@ function wfThumbHandle404() {
        # that to the 404 handler, and puts the original request in REDIRECT_URL.
        if ( isset( $_SERVER['REDIRECT_URL'] ) ) {
                # The URL is un-encoded, so put it back how it was
-               $uri = str_replace( "%2F", "/", urlencode( $_SERVER['REDIRECT_URL'] ) );
-               # Just get the URI path (REDIRECT_URL is either a full URL or a path)
-               if ( $uri[0] !== '/' ) {
-                       $bits = wfParseUrl( $uri );
-                       if ( $bits && isset( $bits['path'] ) ) {
-                               $uri = $bits['path'];
-                       }
-               }
+               $uriPath = str_replace( "%2F", "/", urlencode( $_SERVER['REDIRECT_URL'] ) );
        } else {
-               $uri = $_SERVER['REQUEST_URI'];
+               $uriPath = $_SERVER['REQUEST_URI'];
+       }
+       # Just get the URI path (REDIRECT_URL/REQUEST_URI is either a full URL or a path)
+       if ( substr( $uriPath, 0, 1 ) !== '/' ) {
+               $bits = wfParseUrl( $uriPath );
+               if ( $bits && isset( $bits['path'] ) ) {
+                       $uriPath = $bits['path'];
+               } else {
+                       wfThumbError( 404, 'The source file for the specified thumbnail does not exist.' );
+                       return;
+               }
        }
 
-       $params = wfExtractThumbParams( $uri ); // basic wiki URL param extracting
+       $params = wfExtractThumbParams( $uriPath ); // basic wiki URL param extracting
        if ( $params == null ) {
                wfThumbError( 404, 'The source file for the specified thumbnail does not exist.' );
                return;
@@ -265,22 +268,22 @@ function wfStreamThumb( array $params ) {
  * Extract the required params for thumb.php from the thumbnail request URI.
  * At least 'width' and 'f' should be set if the result is an array.
  *
- * @param $uri String Thumbnail request URI path
+ * @param $uriPath String Thumbnail request URI path
  * @return Array|null associative params array or null
  */
-function wfExtractThumbParams( $uri ) {
+function wfExtractThumbParams( $uriPath ) {
        $repo = RepoGroup::singleton()->getLocalRepo();
 
-       $zoneURI = $repo->getZoneUrl( 'thumb' );
-       if ( substr( $zoneURI, 0, 1 ) !== '/' ) {
-               $bits = wfParseUrl( $zoneURI );
-               if ( $bits && isset( $bits['path'] ) ) {
-                       $zoneURI = $bits['path'];
-               } else {
-                       return null;
-               }
+       $zoneUriPath = $repo->getZoneHandlerUrl( 'thumb' )
+               ? $repo->getZoneHandlerUrl( 'thumb' ) // custom URL
+               : $repo->getZoneUrl( 'thumb' ); // default to main URL
+       // URL might be relative ("/images") or protocol-relative ("//lang.site/image")
+       $bits = wfParseUrl( wfExpandUrl( $zoneUriPath, PROTO_INTERNAL ) );
+       if ( $bits && isset( $bits['path'] ) ) {
+               $zoneUriPath = $bits['path'];
+       } else {
+               return null;
        }
-       $zoneUrlRegex = preg_quote( $zoneURI );
 
        $hashDirRegex = $subdirRegex = '';
        for ( $i = 0; $i < $repo->getHashLevels(); $i++ ) {
@@ -288,10 +291,11 @@ function wfExtractThumbParams( $uri ) {
                $hashDirRegex .= "$subdirRegex/";
        }
 
-       $thumbUrlRegex = "!^$zoneUrlRegex/((archive/|temp/)?$hashDirRegex([^/]*)/([^/]*))$!";
+       $thumbPathRegex = "!^" . preg_quote( $zoneUriPath ) .
+               "/((archive/|temp/)?$hashDirRegex([^/]*)/([^/]*))$!";
 
        // Check if this is a valid looking thumbnail request...
-       if ( preg_match( $thumbUrlRegex, $uri, $matches ) ) {
+       if ( preg_match( $thumbPathRegex, $uriPath, $matches ) ) {
                list( /* all */, $rel, $archOrTemp, $filename, $thumbname ) = $matches;
                $filename = urldecode( $filename );
                $thumbname = urldecode( $thumbname );