* &useskin=default will now always display the default skin. Useful for users with a
preference for the non-default skin to look at something using the default skin.
* (bug 27619) Remove preference option to display broken links as link?
-* (bug 34896) Update jQuery JSON plugin to v2.3 (2011-09-17).
+* (bug 34896) jQuery JSON plugin upgraded to v2.3 (2011-09-17).
* (bug 34302) Add CSS classes to email fields in user preferences.
* Introduced $wgDebugDBTransactions to trace transaction status (currently PostgreSQL only).
* (bug 23795) Add parser itself to ParserMakeImageParams hook.
Special:Version
* Edit notices can now be translated.
* jQuery upgraded to 1.8.
-* jQuery UI upgraded to 1.8.22.
-* (bug 35705) QUnit upgraded from v1.2.0 to v1.8.0.
+* jQuery UI upgraded to 1.8.23.
+* (bug 35705) QUnit upgraded from v1.2.0 to v1.9.0.
* (bug 37604) jquery.cookie upgraded to 2011 version.
* (bug 22887) Add warning and tracking category for preprocessor errors
* (bug 31704) Allow selection of associated namespace on the watchlist
* Show change tags when transclude Special:Recentchanges(linked) or Special:Newpages.
* (bug 23226) Add |class= parameter to image links in order to add class(es) to HTML img tag.
* (bug 39431) SVG animated status is now shown in long description
-* (bug 39376) jquery.form upgraded to 3.14
+* (bug 39376) jquery.form upgraded to 3.14.
* SVG files will now show the actual width in the SVG's specified units
in the metadata box.
* Added ResourceLoader module "jquery.jStorage".
* (bug 39273) Added AJAX support for "Show changes" (diff) in LivePreview.
+* Added ResourceLoader module "jquery.badge".
+* mw.util.$content now points to the overall content area in the skin rather than just
+ page text content area. If you need the old behaviour please use $( '#mw-content-text').
=== Bug fixes in 1.20 ===
* (bug 30245) Use the correct way to construct a log page title.
* (bug 34313) MediaWiki API intro message about "HTML format" should mention
the format parameter.
* (bug 32384) Allow descending order for list=watchlistraw.
-* (bug 31883) Limit of bkusers of list=blocks and titles of action=query is not documented in API help.
+* (bug 31883) Limit of bkusers of list=blocks and titles of action=query is
+ not documented in API help.
* (bug 32492) API now allows editing using pageid.
* (bug 32497) API now allows changing of protection level using pageid.
* (bug 32498) API now allows comparing pages using pageids.
* Watchlist notification timestamp may be queried by page and may be updated via the API.
* (bug 38904) prop=revisions&rvstart=... no longer blows up when continuing.
* (bug 39032) ApiQuery generates help in constructor.
-* (bug 11142) Improve file extension blacklist error reporting in API upload
-* (bug 39635) PostgreSQL LOCK IN SHARE MODE option is a syntax error
+* (bug 11142) Improve file extension blacklist error reporting in API upload.
+* (bug 39635) PostgreSQL LOCK IN SHARE MODE option is a syntax error.
+* (bug 36329) Accesskey tooltips for Firefox 14 on Mac should use "ctrl-option-" prefix.
=== Languages updated in 1.20 ===
'StubObject' => 'includes/StubObject.php',
'StubUserLang' => 'includes/StubObject.php',
'TablePager' => 'includes/Pager.php',
+ 'MWTimestamp' => 'includes/Timestamp.php',
'Title' => 'includes/Title.php',
'TitleArray' => 'includes/TitleArray.php',
'TitleArrayFromResult' => 'includes/TitleArray.php',
*/
$wgCopyUploadsDomains = array();
-/**
- * Enable copy uploads from Special:Upload. $wgAllowCopyUploads must also be
- * true. If $wgAllowCopyUploads is true, but this is false, you will only be
- * able to perform copy uploads from the API or extensions (e.g. UploadWizard).
- */
-$wgCopyUploadsFromSpecialUpload = false;
-
/**
* Max size for uploads, in bytes. If not set to an array, applies to all
* uploads. If set to an array, per upload type maximums can be set, using the
/**
* Get a timestamp string in one of various formats
*
+ * @deprecated
* @param $outputtype Mixed: A timestamp in one of the supported formats, the
* function will autodetect which format is supplied and act
* accordingly.
* @return Mixed: String / false The same date in the format specified in $outputtype or false
*/
function wfTimestamp( $outputtype = TS_UNIX, $ts = 0 ) {
- $uts = 0;
- $da = array();
- $strtime = '';
-
- if ( !$ts ) { // We want to catch 0, '', null... but not date strings starting with a letter.
- $uts = time();
- $strtime = "@$uts";
- } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)$/D', $ts, $da ) ) {
- # TS_DB
- } elseif ( preg_match( '/^(\d{4}):(\d\d):(\d\d) (\d\d):(\d\d):(\d\d)$/D', $ts, $da ) ) {
- # TS_EXIF
- } elseif ( preg_match( '/^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/D', $ts, $da ) ) {
- # TS_MW
- } elseif ( preg_match( '/^-?\d{1,13}$/D', $ts ) ) {
- # TS_UNIX
- $uts = $ts;
- $strtime = "@$ts"; // http://php.net/manual/en/datetime.formats.compound.php
- } elseif ( preg_match( '/^\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}.\d{6}$/', $ts ) ) {
- # TS_ORACLE // session altered to DD-MM-YYYY HH24:MI:SS.FF6
- $strtime = preg_replace( '/(\d\d)\.(\d\d)\.(\d\d)(\.(\d+))?/', "$1:$2:$3",
- str_replace( '+00:00', 'UTC', $ts ) );
- } elseif ( preg_match( '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.*\d*)?Z$/', $ts, $da ) ) {
- # TS_ISO_8601
- } elseif ( preg_match( '/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(?:\.*\d*)?Z$/', $ts, $da ) ) {
- #TS_ISO_8601_BASIC
- } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d*[\+\- ](\d\d)$/', $ts, $da ) ) {
- # TS_POSTGRES
- } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d* GMT$/', $ts, $da ) ) {
- # TS_POSTGRES
- } elseif (preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.\d\d\d$/', $ts, $da ) ) {
- # TS_DB2
- } elseif ( preg_match( '/^[ \t\r\n]*([A-Z][a-z]{2},[ \t\r\n]*)?' . # Day of week
- '\d\d?[ \t\r\n]*[A-Z][a-z]{2}[ \t\r\n]*\d{2}(?:\d{2})?' . # dd Mon yyyy
- '[ \t\r\n]*\d\d[ \t\r\n]*:[ \t\r\n]*\d\d[ \t\r\n]*:[ \t\r\n]*\d\d/S', $ts ) ) { # hh:mm:ss
- # TS_RFC2822, accepting a trailing comment. See http://www.squid-cache.org/mail-archive/squid-users/200307/0122.html / r77171
- # The regex is a superset of rfc2822 for readability
- $strtime = strtok( $ts, ';' );
- } elseif ( preg_match( '/^[A-Z][a-z]{5,8}, \d\d-[A-Z][a-z]{2}-\d{2} \d\d:\d\d:\d\d/', $ts ) ) {
- # TS_RFC850
- $strtime = $ts;
- } elseif ( preg_match( '/^[A-Z][a-z]{2} [A-Z][a-z]{2} +\d{1,2} \d\d:\d\d:\d\d \d{4}/', $ts ) ) {
- # asctime
- $strtime = $ts;
- } else {
- # Bogus value...
- wfDebug("wfTimestamp() fed bogus time value: TYPE=$outputtype; VALUE=$ts\n");
-
- return false;
- }
-
- static $formats = array(
- TS_UNIX => 'U',
- TS_MW => 'YmdHis',
- TS_DB => 'Y-m-d H:i:s',
- TS_ISO_8601 => 'Y-m-d\TH:i:s\Z',
- TS_ISO_8601_BASIC => 'Ymd\THis\Z',
- TS_EXIF => 'Y:m:d H:i:s', // This shouldn't ever be used, but is included for completeness
- TS_RFC2822 => 'D, d M Y H:i:s',
- TS_ORACLE => 'd-m-Y H:i:s.000000', // Was 'd-M-y h.i.s A' . ' +00:00' before r51500
- TS_POSTGRES => 'Y-m-d H:i:s',
- TS_DB2 => 'Y-m-d H:i:s',
- );
-
- if ( !isset( $formats[$outputtype] ) ) {
- throw new MWException( 'wfTimestamp() called with illegal output type.' );
- }
-
- if ( function_exists( "date_create" ) ) {
- if ( count( $da ) ) {
- $ds = sprintf("%04d-%02d-%02dT%02d:%02d:%02d.00+00:00",
- (int)$da[1], (int)$da[2], (int)$da[3],
- (int)$da[4], (int)$da[5], (int)$da[6]);
-
- $d = date_create( $ds, new DateTimeZone( 'GMT' ) );
- } elseif ( $strtime ) {
- $d = date_create( $strtime, new DateTimeZone( 'GMT' ) );
- } else {
- return false;
- }
-
- if ( !$d ) {
- wfDebug("wfTimestamp() fed bogus time value: $outputtype; $ts\n");
- return false;
- }
-
- $output = $d->format( $formats[$outputtype] );
- } else {
- if ( count( $da ) ) {
- // Warning! gmmktime() acts oddly if the month or day is set to 0
- // We may want to handle that explicitly at some point
- $uts = gmmktime( (int)$da[4], (int)$da[5], (int)$da[6],
- (int)$da[2], (int)$da[3], (int)$da[1] );
- } elseif ( $strtime ) {
- $uts = strtotime( $strtime );
- }
-
- if ( $uts === false ) {
- wfDebug("wfTimestamp() can't parse the timestamp (non 32-bit time? Update php): $outputtype; $ts\n");
- return false;
- }
-
- if ( TS_UNIX == $outputtype ) {
- return $uts;
- }
- $output = gmdate( $formats[$outputtype], $uts );
- }
-
- if ( ( $outputtype == TS_RFC2822 ) || ( $outputtype == TS_POSTGRES ) ) {
- $output .= ' GMT';
- }
-
- return $output;
+ $timestamp = new MWTimestamp( $ts );
+ return $timestamp->getTimestamp( $outputtype );
}
/**
* @param $recursive Boolean: queue jobs for recursive updates?
*/
function __construct( $title, $parserOutput, $recursive = true ) {
- parent::__construct( );
+ parent::__construct( false ); // no implicit transaction
if ( !( $title instanceof Title ) ) {
throw new MWException( "The calling convention to LinksUpdate::LinksUpdate() has changed. " .
* @param $page WikiPage Page we are updating
*/
function __construct( WikiPage $page ) {
- parent::__construct( );
+ parent::__construct( false ); // no implicit transaction
$this->mPage = $page;
}
protected $mOptions; //!< SELECT options to be used (array)
private $mHasTransaction; //!< bool whether a transaction is open on this object (internal use only!)
+ protected $mUseTransaction; //!< bool whether this update should be wrapped in a transaction
/**
* Constructor
- **/
- public function __construct( ) {
+ *
+ * @param bool $withTransaction whether this update should be wrapped in a transaction (default: true).
+ * A transaction is only started if no transaction is already in progress,
+ * see beginTransaction() for details.
+ **/
+ public function __construct( $withTransaction = true ) {
global $wgAntiLockFlags;
parent::__construct( );
// @todo: get connection only when it's needed? make sure that doesn't break anything, especially transactions!
$this->mDb = wfGetDB( DB_MASTER );
+
+ $this->mWithTransaction = $withTransaction;
$this->mHasTransaction = false;
}
/**
- * Begin a database transaction.
+ * Begin a database transaction, if $withTransaction was given as true in the constructor for this SqlDataUpdate.
*
- * Because nested transactions are not supportred by the Database class, this implementation
- * checkes Database::trxLevel() and only opens a transaction if none is yet active.
+ * Because nested transactions are not supported by the Database class, this implementation
+ * checks Database::trxLevel() and only opens a transaction if none is already active.
*/
public function beginTransaction() {
+ if ( !$this->mWithTransaction ) {
+ return;
+ }
+
// NOTE: nested transactions are not supported, only start a transaction if none is open
if ( $this->mDb->trxLevel() === 0 ) {
$this->mDb->begin( get_class( $this ) . '::beginTransaction' );
public function commitTransaction() {
if ( $this->mHasTransaction ) {
$this->mDb->commit( get_class( $this ) . '::commitTransaction' );
+ $this->mHasTransaction = false;
}
}
public function abortTransaction() {
if ( $this->mHasTransaction ) {
$this->mDb->rollback( get_class( $this ) . '::abortTransaction' );
+ $this->mHasTransaction = false;
}
}
--- /dev/null
+<?php
+
+/**
+ * Library for creating and parsing MW-style timestamps. Based on the JS
+ * library that does the same thing.
+ *
+ * @author Tyler Romeo, 2012
+ * @since 1.20
+ */
+class MWTimestamp {
+ /**
+ * Standard gmdate() formats for the different timestamp types.
+ */
+ private static $formats = array(
+ TS_UNIX => 'U',
+ TS_MW => 'YmdHis',
+ TS_DB => 'Y-m-d H:i:s',
+ TS_ISO_8601 => 'Y-m-d\TH:i:s\Z',
+ TS_ISO_8601_BASIC => 'Ymd\THis\Z',
+ TS_EXIF => 'Y:m:d H:i:s', // This shouldn't ever be used, but is included for completeness
+ TS_RFC2822 => 'D, d M Y H:i:s',
+ TS_ORACLE => 'd-m-Y H:i:s.000000', // Was 'd-M-y h.i.s A' . ' +00:00' before r51500
+ TS_POSTGRES => 'Y-m-d H:i:s',
+ TS_DB2 => 'Y-m-d H:i:s',
+ );
+
+ /**
+ * Different units for human readable timestamps.
+ * @see MWTimestamp::getHumanTimestamp
+ */
+ private static $units = array(
+ "milliseconds" => 1,
+ "seconds" => 1000, // 1000 milliseconds per second
+ "minutes" => 60, // 60 seconds per minute
+ "hours" => 60, // 60 minutes per hour
+ "days" => 24 // 24 hours per day
+ );
+
+ /**
+ * The actual timestamp being wrapped. Either a DateTime
+ * object or a string with a Unix timestamp depending on
+ * PHP.
+ */
+ private $timestamp;
+
+ /**
+ * Make a new timestamp and set it to the specified time,
+ * or the current time if unspecified.
+ *
+ * @param $timestamp Timestamp to set, or false for current time
+ */
+ public function __construct( $timestamp = false ) {
+ $this->setTimestamp( $timestamp );
+ }
+
+ /**
+ * Set the timestamp to the specified time, or the current time if unspecified.
+ *
+ * Parse the given timestamp into either a DateTime object or a Unix teimstamp,
+ * and then store it.
+ *
+ * @param $ts Timestamp to store, or false for now
+ */
+ public function setTimestamp( $ts = false ) {
+ $uts = 0;
+ $da = array();
+ $strtime = '';
+
+ if ( !$ts ) { // We want to catch 0, '', null... but not date strings starting with a letter.
+ $uts = time();
+ $strtime = "@$uts";
+ } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)$/D', $ts, $da ) ) {
+ # TS_DB
+ } elseif ( preg_match( '/^(\d{4}):(\d\d):(\d\d) (\d\d):(\d\d):(\d\d)$/D', $ts, $da ) ) {
+ # TS_EXIF
+ } elseif ( preg_match( '/^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/D', $ts, $da ) ) {
+ # TS_MW
+ } elseif ( preg_match( '/^-?\d{1,13}$/D', $ts ) ) {
+ # TS_UNIX
+ $uts = $ts;
+ $strtime = "@$ts"; // http://php.net/manual/en/datetime.formats.compound.php
+ } elseif ( preg_match( '/^\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}.\d{6}$/', $ts ) ) {
+ # TS_ORACLE // session altered to DD-MM-YYYY HH24:MI:SS.FF6
+ $strtime = preg_replace( '/(\d\d)\.(\d\d)\.(\d\d)(\.(\d+))?/', "$1:$2:$3",
+ str_replace( '+00:00', 'UTC', $ts ) );
+ } elseif ( preg_match( '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.*\d*)?Z$/', $ts, $da ) ) {
+ # TS_ISO_8601
+ } elseif ( preg_match( '/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(?:\.*\d*)?Z$/', $ts, $da ) ) {
+ #TS_ISO_8601_BASIC
+ } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d*[\+\- ](\d\d)$/', $ts, $da ) ) {
+ # TS_POSTGRES
+ } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d* GMT$/', $ts, $da ) ) {
+ # TS_POSTGRES
+ } elseif (preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.\d\d\d$/', $ts, $da ) ) {
+ # TS_DB2
+ } elseif ( preg_match( '/^[ \t\r\n]*([A-Z][a-z]{2},[ \t\r\n]*)?' . # Day of week
+ '\d\d?[ \t\r\n]*[A-Z][a-z]{2}[ \t\r\n]*\d{2}(?:\d{2})?' . # dd Mon yyyy
+ '[ \t\r\n]*\d\d[ \t\r\n]*:[ \t\r\n]*\d\d[ \t\r\n]*:[ \t\r\n]*\d\d/S', $ts ) ) { # hh:mm:ss
+ # TS_RFC2822, accepting a trailing comment. See http://www.squid-cache.org/mail-archive/squid-users/200307/0122.html / r77171
+ # The regex is a superset of rfc2822 for readability
+ $strtime = strtok( $ts, ';' );
+ } elseif ( preg_match( '/^[A-Z][a-z]{5,8}, \d\d-[A-Z][a-z]{2}-\d{2} \d\d:\d\d:\d\d/', $ts ) ) {
+ # TS_RFC850
+ $strtime = $ts;
+ } elseif ( preg_match( '/^[A-Z][a-z]{2} [A-Z][a-z]{2} +\d{1,2} \d\d:\d\d:\d\d \d{4}/', $ts ) ) {
+ # asctime
+ $strtime = $ts;
+ } else {
+ throw new TimestampException( __METHOD__ . " : Invalid timestamp - $ts" );
+ }
+
+ if( !$strtime ) {
+ $da = array_map( 'intval', $da );
+ $da[0] = "%04d-%02d-%02dT%02d:%02d:%02d.00+00:00";
+ $strtime = call_user_func_array( "sprintf", $da );
+ }
+
+ if( function_exists( "date_create" ) ) {
+ try {
+ $final = new DateTime( $strtime, new DateTimeZone( 'GMT' ) );
+ } catch(Exception $e) {
+ throw new TimestampException( __METHOD__ . 'Invalid timestamp format.' );
+ }
+ } else {
+ $final = strtotime( $strtime );
+ }
+
+ if( $final === false ) {
+ throw new TimestampException( __METHOD__ . 'Invalid timestamp format.' );
+ }
+ $this->timestamp = $final;
+ }
+
+ /**
+ * Get the timestamp represented by this object in a certain form.
+ *
+ * Convert the internal timestamp to the specified format and then
+ * return it.
+ *
+ * @param $style Output format for timestamp
+ * @return string The formatted timestamp
+ */
+ public function getTimestamp( $style = TS_UNIX ) {
+ if( !isset( self::$formats[$style] ) ) {
+ throw new TimestampException( __METHOD__ . ' : Illegal timestamp output type.' );
+ }
+
+ if( is_object( $this->timestamp ) ) {
+ // DateTime object was used, call DateTime::format.
+ $output = $this->timestamp->format( self::$formats[$style] );
+ } elseif( TS_UNIX == $style ) {
+ // Unix timestamp was used and is wanted, just return it.
+ $output = $this->timestamp;
+ } else {
+ // Unix timestamp was used, use gmdate().
+ $output = gmdate( self::$formats[$style], $this->timestamp );
+ }
+
+ if ( ( $style == TS_RFC2822 ) || ( $style == TS_POSTGRES ) ) {
+ $output .= ' GMT';
+ }
+
+ return $output;
+ }
+
+ /**
+ * Get the timestamp in a human-friendly relative format, e.g., "3 days ago".
+ *
+ * Determine the difference between the timestamp and the current time, and
+ * generate a readable timestamp by returning "<N> <units> ago", where the
+ * largest possible unit is used.
+ *
+ * @return string Formatted timestamp
+ */
+ public function getHumanTimestamp() {
+ $then = $this->getTimestamp( TS_UNIX );
+ $now = time();
+ $timeago = ($now - $then) * 1000;
+ $message = false;
+
+ foreach( self::$units as $unit => $factor ) {
+ $next = $timeago / $factor;
+ if( $next < 1 ) {
+ break;
+ } else {
+ $timeago = $next;
+ $message = array( $unit, floor( $timeago ) );
+ }
+ }
+
+ if( $message ) {
+ $initial = call_user_func_array( 'wfMessage', $message );
+ return wfMessage( 'ago', $initial );
+ } else {
+ return wfMessage( 'just-now' );
+ }
+ }
+
+ public function __toString() {
+ return $this->getTimestamp();
+ }
+}
+
+class TimestampException extends MWException {}
* @return Title the new object
*/
public static function newMainPage() {
- $title = Title::newFromText( wfMsgForContent( 'mainpage' ) );
+ $title = Title::newFromText( wfMessage( 'mainpage' )->inContentLanguage()->text() );
// Don't give fatal errors if the message is broken
if ( !$title ) {
$title = Title::newFromText( 'Main Page' );
* queries by skipping checks for cascading protections and user blocks.
* @param $ignoreErrors Array of Strings Set this to a list of message keys
* whose corresponding errors may be ignored.
- * @return Array of arguments to wfMsg to explain permissions problems.
+ * @return Array of arguments to wfMessage to explain permissions problems.
*/
public function getUserPermissionsErrors( $action, $user, $doExpensiveQueries = true, $ignoreErrors = array() ) {
$errors = $this->getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries );
# Check $wgNamespaceProtection for restricted namespaces
if ( $this->isNamespaceProtected( $user ) ) {
$ns = $this->mNamespace == NS_MAIN ?
- wfMsg( 'nstab-main' ) : $this->getNsText();
+ wfMessage( 'nstab-main' )->text() : $this->getNsText();
$errors[] = $this->mNamespace == NS_MEDIAWIKI ?
array( 'protectedinterface' ) : array( 'namespaceprotected', $ns );
}
$id = $user->blockedBy();
$reason = $user->blockedFor();
if ( $reason == '' ) {
- $reason = wfMsg( 'blockednoreason' );
+ $reason = wfMessage( 'blockednoreason' )->text();
}
$ip = $user->getRequest()->getIP();
* @param $user User to check
* @param $doExpensiveQueries Bool Set this to false to avoid doing unnecessary queries.
* @param $short Bool Set this to true to stop after the first permission error.
- * @return Array of arrays of the arguments to wfMsg to explain permissions problems.
+ * @return Array of arrays of the arguments to wfMessage to explain permissions problems.
*/
protected function getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries = true, $short = false ) {
wfProfileIn( __METHOD__ );
);
# Update the protection log
$log = new LogPage( 'protect' );
- $comment = wfMsgForContent( 'prot_1movedto2', $this->getPrefixedText(), $nt->getPrefixedText() );
+ $comment = wfMessage(
+ 'prot_1movedto2',
+ $this->getPrefixedText(),
+ $nt->getPrefixedText()
+ )->inContentLanguage()->text();
if ( $reason ) {
- $comment .= wfMsgForContent( 'colon-separator' ) . $reason;
+ $comment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $reason;
}
// @todo FIXME: $params?
$log->addEntry( 'move_prot', $nt, $comment, array( $this->getPrefixedText() ) );
$formatter->setContext( RequestContext::newExtraneousContext( $this ) );
$comment = $formatter->getPlainActionText();
if ( $reason ) {
- $comment .= wfMsgForContent( 'colon-separator' ) . $reason;
+ $comment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $reason;
}
# Truncate for whole multibyte characters.
$comment = $wgContLang->truncate( $comment, 255 );
// Certain names may be reserved for batch processes.
foreach ( $reservedUsernames as $reserved ) {
if ( substr( $reserved, 0, 4 ) == 'msg:' ) {
- $reserved = wfMsgForContent( substr( $reserved, 4 ) );
+ $reserved = wfMessage( substr( $reserved, 4 ) )->inContentLanguage()->text();
}
if ( $reserved == $name ) {
return false;
# Local list
if ( self::isLocallyBlockedProxy( $ip ) ) {
$block = new Block;
- $block->setBlocker( wfMsg( 'proxyblocker' ) );
- $block->mReason = wfMsg( 'proxyblockreason' );
+ $block->setBlocker( wfMessage( 'proxyblocker' )->text() );
+ $block->mReason = wfMessage( 'proxyblockreason' )->text();
$block->setTarget( $ip );
} elseif ( $this->isAnon() && $this->isDnsBlacklisted( $ip ) ) {
$block = new Block;
- $block->setBlocker( wfMsg( 'sorbs' ) );
- $block->mReason = wfMsg( 'sorbsreason' );
+ $block->setBlocker( wfMessage( 'sorbs' )->text() );
+ $block->mReason = wfMessage( 'sorbsreason' )->text();
$block->setTarget( $ip );
}
}
if( $str !== null ) {
if( !$wgAuth->allowPasswordChange() ) {
- throw new PasswordError( wfMsg( 'password-change-forbidden' ) );
+ throw new PasswordError( wfMessage( 'password-change-forbidden' )->text() );
}
if( !$this->isValidPassword( $str ) ) {
$message = $valid;
$params = array( $wgMinimalPasswordLength );
}
- throw new PasswordError( wfMsgExt( $message, array( 'parsemag' ), $params ) );
+ throw new PasswordError( wfMessage( $message, $params )->text() );
}
}
if( !$wgAuth->setPassword( $this, $str ) ) {
- throw new PasswordError( wfMsg( 'externaldberror' ) );
+ throw new PasswordError( wfMessage( 'externaldberror' )->text() );
}
$this->setInternalPassword( $str );
$message = 'confirmemail_body_' . $type;
}
- return $this->sendMail( wfMsg( 'confirmemail_subject' ),
- wfMsg( $message,
+ return $this->sendMail( wfMessage( 'confirmemail_subject' )->text(),
+ wfMessage( $message,
$this->getRequest()->getIP(),
$this->getName(),
$url,
$wgLang->timeanddate( $expiration, false ),
$invalidateURL,
$wgLang->date( $expiration, false ),
- $wgLang->time( $expiration, false ) ) );
+ $wgLang->time( $expiration, false ) )->text() );
}
/**
$action = 'create2';
if ( $byEmail ) {
if ( $reason === '' ) {
- $reason = wfMsgForContent( 'newuserlog-byemail' );
+ $reason = wfMessage( 'newuserlog-byemail' )->inContentLanguage()->text();
} else {
$reason = $wgContLang->commaList( array(
- $reason, wfMsgForContent( 'newuserlog-byemail' ) ) );
+ $reason, wfMessage( 'newuserlog-byemail' )->inContentLanguage()->text() ) );
}
}
}
/*
if ( $wgMinimalPasswordLength > 1 ) {
$ret['pattern'] = '.{' . intval( $wgMinimalPasswordLength ) . ',}';
- $ret['title'] = wfMsgExt( 'passwordtooshort', 'parsemag',
- $wgMinimalPasswordLength );
+ $ret['title'] = wfMessage( 'passwordtooshort' )
+ ->numParams( $wgMinimalPasswordLength )->text();
}
*/
if ( $this->oldid ) {
// Always show a link to the diff which triggered the mail. See bug 32210.
- $keys['$NEWPAGE'] = wfMsgForContent( 'enotif_lastdiff',
- $this->title->getCanonicalUrl( 'diff=next&oldid=' . $this->oldid ) );
+ $keys['$NEWPAGE'] = wfMessage( 'enotif_lastdiff',
+ $this->title->getCanonicalUrl( 'diff=next&oldid=' . $this->oldid ) )
+ ->inContentLanguage()->text();
if ( !$wgEnotifImpersonal ) {
// For personal mail, also show a link to the diff of all changes
// since last visited.
- $keys['$NEWPAGE'] .= " \n" . wfMsgForContent( 'enotif_lastvisited',
- $this->title->getCanonicalUrl( 'diff=0&oldid=' . $this->oldid ) );
+ $keys['$NEWPAGE'] .= " \n" . wfMessage( 'enotif_lastvisited',
+ $this->title->getCanonicalUrl( 'diff=0&oldid=' . $this->oldid ) )
+ ->inContentLanguage()->text();
}
$keys['$OLDID'] = $this->oldid;
- $keys['$CHANGEDORCREATED'] = wfMsgForContent( 'changed' );
+ $keys['$CHANGEDORCREATED'] = wfMessage( 'changed' )->inContentLanguage()->text();
} else {
- $keys['$NEWPAGE'] = wfMsgForContent( 'enotif_newpagetext' );
+ $keys['$NEWPAGE'] = wfMessage( 'enotif_newpagetext' )->inContentLanguage()->text();
# clear $OLDID placeholder in the message template
$keys['$OLDID'] = '';
- $keys['$CHANGEDORCREATED'] = wfMsgForContent( 'created' );
+ $keys['$CHANGEDORCREATED'] = wfMessage( 'created' )->inContentLanguage()->text();
}
$keys['$PAGETITLE'] = $this->title->getPrefixedText();
$keys['$PAGETITLE_URL'] = $this->title->getCanonicalUrl();
- $keys['$PAGEMINOREDIT'] = $this->minorEdit ? wfMsgForContent( 'minoredit' ) : '';
+ $keys['$PAGEMINOREDIT'] = $this->minorEdit ?
+ wfMessage( 'minoredit' )->inContentLanguage()->text() : '';
$keys['$UNWATCHURL'] = $this->title->getCanonicalUrl( 'action=unwatch' );
if ( $this->editor->isAnon() ) {
# real anon (user:xxx.xxx.xxx.xxx)
- $keys['$PAGEEDITOR'] = wfMsgForContent( 'enotif_anon_editor', $this->editor->getName() );
- $keys['$PAGEEDITOR_EMAIL'] = wfMsgForContent( 'noemailtitle' );
+ $keys['$PAGEEDITOR'] = wfMessage( 'enotif_anon_editor', $this->editor->getName() )
+ ->inContentLanguage()->text();
+ $keys['$PAGEEDITOR_EMAIL'] = wfMessage( 'noemailtitle' )->inContentLanguage()->text();
} else {
$keys['$PAGEEDITOR'] = $wgEnotifUseRealName ? $this->editor->getRealName() : $this->editor->getName();
$emailPage = SpecialPage::getSafeTitleFor( 'Emailuser', $this->editor->getName() );
# Now build message's subject and body
- $subject = wfMsgExt( 'enotif_subject', 'content' );
+ $subject = wfMessage( 'enotif_subject' )->inContentLanguage()->plain();
$subject = strtr( $subject, $keys );
$subject = MessageCache::singleton()->transform( $subject, false, null, $this->title );
$this->subject = strtr( $subject, $postTransformKeys );
- $body = wfMsgExt( 'enotif_body', 'content' );
+ $body = wfMessage( 'enotif_body' )->inContentLanguage()->plain();
$body = strtr( $body, $keys );
$body = MessageCache::singleton()->transform( $body, false, null, $this->title );
$this->body = wordwrap( strtr( $body, $postTransformKeys ), 72 );
array( '$WATCHINGUSERNAME',
'$PAGEEDITDATE',
'$PAGEEDITTIME' ),
- array( wfMsgForContent( 'enotif_impersonal_salutation' ),
+ array( wfMessage( 'enotif_impersonal_salutation' )->inContentLanguage()->text(),
$wgContLang->date( $this->timestamp, false, false ),
$wgContLang->time( $this->timestamp, false, false ) ),
$this->body );
/** @return string */
function getMessage() {
// '$1 at line $2, col $3 (byte $4): $5',
- return wfMsgHtml( 'xml-error-string',
+ return wfMessage( 'xml-error-string',
$this->mMessage,
$this->mLine,
$this->mColumn,
$this->mByte . $this->mContext,
- xml_error_string( $this->mXmlError ) );
+ xml_error_string( $this->mXmlError ) )->escaped();
}
function _extractContext( $context, $offset ) {
* Create a WikiPage object of the appropriate class for the given title.
*
* @param $title Title
+ * @throws MWException
* @return WikiPage object of the appropriate type
*/
public static function factory( Title $title ) {
* Determine whether a page would be suitable for being counted as an
* article in the site_stats table based on the title & its content
*
- * @param $editInfo Object or false: object returned by prepareTextForEdit(),
+ * @param $editInfo Object|bool (false): object returned by prepareTextForEdit(),
* if false, the current database state will be used
* @return Boolean
*/
if ( $section == 'new' ) {
# Inserting a new section
- $subject = $sectionTitle ? wfMsgForContent( 'newsectionheaderdefaultlevel', $sectionTitle ) . "\n\n" : '';
+ $subject = $sectionTitle ? wfMessage( 'newsectionheaderdefaultlevel' )
+ ->rawParams( $sectionTitle )->inContentLanguage()->text() . "\n\n" : '';
if ( wfRunHooks( 'PlaceNewSection', array( $this, $oldtext, $subject, &$text ) ) ) {
$text = strlen( trim( $oldtext ) ) > 0
? "{$oldtext}\n\n{$subject}{$text}"
* edit-already-exists error will be returned. These two conditions are also possible with
* auto-detection due to MediaWiki's performance-optimised locking strategy.
*
- * @param $baseRevId int the revision ID this edit was based off, if any
+ * @param bool|int $baseRevId int the revision ID this edit was based off, if any
* @param $user User the user doing the edit
*
+ * @throws MWException
* @return Status object. Possible errors:
* edit-hook-aborted: The ArticleSave hook aborted the edit but didn't set the fatal flag of $status
* edit-gone-missing: In update mode, but the article didn't exist
if ( $restrictions != '' ) {
$protectDescription .= $wgContLang->getDirMark() . "[$action=$restrictions] (";
if ( $encodedExpiry[$action] != 'infinity' ) {
- $protectDescription .= wfMsgForContent( 'protect-expiring',
+ $protectDescription .= wfMessage(
+ 'protect-expiring',
$wgContLang->timeanddate( $expiry[$action], false, false ) ,
$wgContLang->date( $expiry[$action], false, false ) ,
- $wgContLang->time( $expiry[$action], false, false ) );
+ $wgContLang->time( $expiry[$action], false, false )
+ )->inContentLanguage()->text();
} else {
- $protectDescription .= wfMsgForContent( 'protect-expiry-indefinite' );
+ $protectDescription .= wfMessage( 'protect-expiry-indefinite' )
+ ->inContentLanguage()->text();
}
$protectDescription .= ') ';
}
# Prepare a null revision to be added to the history
- $editComment = $wgContLang->ucfirst( wfMsgForContent( $revCommentMsg, $this->mTitle->getPrefixedText() ) );
+ $editComment = $wgContLang->ucfirst(
+ wfMessage(
+ $revCommentMsg,
+ $this->mTitle->getPrefixedText()
+ )->inContentLanguage()->text()
+ );
if ( $reason ) {
$editComment .= ": $reason";
}
$editComment .= " ($protectDescription)";
}
if ( $cascade ) {
- $editComment .= ' [' . wfMsgForContent( 'protect-summary-cascade' ) . ']';
+ // FIXME: Should use 'brackets' message.
+ $editComment .= ' [' . wfMessage( 'protect-summary-cascade' )
+ ->inContentLanguage()->text() . ']';
}
# Insert a null revision
* Take an array of page restrictions and flatten it to a string
* suitable for insertion into the page_restrictions field.
* @param $limit Array
+ * @throws MWException
* @return String
*/
protected static function flattenRestrictions( $limit ) {
$target = Revision::newFromId( $s->rev_id );
if ( empty( $summary ) ) {
if ( $from == '' ) { // no public user name
- $summary = wfMsgForContent( 'revertpage-nouser' );
+ $summary = wfMessage( 'revertpage-nouser' )->inContentLanguage()->text();
} else {
- $summary = wfMsgForContent( 'revertpage' );
+ $summary = wfMessage( 'revertpage' )->inContentLanguage()->text();
}
}
$truncatedtext = $wgContLang->truncate(
str_replace( "\n", ' ', $newtext ),
max( 0, 255
- - strlen( wfMsgForContent( 'autoredircomment' ) )
+ - strlen( wfMessage( 'autoredircomment' )->inContentLanguage()->text() )
- strlen( $rt->getFullText() )
) );
- return wfMsgForContent( 'autoredircomment', $rt->getFullText(), $truncatedtext );
+ return wfMessage( 'autoredircomment', $rt->getFullText() )
+ ->rawParams( $truncatedtext )->inContentLanguage()->text();
}
# New page autosummaries
$truncatedtext = $wgContLang->truncate(
str_replace( "\n", ' ', $newtext ),
- max( 0, 200 - strlen( wfMsgForContent( 'autosumm-new' ) ) ) );
+ max( 0, 200 - strlen( wfMessage( 'autosumm-new' )->inContentLanguage()->text() ) ) );
- return wfMsgForContent( 'autosumm-new', $truncatedtext );
+ return wfMessage( 'autosumm-new' )->rawParams( $truncatedtext )
+ ->inContentLanguage()->text();
}
# Blanking autosummaries
if ( $oldtext != '' && $newtext == '' ) {
- return wfMsgForContent( 'autosumm-blank' );
+ return wfMessage( 'autosumm-blank' )->inContentLanguage()->text();
} elseif ( strlen( $oldtext ) > 10 * strlen( $newtext ) && strlen( $newtext ) < 500 ) {
# Removing more than 90% of the article
$truncatedtext = $wgContLang->truncate(
$newtext,
- max( 0, 200 - strlen( wfMsgForContent( 'autosumm-replace' ) ) ) );
+ max( 0, 200 - strlen( wfMessage( 'autosumm-replace' )->inContentLanguage()->text() ) ) );
- return wfMsgForContent( 'autosumm-replace', $truncatedtext );
+ return wfMessage( 'autosumm-replace' )->rawParams( $truncatedtext )
+ ->inContentLanguage()->text();
}
# If we reach this point, there's no applicable autosummary for our case, so our
if ( $blank ) {
// The current revision is blank and the one before is also
// blank. It's just not our lucky day
- $reason = wfMsgForContent( 'exbeforeblank', '$1' );
+ $reason = wfMessage( 'exbeforeblank', '$1' )->inContentLanguage()->text();
} else {
if ( $onlyAuthor ) {
- $reason = wfMsgForContent( 'excontentauthor', '$1', $onlyAuthor );
+ $reason = wfMessage(
+ 'excontentauthor',
+ '$1',
+ $onlyAuthor
+ )->inContentLanguage()->text();
} else {
- $reason = wfMsgForContent( 'excontent', '$1' );
+ $reason = wfMessage( 'excontent', '$1' )->inContentLanguage()->text();
}
}
/**
* @deprecated since 1.18
+ * @param $oldid int
* @return bool
*/
public function useParserCache( $oldid ) {
} else {
$status = $this->doCreateInternal( $params );
$this->clearCache( array( $params['dst'] ) );
- $this->deleteFileCache( $params['dst'] ); // persistent cache
+ if ( !empty( $params['overwrite'] ) ) { // file possibly mutated
+ $this->deleteFileCache( $params['dst'] ); // persistent cache
+ }
}
wfProfileOut( __METHOD__ . '-' . $this->name );
wfProfileOut( __METHOD__ );
} else {
$status = $this->doStoreInternal( $params );
$this->clearCache( array( $params['dst'] ) );
- $this->deleteFileCache( $params['dst'] ); // persistent cache
+ if ( !empty( $params['overwrite'] ) ) { // file possibly mutated
+ $this->deleteFileCache( $params['dst'] ); // persistent cache
+ }
}
wfProfileOut( __METHOD__ . '-' . $this->name );
wfProfileOut( __METHOD__ );
wfProfileIn( __METHOD__ . '-' . $this->name );
$status = $this->doCopyInternal( $params );
$this->clearCache( array( $params['dst'] ) );
- $this->deleteFileCache( $params['dst'] ); // persistent cache
+ if ( !empty( $params['overwrite'] ) ) { // file possibly mutated
+ $this->deleteFileCache( $params['dst'] ); // persistent cache
+ }
wfProfileOut( __METHOD__ . '-' . $this->name );
wfProfileOut( __METHOD__ );
return $status;
$status = $this->doMoveInternal( $params );
$this->clearCache( array( $params['src'], $params['dst'] ) );
$this->deleteFileCache( $params['src'] ); // persistent cache
- $this->deleteFileCache( $params['dst'] ); // persistent cache
+ if ( !empty( $params['overwrite'] ) ) { // file possibly mutated
+ $this->deleteFileCache( $params['dst'] ); // persistent cache
+ }
wfProfileOut( __METHOD__ . '-' . $this->name );
wfProfileOut( __METHOD__ );
return $status;
}
/**
- * Set the cached stat info for a file path
+ * Set the cached stat info for a file path.
+ * Negatives (404s) are not cached. By not caching negatives, we can skip cache
+ * salting for the case when a file is created at a path were there was none before.
*
* @param $path string Storage path
* @param $val mixed Information to cache
return null;
}
- # Check the recursion guard to avoid loops when filling metadata
- if ( empty( $params['nostat'] ) && !$this->fileExists( $params ) ) {
- return null;
- }
-
+ // Blindly create a tmp file and stream to it, catching any exception if the file does
+ // not exist. Also, doing a stat here will cause infinite loops when filling metadata.
$tmpFile = null;
try {
$sContObj = $this->getContainer( $srcCont );
}
} catch ( NoSuchContainerException $e ) {
$tmpFile = null;
+ } catch ( NoSuchObjectException $e ) {
+ $tmpFile = null;
} catch ( CloudFilesException $e ) { // some other exception?
$tmpFile = null;
$this->handleException( $e, null, __METHOD__, $params );
* @return Array: descriptor array
*/
protected function getSourceSection() {
- global $wgCopyUploadsFromSpecialUpload;
-
if ( $this->mSessionKey ) {
return array(
'SessionKey' => array(
);
}
- $canUploadByUrl = UploadFromUrl::isEnabled()
- && UploadFromUrl::isAllowed( $this->getUser() )
- && $wgCopyUploadsFromSpecialUpload;
+ $canUploadByUrl = UploadFromUrl::isEnabled() && UploadFromUrl::isAllowed( $this->getUser() );
$radio = $canUploadByUrl;
$selectedSourceType = strtolower( $this->getRequest()->getText( 'wpSourceType', 'File' ) );
'addedwatchtext' => 'Ouzh ho [[Special:Watchlist|rollad evezhiañ]] eo bet ouzhpennet ar bajenn "[[:$1]]".
Kemmoù da zont ar bajenn-mañ ha re ar bajenn gaozeal stag outi a vo rollet amañ hag e teuio ar bajenn <b>e tev</b> er [[Special:RecentChanges|roll kemmoù diwezhañ]] evit bezañ gwelet aesoc\'h ganeoc\'h.
-Evit tennañ ar bajenn-mañ a-ziwar ho rollad evezhiañ. klikit war "Paouez da evezhiañ" er framm merdeiñ.',
+Evit tennañ ar bajenn-mañ a-ziwar ho rollad evezhiañ, klikit war "Paouez da evezhiañ" er framm merdeiñ.',
'removewatch' => 'Lemel a-ziwar ar roll evezhiañ',
'removedwatchtext' => 'Lamet eo bet ar bajenn "[[:$1]]" a-ziwar ho [[Special:Watchlist|roll evezhiañ]].',
'watch' => 'Evezhiañ',
'badsig' => 'ئیمزاكه ههڵهیه، تهماشای كۆدی HTML بكه',
'badsiglength' => 'واژۆکەت زۆر درێژە.
واژۆ نابێ لە $1 {{PLURAL:$1|نووسە|نووسە}} درێژتر بێت.',
-'yourgender' => 'ڕەگەز:',
+'yourgender' => 'زایەند:',
'gender-unknown' => 'ئاشکرا نەکراو',
'gender-male' => 'پیاو',
'gender-female' => 'ژن',
# Special:DeletedContributions
'deletedcontributions' => 'İştiraqê karberan de besternayına',
'deletedcontributions-title' => 'Îştirakê karberî wederna',
-'sp-deletedcontributions-contribs' => 'iştıraqi',
+'sp-deletedcontributions-contribs' => 'pêşteni',
# Special:LinkSearch
'linksearch' => 'Gıreyê teberi cı geyrê',
'blanknamespace' => '(Ser)',
# Contributions
-'contributions' => 'İştirakê karberi',
+'contributions' => 'İştiraqê karberi',
'contributions-title' => '$1 de iştırakê karberi',
-'mycontris' => 'İştıraqi',
+'mycontris' => 'Pêşteni',
'contribsub2' => 'Qandê $1 ($2)',
'nocontribs' => 'Ena kriteriya de vurnayîş çini yo.',
'uctop' => '(ser)',
'blocklink' => 'kılit ke',
'unblocklink' => 'ake',
'change-blocklink' => 'kılit-kerdışi bıvurne',
-'contribslink' => 'iştıraqi',
+'contribslink' => 'pêşteni',
'emaillink' => 'e-poste bırışe',
'autoblocker' => 'Şıma otomatikmen kılit biy, çıke adresa şımawa \'\'IP\'\'y terefê "[[User:$1|$1]]" gureniyena.
Sebebê kılit-biyayışê $1\'i: "$2"o',
'exif-ycbcrpositioning-1' => 'Wertekerdış',
'exif-ycbcrpositioning-2' => 'Wayırê-site',
-'exif-dc-contributor' => 'İştırakdari',
+'exif-dc-contributor' => 'Pêşteni',
'exif-dc-coverage' => 'Heruna yana wextin grotışa medya',
'exif-dc-date' => 'Tarix(i)',
'exif-dc-publisher' => 'Hesrekar',
# Table pager
'ascending_abbrev' => 'berz',
'descending_abbrev' => 'nızm',
-'table_pager_next' => 'Pela badê cû',
+'table_pager_next' => 'Pela peyên',
'table_pager_prev' => 'Pela verêne',
'table_pager_first' => 'Pela jûyıne',
'table_pager_last' => 'Pela peyêne',
'noarticletext-nopermission' => 'Actualmente no hay texto en esta página.
Puedes [[Special:Search/{{PAGENAME}}|buscar este título de página]] en otras páginas,
o <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} buscar en los registros relacionados]</span>.',
-'missing-revision' => 'La revisión # $1 de la página denominada "{{PAGENAME}}" no existe.
-!¡ N!Esto es generalmente causado al seguir un enlace de historia obsoleto a una página que se ha borrado.!¡ N!Los detalles pueden encontrarse en el [{{fullurl: {{#Special:Log}} / delete|page = {{FULLPAGENAMEE}}}} registro de borrado].',
+'missing-revision' => 'La revisión #$1 de la página «{{PAGENAME}}» no existe.
+
+Esto suele deberse a seguir un enlace obsoleto hacia el historial de una página que ya ha sido borrada.
+Los detalles pueden encontrarse en el [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registro de borrado].',
'userpage-userdoesnotexist' => 'La cuenta de usuario «<nowiki>$1</nowiki>» no está registrada. Por favor comprueba si quieres crear o editar esta página.',
'userpage-userdoesnotexist-view' => 'La cuenta de usuario «$1» no está registrada.',
'blocked-notice-logextract' => 'Este usuario está actualmente bloqueado.
'editundo' => 'deshacer',
'diff-multi' => '(No se {{PLURAL:$1|muestra una edición intermedia realizada|muestran $1 ediciones intermedias realizadas}} por {{PLURAL:$2|un usuario|$2 usuarios}})',
'diff-multi-manyusers' => '(No se {{PLURAL:$1|muestra una edición intermedia|muestran $1 ediciones intermedias}} de {{PLURAL:$2|un usuario|$2 usuarios}})',
-'difference-missing-revision' => '{{PLURAL:$2|Un revisión| $2 revisiones}} de esta diferencia ( $1 ) no {{PLURAL:$2| ha siado encontrada|han sido encontradas}}.
-!¡ N!Esto es generalmente causado por seguir un enlace de diffs obsoletas a una página que ha sido borrada.!¡ N!Los detalles pueden encontrarse en el [{{fullurl:{{#Special:log}} / delete|page = {{FULLPAGENAMEE}}}} registro de borrado].',
+'difference-missing-revision' => 'No {{PLURAL:$2|se ha encontrado|se han encontrado}} {{PLURAL:$2|una revisión|$2 revisiones}} de esta diferencia ($1).
+
+Esto suele deberse a seguir un enlace obsoleto hacia una página que ya ha sido borrada.
+Los detalles pueden encontrarse en el [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registro de borrado].',
# Search results
'searchresults' => 'Resultados de la búsqueda',
'talk' => 'Arutelu',
'views' => 'vaatamisi',
'toolbox' => 'Tööriistad',
-'userpage' => 'Kasutajalehekülg',
+'userpage' => 'Vaata kasutajalehekülge',
'projectpage' => 'Vaata projektilehekülge',
'imagepage' => 'Vaata faililehekülge',
'mediawikipage' => 'Vaata sõnumi lehekülge',
-'templatepage' => 'Mallilehekülg',
+'templatepage' => 'Vaata malli lehekülge',
'viewhelppage' => 'Vaata abilehekülge',
-'categorypage' => 'Kategoorialehekülg',
-'viewtalkpage' => 'Arutelulehekülg',
+'categorypage' => 'Vaata kategooria lehekülge',
+'viewtalkpage' => 'Vaata arutelulehekülge',
'otherlanguages' => 'Teistes keeltes',
'redirectedfrom' => '(Ümber suunatud leheküljelt $1)',
'redirectpagesub' => 'Ümbersuunamisleht',
'youhavenewmessages' => '$1 دارید ($2).',
'newmessageslink' => 'پیامهای جدید',
'newmessagesdifflink' => 'آخرین تغییر',
+'youhavenewmessagesfromusers' => 'شما $1 از {{PLURAL:$3| کاربر دیگر| $3 کاربر}} دارید ( $2 ).',
+'youhavenewmessagesmanyusers' => 'شما $1 از تعدادی کاربر دارید ( $2 ).',
+'newmessageslinkplural' => '{{PLURAL:$1|پیام جدید |پیام جدید}}',
+'newmessagesdifflinkplural' => '$1 {{PLURAL:$1|تغییر|تغییرات}} اخیر',
'youhavenewmessagesmulti' => 'پیامهای جدیدی در $1 دارید.',
'editsection' => 'ویرایش',
'editold' => 'ویرایش',
'dberrortext' => 'اشکال نحوی در درخواست فرستاده شده به پایگاه داده رخ داد.
دلیل این مشکل میتواند ایرادی در نرمافزار باشد.
آخرین درخواست که برای پایگاه داده فرستاد شد این بود:
-<blockquote style="direction:ltr;"><tt>$1</tt></blockquote>
-این درخواست از درون عملگر «<span class="ltr"><tt>$2</tt></span>» فرستاده شد.
+<blockquote style="direction:ltr;"><code>$1</code></blockquote>
+این درخواست از درون عملگر «<span class="ltr"><code>$2</code></span>» فرستاده شد.
پایگاه داده این خطا را بازگرداند:
-<div class="ltr"><tt>$3: $4</tt></div>',
+<div class="ltr"><samp>$3: $4</samp></div>',
'dberrortextcl' => 'اشکال نحوی در درخواست فرستاده شده به پایگاه داده رخ داد.
آخرین درخواستی که برای پایگاه داده فرستاد شد این بود:
<div class="ltr">$1</div>
'noarticletext-nopermission' => 'این صفحه هماکنون متنی ندارد.
شما میتوانید در دیگر صفحهها [[Special:Search/{{PAGENAME}}|این عنوان را جستجو کنید]]،
یا <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} سیاهههای مرتبط را بگردید]</span>.',
+'missing-revision' => 'ویرایش #$1 از صفحهٔ "{{PAGENAME}}" موجود نیست.
+
+معمولاً در اثر پیوند به تاریخچهٔ بهروز نشدهٔ صفحهٔ حذف شده است.
+میتوانید جزئیات بیشتر را در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] بیابید.',
'userpage-userdoesnotexist' => 'حساب کاربر «<nowiki>$1</nowiki>» ثبت نشدهاست.
لطفاً مطمئن شوید که میخواهید این صفحه را ایجاد یا ویرایش کنید.',
'userpage-userdoesnotexist-view' => 'حساب کاربری «$1» ثبت نشدهاست.',
'blocked-notice-logextract' => 'دسترسی این کاربر در حال حاضر بسته است.
آخرین مورد سیاهه قطع دسترسی در زیر آمدهاست:',
-'clearyourcache' => "'''نکته:''' پس از ذخیرهکردن ممکن است برای دیدن تغییرات نیاز باشد که حافظهٔ نهانی مرورگر خود را پاک کنید.
+'clearyourcache' => "''نکته:''' پس از ذخیرهکردن ممکن است برای دیدن تغییرات نیاز باشد که حافظهٔ نهانی مرورگر خود را پاک کنید.
*'''فایرفاکس / سافاری:''' کلید ''Shift'' را نگه دارید و روی دکمهٔ ''Reload'' کلیک کنید، یا کلیدهای ''Ctrl-F5'' یا ''Ctrl-R'' را با هم فشار دهید (در رایانههای اپل مکینتاش کلیدهای ''⌘-R'')
*'''گوگل کروم:'''کلیدهای ''Ctrl+Shift+R'' را با هم فشار دهید. (در رایانههای اپل مکینتاش کلیدهای ''⌘-Shift-R'')
*'''اینترنت اکسپلورر:''' کلید ''Ctrl'' را نگهدارید و روی دکمهٔ ''Refresh'' کلیک کنید، یا کلیدهای ''Ctrl-F5'' را با هم فشار دهید
-*'''کانکوئرر:''' روی دکمهٔ ''Reload'' کلیک کنید و یا کلید ''F5'' را فشار دهید
*'''اپرا:''' حافظهٔ نهانی مرورگر را از طریق منوی ''Tools → Preferences'' پاک کنید",
'usercssyoucanpreview' => "'''نکته:''' پیش از ذخیهکردن فایل CSS یا JS خود، با دکمهٔ '''{{int:showpreview}}''' آن را آزمایش کنید.",
'userjsyoucanpreview' => "'''نکته:''' پیش از ذخیرهکردن فایل CSS یا JS خود، با دکمهٔ '''{{int:showpreview}}''' آن را آزمایش کنید.",
'expansion-depth-exceeded-warning' => 'صفحه حداکثر عمق بسط دادن تجاوز کرد',
'parser-unstrip-loop-warning' => 'حلقه در دستور unstrip پیدا شد',
'parser-unstrip-recursion-limit' => 'از حداکثر ارجاع در دستور unstrip تجاوز شد ($1)',
+'converter-manual-rule-error' => 'خطا در ساختار کتابچهٔ مبدل زبان',
# "Undo" feature
'undo-success' => 'این ویرایش را میتوان خنثی کرد.
'editundo' => 'خنثیسازی',
'diff-multi' => '({{PLURAL:$1|یک|$1}} ویرایش میانی توسط {{PLURAL:$2|یک|$2}} کاربر نشان داده نشدهاست)',
'diff-multi-manyusers' => '({{PLURAL:$1|یک|$1}} ویرایش میانی توسط بیش از {{PLURAL:$2|یک|$2}} کاربر نشان داده نشدهاست)',
+'difference-missing-revision' => '{{PLURAL:$2|یک ویرایش|$2 ویرایش}} از تفاوت نسخهها ($1) {{PLURAL:$2|یافت|یافت}} نشد.
+
+معمولاً در اثر پیوند به تاریخچهٔ بهروز نشدهٔ صفحهٔ حذف شده است.
+میتوانید جزئیات بیشتر را در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] بیابید.',
# Search results
'searchresults' => 'نتایج جستجو',
'shared-repo-from' => 'از $1',
'shared-repo' => 'یک مخزن مشترک',
'shared-repo-name-wikimediacommons' => 'ویکیانبار',
+'upload-disallowed-here' => 'متاسفانه شما نمی توانید این نگاره را بازنویس کنید.',
# File reversion
'filerevert' => 'واگردانی $1',
'disambiguations' => 'صفحههای دارای پیوند به صفحههای ابهامزدایی',
'disambiguationspage' => 'Template:ابهامزدایی',
-'disambiguations-text' => "صفحههای زیر پیوندی به یک '''صفحهٔ ابهامزدایی''' هستند.
-اÛ\8cÙ\86 صÙ\81ØÙ\87â\80\8cÙ\87ا باید در عوض به موضوعات مرتبط پیوند داده شوند.<br />
+'disambiguations-text' => "صفحههای زیر حاوی حداقل یک پیوند به یک '''صفحهٔ ابهامزدایی''' هستند.
+اÛ\8cÙ\86 صÙ\81ØÙ\87â\80\8cÙ\87ا Ø´اید در عوض به موضوعات مرتبط پیوند داده شوند.<br />
یک صفحه هنگامی صفحهٔ ابهامزدایی در نظر گرفته میشود که در آن از الگویی که به [[MediaWiki:Disambiguationspage]] پیوند دارد استفاده شده باشد.",
'doubleredirects' => 'تغییرمسیرهای دوتایی',
# Miscellaneous special pages
'nbytes' => '$1 {{PLURAL:$1|بایت|بایت}}',
'ncategories' => '$1 {{PLURAL:$1|رده|رده}}',
+'ninterwikis' => '$1 {{PLURAL:$1|میانویکی|میانویکی}}',
'nlinks' => '$1 {{PLURAL:$1|پیوند|پیوند}}',
'nmembers' => '$1 {{PLURAL:$1|عضو|عضو}}',
'nrevisions' => '$1 {{PLURAL:$1|نسخه|نسخه}}',
'mostlinkedtemplates' => 'الگوهایی که بیشتر از همه به آنها پیوند داده شدهاست',
'mostcategories' => 'صفحههای دارای بیشترین رده',
'mostimages' => 'پروندههایی که بیشتر از همه به آنها پیوند داده شدهاست',
+'mostinterwikis' => 'صفحههای دارای بیشترین میانویکی',
'mostrevisions' => 'صفحههای دارای بیشترین نسخه',
'prefixindex' => 'تمام صفحهها با پیشوند',
'prefixindex-namespace' => 'همهٔ صفحههای دارای پیشوند (فضاینام $1)',
'mailnologin' => 'نشانیای از فرستنده موجود نیست',
'mailnologintext' => 'برای فرستادن رایانامه به کاربران دیگر باید [[Special:UserLogin|به سامانه وارد شوید]] و نشانی رایانامهٔ معتبری در [[Special:Preferences|ترجیحات]] خود داشته باشید.',
'emailuser' => 'فرستادن نامه به این کاربر',
+'emailuser-title-target' => 'ایمیل این {{GENDER:$1| کاربر}}',
+'emailuser-title-notarget' => 'رایانامه به کاربر',
'emailpage' => 'رایانامه به کاربر',
'emailpagetext' => 'شما میتوانید از فرم زیر برای ارسال یک رایانامه به این کاربر استفاده کنید.
نشانی رایانامهای که در [[Special:Preferences|ترجیحات کاربریتان]] وارد کردهاید در نشانی فرستنده (From) نامه خواهد آمد، تا گیرنده بتواند پاسخ دهد.',
'import-interwiki-templates' => 'تمام الگوها را شامل شود',
'import-interwiki-submit' => 'درونریزی شود',
'import-interwiki-namespace' => 'فضای نام مقصد:',
+'import-interwiki-rootpage' => 'مقصد صفحه ٔ مبنا (اختیاری):',
'import-upload-filename' => 'نام پرونده:',
'import-comment' => 'توضیح:',
'importtext' => 'لطفاً پرونده را از ویکی منبع با کمک [[Special:Export|ابزار برونبری]] دریافت کنید.
'import-error-interwiki' => 'صفحه «$1» وارد نشد. چون نام آن برای پیوند خارجی (interwiki) رزرو شدهاست.',
'import-error-special' => 'صفحه «$1» درونریزی نشد، چرا که متعلق به فضای نام غیرمجاز است.',
'import-error-invalid' => 'صفحه "$1" به دلیل نامعتبر بودن نامش وارد نمیشود.',
+'import-options-wrong' => '{{PLURAL:$2|جزئیات|جزئیات}} اشتباه: <nowiki>$1</nowiki>',
+'import-rootpage-invalid' => 'با توجه به ریشه صفحه عنوان نامعتبر است.',
+'import-rootpage-nosubpage' => 'فضای نام "$1" صفحهٔ مبنا اجازهٔ زیرصفحه نمیدهد.',
# Import log
'importlogpage' => 'سیاههٔ درونریزیها',
# Info page
'pageinfo-title' => 'اطلاعات در مورد «$1»',
-'pageinfo-header-edits' => 'ویرایش',
+'pageinfo-header-basic' => 'اطلاعات اولیه',
+'pageinfo-header-edits' => 'ویرایش تاریخچه',
+'pageinfo-header-restrictions' => 'حفاظت از صفحه',
+'pageinfo-header-properties' => 'ويژگيهای صفحه',
+'pageinfo-display-title' => 'نمایش عنوان',
+'pageinfo-default-sort' => 'کلید مرتبسازی پیشفرض',
+'pageinfo-length' => 'حجم صفحه (بایت)',
+'pageinfo-article-id' => 'شناسهٔ صفحه',
+'pageinfo-robot-policy' => 'وضعیت موتور جستجو',
+'pageinfo-robot-index' => 'فهرستپذیر',
+'pageinfo-robot-noindex' => 'عدم فهرستپذیری',
'pageinfo-views' => 'شمار بازدیدها',
-'pageinfo-watchers' => 'شمار پیگیریکنندگان',
-'pageinfo-edits' => 'شمار ویرایشها',
-'pageinfo-authors' => 'شمار نویسندگان یکتا',
+'pageinfo-watchers' => 'شمار پیگیریکنندگان صفحه',
+'pageinfo-redirects-name' => 'تغییرمسیرها به این صفحه',
+'pageinfo-subpages-name' => 'زیرصفحههای این صفحه',
+'pageinfo-subpages-value' => '$1 ($2 {{PLURAL:$2|تغییرمسیر|تغییرمسیر}}; $3 {{PLURAL:$3|غیرتغییرمسیر|غیرتغییرمسیر}})',
+'pageinfo-firstuser' => 'بهوجود آورندهٔ صفحه',
+'pageinfo-firsttime' => 'زمان ایجاد صفحه',
+'pageinfo-lastuser' => 'آخرین ویرایشگر',
+'pageinfo-lasttime' => 'تاریخ آخرین ویرایش',
+'pageinfo-edits' => 'شمار کلی ویرایشها',
+'pageinfo-authors' => 'تعداد کلی نویسندگان یکتا',
+'pageinfo-recent-edits' => 'شماره ویرایشهای اخیر (در $1 گذشته)',
+'pageinfo-recent-authors' => 'تعداد نویسندگان یکتای اخیر',
+'pageinfo-restriction' => 'محافظت صفحه ( <code>{{lcfirst:$1}}</code> )',
+'pageinfo-magic-words' => '{{PLURAL:$1|حرف|حروف}} جادویی ($1)',
+'pageinfo-hidden-categories' => '{{PLURAL:$1| ردهٔ|ردهٔ}} پنهان ( $1 )',
+'pageinfo-templates' => '{{PLURAL:$1|الگو|الگو}} استفادهشده ($1)',
# Skin names
'skinname-standard' => 'کلاسیک',
'file-info-size-pages' => '<span style="direction:ltr">$1 × $2</span> نقطه، حجم پرونده: $3، نوع MIME پرونده: $4، $5 صفحه',
'file-nohires' => 'تفکیکپذیری بالاتری در دسترس نیست.',
'svg-long-desc' => 'پروندهٔ اسویجی، با ابعاد <span dir="ltr">$1 × $2</span> پیکسل، اندازهٔ پرونده: $3',
+'svg-long-desc-animated' => 'پروندهٔ اسویجی متحرک، با ابعاد <span dir="ltr">$1 × $2</span> پیکسل، اندازهٔ پرونده: $3',
'show-big-image' => 'تصویر با تفکیکپذیری بالاتر',
'show-big-image-preview' => 'اندازهٔ این پیشنمایش: $1.',
'show-big-image-other' => '{{PLURAL:$2|کیفیت|کیفیتهای}} دیگر: $1.',
'file-info-png-looped' => 'چرخشدار',
'file-info-png-repeat' => '$1 {{PLURAL:$1|بار|بار}} پخش شد',
'file-info-png-frames' => '$1 {{PLURAL:$1|قاب|قاب}}',
+'file-no-thumb-animation' => "'''توجه: به علت مسائل فنی پیشنمایش پرونده به صورت متحرک نمایش داده نمیشود.'''",
+'file-no-thumb-animation-gif' => "'''توجه:به علت مسائل فنی پیشنمایش پروندههای GIF مانند این پرونده، به صورت متحرک نمایش داده نمیشود.'''",
# Special:NewFiles
'newimages' => 'نگارخانهٔ پروندههای جدید',
'youhavenewmessages' => 'თქვენ გაქვთ $1 ($2).',
'newmessageslink' => 'ახალი შეტყობინებები',
'newmessagesdifflink' => 'განსხვავება წინა ვერსიასთან',
+'youhavenewmessagesfromusers' => 'თქვენ გაქვთ $1 {{PLURAL:$3|სხვა მომხმარებლისგან|$3 მომხმარებლებისგან}} ($2).',
+'youhavenewmessagesmanyusers' => 'თქვენ გაქვთ $1 ბევრი მომხმარებლისგან ($2).',
'newmessageslinkplural' => '{{PLURAL:$1|ახალი შეტყობინება|ახალი შეტყობინება}}',
'newmessagesdifflinkplural' => 'ბოლო {{PLURAL:$1|ცვლილება|ცვლილება}}',
'youhavenewmessagesmulti' => 'თქვენ გაქვთ ახალი შეტყობინება $1-ზე',
'rollback' => 'რცვლილებების გაუქმება',
'rollback_short' => 'სწრაფი გაუქმება',
'rollbacklink' => 'სწრაფი გაუქმება',
-'rollbacklinkcount' => '$1 {{PLURAL:$1|á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\98á\83¡|á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\98á\83¡}} á\83\93á\83\90á\83\91á\83 á\83£á\83\9cება',
-'rollbacklinkcount-morethan' => '$1-á\83\96á\83\94 á\83\9bá\83\94á\83¢á\83\98 {{PLURAL:$1|á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\98á\83¡|á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\98á\83¡}} á\83\93á\83\90á\83\91á\83 á\83£á\83\9cება',
+'rollbacklinkcount' => '$1 {{PLURAL:$1|á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\98á\83¡|á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\98á\83¡}} á\83\92á\83\90á\83£á\83¥á\83\9bება',
+'rollbacklinkcount-morethan' => '$1-á\83\96á\83\94 á\83\9bá\83\94á\83¢á\83\98 {{PLURAL:$1|á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\98á\83¡|á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\98á\83¡}} á\83\92á\83\90á\83£á\83¥á\83\9bება',
'rollbackfailed' => 'შეცდომა გაუქმებისას',
'cantrollback' => 'შეუძლებელია უწინდელი რედაქციის აღდგენა; ის, ვინც უკანასკნელი ცვლილებები შეიტანა, ამ სტატიის ერთადერთი ავტორია.',
'alreadyrolled' => 'შეუძლებელია ბოლო ცვლილების გაუქმება [[:$1]], გაკეებული [[User:$2|$2]] ([[User talk:$2|განხილვა]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);
'ipb_expiry_invalid' => 'მოქმედების მიუღებელი პერიოდი',
'ipb_expiry_temp' => 'ბლოკირება მომხმარებლის სახელის დამალვით უვადო უნდა იყოს',
'ipb_hide_invalid' => 'შეუძლებელია მოხემული ანგარიშის დამალვა, სავარაუდოდ მის მიერ განხორციელებულია ძალიან ბევრი შესწორება',
-'ipb_already_blocked' => '"$1" უკვე ბლოკირებულია',
+'ipb_already_blocked' => '„$1“ უკვე ბლოკირებულია',
'ipb-needreblock' => 'მომხმარებელი $1 უკვე დაიბლოკა. გსურთ დაბლოკვის პარამეტრების შესწორება?',
'ipb-otherblocks-header' => 'სხვა {{PLURAL:$1|დაბლოკვა|დაბლოკვები}}',
'unblock-hideuser' => 'თქვენ არ შეგიძლიათ მოხსნათ ბლოკი ამ მომხმარებელს, რადგან მისი მომხმარებლის სახელი დამალულია.',
'delete_and_move' => 'წაშლა და გადატანა',
'delete_and_move_text' => '==საჭიროა წაშლა==
-სტატია დასახელებით "[[:$1]]" უკვე არსებობს. გსურთ მისი წაშლა გადატანისთვის ადგილის დასათმობად?',
+სტატია დასახელებით „[[:$1]]“ უკვე არსებობს. გსურთ მისი წაშლა გადატანისთვის ადგილის დასათმობად?',
'delete_and_move_confirm' => 'დიახ, წაშალეთ ეს გვერდი',
-'delete_and_move_reason' => 'წაშლილია "[[$1]]"-á\83\93á\83\90á\83\9c á\83\92á\83\90á\83\93á\83\90á\83¢á\83\90á\83\9cá\83\98á\83¡á\83\97á\83\95á\83\98á\83¡ á\83\90á\83\93á\83\92á\83\98á\83\9aá\83\98á\83¡ á\83\93á\83\90á\83¡á\83\90á\83\97á\83\9bá\83\9dá\83\91á\83\90á\83\93',
+'delete_and_move_reason' => 'წაშლილია â\80\9e[[$1]]-á\83\93á\83\90á\83\9câ\80\9c á\83\92á\83\90á\83\93á\83\90á\83¢á\83\90á\83\9cá\83\98á\83¡á\83\97á\83\95á\83\98á\83¡ á\83\90á\83\93á\83\92á\83\98á\83\9aá\83\98á\83¡ á\83\93á\83\90á\83¡á\83\90á\83\97á\83\9bá\83\9dá\83\91á\83\90á\83\93',
'selfmove' => 'წყარო და დანიშნულების სათაურები მსგავსია; შეუძლებელია გვერდის საკუთარ თავზე გადატანა.',
-'immobile-source-namespace' => 'შეუძლებელია სახელის გადარქმევა «$1» სახელთა სივრცეში',
-'immobile-target-namespace' => 'შეუძლებელია გვერდის გადატანა «$1» სახელთა სივრცეში',
+'immobile-source-namespace' => 'შეუძლებელია სახელის გადარქმევა „$1“ სახელთა სივრცეში',
+'immobile-target-namespace' => 'შეუძლებელია გვერდის გადატანა „$1“ სახელთა სივრცეში',
'immobile-target-namespace-iw' => 'ინტერვიკის ბმული შეუძლებელია გამოყენებული იქნას გადარქმევისთვის.',
'immobile-source-page' => 'ამ გვეერდის გადატანა შეუძლებელია.',
'immobile-target-page' => 'შეუძლებელია მოცემულ სახელზე გადატანა.',
'import-upload' => 'XML მონაცემების ატვირთვა',
'import-token-mismatch' => 'სეანსის მონაცემები დაიკარგა. კიდევ ერთხელ სცადეთ!',
'import-invalid-interwiki' => 'შეუძლებელია იმპორტირება მოცემული ვიკიდან.',
-'import-error-edit' => 'გვერდი "$1" იმპორტირება არ მოხდა, რადგან თქვენ არ გაქვთ მისი რედაქტირების უფლება.',
-'import-error-create' => 'გვერდი "$1" იმპორტირება არ მოხდა, რადგან თქვენ არ გაქვთ მისი შექმნის უფლება.',
-'import-error-interwiki' => 'გვერდი "$1" არ იქნა იმპორტირებული, რადგანაც მისი სახელი დარეგისტრირებულია გარე ბმულებისათვის (interwiki).',
-'import-error-special' => 'გვერდი "$1" არ იქნა იმპორტირებული, რადგანაც ის განეკუთვნება განსაკუთრებულ სახელთა სივრცეს, რომელიც კრძალავს გვერდების შექმნას.',
+'import-error-edit' => 'გვერდი „$1“ იმპორტირება არ მოხდა, რადგან თქვენ არ გაქვთ მისი რედაქტირების უფლება.',
+'import-error-create' => 'გვერდი „$1“ იმპორტირება არ მოხდა, რადგან თქვენ არ გაქვთ მისი შექმნის უფლება.',
+'import-error-interwiki' => 'გვერდი „$1“ არ იქნა იმპორტირებული, რადგანაც მისი სახელი დარეგისტრირებულია გარე ბმულებისათვის (interwiki).',
+'import-error-special' => 'გვერდი „$1“ არ იქნა იმპორტირებული, რადგანაც ის განეკუთვნება განსაკუთრებულ სახელთა სივრცეს, რომელიც კრძალავს გვერდების შექმნას.',
'import-error-invalid' => 'გვერდი "$1" იმპორტირება არ მოხდა მიუღებელი სახელის გამო.',
'import-options-wrong' => 'არასწორი {{PLURAL:$2|პარამეტრი|პარამეტრი}}: <nowiki>$1</nowiki>',
'import-rootpage-invalid' => 'ძირეული გვერდის მითითებული სახელი არასწორია.',
# Import log
'importlogpage' => 'იმპორტის ჟურნალი',
'importlogpagetext' => 'ადმინისტრატორთა მიერ გვერდების იმპორტირება ცვლილებების ჩათვლით სხვა ვიკიდან.',
-'import-logentry-upload' => '«[[$1]]» — ფაილის იმპორტი',
+'import-logentry-upload' => '„[[$1]]“ — ფაილის იმპორტი',
'import-logentry-upload-detail' => '$1 ცვლილება',
-'import-logentry-interwiki' => '«$1» — ტრანსვიკი იმპორტი',
+'import-logentry-interwiki' => '„$1“ — ტრანსვიკი იმპორტი',
'import-logentry-interwiki-detail' => '$1 ცვლილება $2-დან',
# JavaScriptTest
'javascripttest-disabled' => 'ეს ფუნქცია ამ ვიკიში არ ჩართულა.',
'javascripttest-title' => 'მიმდინარეობს $1-ის ტესტირება',
'javascripttest-pagetext-noframework' => 'ეს გვერდი დარეგისტრირებულია JavaScript-ის ტესტების გასაშვებად.',
-'javascripttest-pagetext-unknownframework' => '"$1"-ის ტესტირების უცნობი გარემო.',
+'javascripttest-pagetext-unknownframework' => '„$1-ის“ ტესტირების უცნობი გარემო.',
'javascripttest-pagetext-frameworks' => 'გთხოვთ, აირჩიეთ ტესტირების ერთ-ერთი შემდეგი გარემო: $1',
'javascripttest-pagetext-skins' => 'ტესტების გასაშვებად აირჩიეთ გაფორმების თემა:',
'javascripttest-qunit-intro' => 'იხილეთ [$1 ტესტირების დოკუმენტები] mediawiki.org-ზე.',
'revdelete-uname-unhid' => 'მომხმარებლის სახელი გახსნილია',
'revdelete-restricted' => 'შეზღუდვა ადმინისტრატორთათვის',
'revdelete-unrestricted' => 'ადმინისტრატორთათვის შეზღუდვები მოხსნილია',
-'logentry-move-move' => '$1 á\83\92á\83\90á\83\93á\83\90á\83\98á\83¢á\83\90á\83\9cá\83\90 á\83\92á\83\95á\83\94á\83 á\83\93á\83\98 $3 â\86\92 $4-á\83\96á\83\94',
-'logentry-move-move-noredirect' => '$1 á\83\92á\83\90á\83\93á\83\90á\83\98á\83¢á\83\90á\83\9cá\83\90 á\83\92á\83\95á\83\94á\83 á\83\93á\83\98 $3 $4-á\83¨á\83\98 გადამისამართების დატოვების გარეშე',
-'logentry-move-move_redir' => '$1 á\83\92á\83\90á\83\93á\83\90á\83\98á\83¢á\83\90á\83\9cá\83\90 á\83\92á\83\95á\83\94á\83 á\83\93á\83\98 $3 $4-á\83¨á\83\98 გადამისამართებაზე',
+'logentry-move-move' => '$1 á\83\92á\83\95á\83\94á\83 á\83\93á\83\98 â\80\9e$3â\80\9c á\83\92á\83\90á\83\93á\83\90á\83\98á\83¢á\83\90á\83\9cá\83\90 á\83\92á\83\95á\83\94á\83 á\83\93á\83\96á\83\94 â\80\9e$4â\80\9c',
+'logentry-move-move-noredirect' => '$1 á\83\92á\83\95á\83\94á\83 á\83\93á\83\98 â\80\9e$3â\80\9c á\83\92á\83\90á\83\93á\83\90á\83\98á\83¢á\83\90á\83\9cá\83\90 á\83\92á\83\95á\83\94á\83 á\83\93á\83\96á\83\94 â\80\9e$4â\80\9c გადამისამართების დატოვების გარეშე',
+'logentry-move-move_redir' => '$1 á\83\92á\83\95á\83\94á\83 á\83\93á\83\98 â\80\9e$3â\80\9c á\83\92á\83\90á\83\93á\83\90á\83\98á\83¢á\83\90á\83\9cá\83\90 á\83\92á\83\95á\83\94á\83 á\83\93á\83\96á\83\94 â\80\9e$4â\80\9c გადამისამართებაზე',
'logentry-move-move_redir-noredirect' => '$1 გადაიტანა გვერდი $3 $4-ში გადამისამართების დატოვების გარეშე',
-'logentry-patrol-patrol' => '$1 გააკეთა გვერდი $3-ის $4 ვერსიის პატრულირება',
-'logentry-patrol-patrol-auto' => '$1 ავტომატურად გააკეთა გვერდი $3-ის $4 ვერსიის პატრულირება',
+'logentry-patrol-patrol' => '$1 გააკეთა გვერდის „$3“ $4 ვერსიის პატრულირება',
+'logentry-patrol-patrol-auto' => '$1 ავტომატურად გააკეთა გვერდის „$3“ $4 ვერსიის პატრულირება',
'logentry-newusers-newusers' => '$1 შექმნა მომხმარებლის ანგარიში',
'logentry-newusers-create' => '$1 შექმნა მომხმარებლის ანგარიში',
'logentry-newusers-create2' => '$1 შექმნა მომხმარებელ $3 ანგარიში',
'youhavenewmessages' => 'Habes $1 ($2).',
'newmessageslink' => 'nuntia nova',
'newmessagesdifflink' => 'dissimilia post mutationem ultimam',
+'youhavenewmessagesfromusers' => 'Habes $1 ab {{PLURAL:$3|uno usore alio|usoribus $3}} ($2).',
+'youhavenewmessagesmanyusers' => 'Habes $1 a multis usoribus ($2).',
+'newmessageslinkplural' => '{{PLURAL:$1|nuntium novum|nuntia nova}}',
+'newmessagesdifflinkplural' => 'dissimilitudo post mutationem ultimam',
'youhavenewmessagesmulti' => 'Habes nuntia nova in $1',
'editsection' => 'recensere',
'editold' => 'recensere',
'uploadnewversion-linktext' => 'Last opp en ny versjon av denne filen',
'shared-repo-from' => 'fra $1',
'shared-repo' => 'et delt fillager',
+'upload-disallowed-here' => 'Beklageligvis kan du ikke overskrive dette bildet.',
# File reversion
'filerevert' => 'Tilbakestill $1',
'pageinfo-authors' => 'Totalt antall forskjellige forfattere',
'pageinfo-recent-edits' => 'Antall nylige redigeringer (innen siste $1)',
'pageinfo-recent-authors' => 'Antall nylige forfattere',
-'pageinfo-restriction' => 'Sidebeskyttelse (<code>$1</code>)',
+'pageinfo-restriction' => 'Sidebeskyttelse (<code>{{lcfirst:$1}}</code>)',
'pageinfo-magic-words' => '{{PLURAL:$1|Magisk|Magiske}} ord ($1)',
'pageinfo-hidden-categories' => '{{PLURAL:$1|Skjult kategori|Skjulte kategorier}} ($1)',
'pageinfo-templates' => 'Transkludert {{PLURAL:$1|mal|maler}} ($1)',
'file-info-size' => '$1 × $2 piksler, filstørrelse: $3, MIME-type: $4',
'file-info-size-pages' => '$1 × $2 piksler, filstørrelse: $3, MIME-type: $4, $5 {{PLURAL:$5|side|sider}}',
'file-nohires' => 'Ingen høyere oppløsning tilgjengelig.',
-'svg-long-desc' => 'SVG-fil, standardoppløsning $1 × $2 piksler, filstørrelse: $3',
+'svg-long-desc' => 'SVG-fil, standardstørrelse $1 × $2 piksler, filstørrelse: $3',
+'svg-long-desc-animated' => 'Animert SVG-fil, standardstørrelse $1 × $2 piksler, filstørrelse: $3',
'show-big-image' => 'Full oppløsning',
'show-big-image-preview' => 'Størrelse på denne forhåndsvisningen: $1.',
'show-big-image-other' => '{{PLURAL:$2|Annen oppløsning|Andre oppløsninger}}: $1.',
'file-info-png-looped' => 'loopet',
'file-info-png-repeat' => 'avspilt $1 {{PLURAL:$1|gang|ganger}}',
'file-info-png-frames' => '$1 {{PLURAL:$1|bilde|bilder}}',
+'file-no-thumb-animation' => "'''Merk: På grunn av tekniske begrensninger vil ikke miniatyrbilder av denne filen bli animert.'''",
+'file-no-thumb-animation-gif' => "'''Merk: På grunn av tekniske begrensninger vil ikke miniatyrbilder av høyoppløselige GIF-bilder, slik som denne, bli animert.'''",
# Special:NewFiles
'newimages' => 'Galleri over nye filer',
'ipblocklist-empty' => 'De blokkeerlijst is leeg.',
'ipblocklist-no-results' => 'Dit IP-adres of deze gebruikersnaam is niet geblokkeerd.',
'blocklink' => 'blokkeren',
-'unblocklink' => 'deblokkeren',
+'unblocklink' => 'blokkade opheffen',
'change-blocklink' => 'blokkade wijzigen',
'contribslink' => 'bijdragen',
'emaillink' => 'e-mail verzenden',
'prefs-beta' => 'ଆଗ ବିଶେଷତାମାନ',
'prefs-datetime' => 'ତାରିଖ ଓ ସମୟ',
'prefs-labs' => 'ପରଖଶାଳା ସୁବିଧାସବୁ',
+'prefs-user-pages' => 'ବ୍ୟବହାରକାରୀଙ୍କର ପୃଷ୍ଠାଗୁଡିକ',
'prefs-personal' => 'ସଭ୍ୟ ପ୍ରଫାଇଲ',
'prefs-rc' => 'ନଗଦ ବଦଳ',
'prefs-watchlist' => 'ଦେଖଣା ତାଲିକା',
'allpagesbadtitle' => 'ଆପଣ ଅନୁରୋଧ କରିଥିବା ପୃଷ୍ଠାଟି ଭୁଲ, ଅଲଗା ଭାଷାର ବ୍ୟବହାର କରାଯାଇଛି ବା ଭୁଲ ଇଣ୍ଟର ଉଇକି ଉପସର୍ଗ ଦିଆଯାଇଛି ।
ଏଥିରେ ଥିବା ଗୋଟିଏ ବା ଦୁଇଟି ଅକ୍ଷର ଶିରୋନାମା ଭାବରେ ବ୍ୟବହାର କରାଯାଇ ପାରିବ ନାହିଁ ।',
'allpages-bad-ns' => '{{SITENAME}}ରେ "$1" ନେମସ୍ପେସଟିଏ ନାହିଁ ।',
+'allpages-hide-redirects' => 'ପୁନଃପ୍ରେରଣସମୂହକୁ ଲୁଚାଇବେ',
# SpecialCachedPage
'cachedspecial-refresh-now' => 'ନୂତନତମ ଦେଖନ୍ତୁ ।',
'mailnologin' => 'ଗୋଟିଏ ବି ପଠାଇବା ଠିକଣା ନାହିଁ',
'mailnologintext' => 'ଆପଣ ନିଜ [[Special:Preferences|ପସନ୍ଦସବୁ]]ରେ [[Special:UserLogin|ଲଗ ଇନ]] କରିଥିଲେ ଓ ନିଜର ଏକ ସଚଳ ଇ-ମେଲ ଠିକଣା ଥିଲେ ଯାଇ ବାକି ସବୁ ସଭ୍ୟଙ୍କୁ ଇ-ମେଲ ପଠାଇପାରିବେ ।',
'emailuser' => 'ଏହି ସଭ୍ୟଙ୍କୁ ଇମେଲ କରିବେ',
+'emailuser-title-notarget' => 'ବ୍ୟବହାରକାରୀ କୁ ଇ-ମେଲ',
'emailpage' => 'ଇ-ମେଲ ବ୍ୟବହାରକାରୀ',
'emailpagetext' => 'ତଳେ ଥିବା ଫର୍ମ ବ୍ୟବହାର କରି ଆପଣ ଏହି ସଭ୍ୟଙ୍କୁ ଇ-ମେଲ କରିପାରିବେ ।
[[Special:Preferences|ଆପଣଙ୍କ ପସନ୍ଦ]]ରେ ଥିବା ଇ-ମେଲ ଠିକଣା ପ୍ରେରକ ଭାବରେ ଦେଖାଯିବ, ତେଣୁ ଚିଠି ପାଇଥିବା ସଭ୍ୟ ଆପଣଙ୍କୁ ସିଧା ସଳଖ ଉତ୍ତର ଦେଇପାରିବ ।',
# Info page
'pageinfo-title' => '"$1"ର ବିବରଣୀ',
'pageinfo-header-edits' => 'ବଦଳସବୁ',
+'pageinfo-article-id' => 'ପୃଷ୍ଠା ଆଇଡ଼ି',
'pageinfo-views' => 'ଦେଖଣା ସଂଖ୍ୟା',
'pageinfo-watchers' => 'ଦେଖଣାହାରି ସଂଖ୍ୟା',
'pageinfo-edits' => 'ସମ୍ପାଦନା ସଂଖ୍ୟା:',
'tooltip-ca-nstab-media' => 'Vardé la pàgina dël mojen',
'tooltip-ca-nstab-special' => "Costa a l'é na pàgina special, a peul nen modifichela.",
'tooltip-ca-nstab-project' => 'Vardé la pàgina proteta.',
-'tooltip-ca-nstab-image' => 'Vardé la pàgina dl',
-'tooltip-ca-nstab-mediawiki' => 'Vardé ël messagi ëd sistema.',
+'tooltip-ca-nstab-image' => "Vardé la pàgina dl'archivi",
+'tooltip-ca-nstab-mediawiki' => 'Vardé ël mëssagi ëd sistema.',
'tooltip-ca-nstab-template' => 'Vardé lë stamp.',
'tooltip-ca-nstab-help' => 'Vardé la pàgina d',
'tooltip-ca-nstab-category' => 'Vardé la pàgina dla categorìa.',
'editundo' => 'gör ogjord',
'diff-multi' => '({{PLURAL:$1|En mellanliggande version|$1 mellanliggande versioner}} av {{PLURAL:$2|en användare|$2 användare}} visas inte)',
'diff-multi-manyusers' => '({{PLURAL:$1|En mellanliggande version|$1 mellanliggande versioner}} av mer än $2 användare visas inte)',
+'difference-missing-revision' => '{{PLURAL:$2|En revision|$2 revisioner}} av denna skillnad ($1) kunde inte hittas.
+
+Detta orsakas vanligtvis av att följa en utgången difflänk till en sida som har raderats.
+Detaljer kan hittas i [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} raderingsloggen].',
# Search results
'searchresults' => 'Sökresultat',
'disambiguations' => 'Sidor som länkar till förgreningssidor',
'disambiguationspage' => 'Template:Förgrening',
-'disambiguations-text' => "Följande sidor länkar till ''förgreningssidor''.
-Länkarna bör troligtvis ändras så att de länkar till en artikel istället.<br />
+'disambiguations-text' => "Följande sidorna innehåller minst en länk till en '''förgreningssida'''.
+De bör troligtvis ändras så att de länkar till en mer passande sida istället.<br />
En sida anses vara en förgreningssida om den inkluderar en mall som länkas till från [[MediaWiki:Disambiguationspage]].",
'doubleredirects' => 'Dubbla omdirigeringar',
'import-interwiki-templates' => 'Inkludera alla mallar',
'import-interwiki-submit' => 'Importera',
'import-interwiki-namespace' => 'Målnamnrymd:',
+'import-interwiki-rootpage' => 'Destinationens grundsida (valfri):',
'import-upload-filename' => 'Filnamn:',
'import-comment' => 'Kommentar:',
'importtext' => 'Var god exportera filen från ursprungs-wikin med hjälp av [[Special:Export|exporteringsverktyget]].
'import-error-special' => 'Sidan "$1" är inte importerad eftersom den tillhör en särskild namnrymd som inte tillåter sidor.',
'import-error-invalid' => 'Sidan "$1" är inte importerad eftersom dess namn är ogiltigt.',
'import-options-wrong' => 'Fel {{PLURAL:$2|alternativ|alternativ}}: <nowiki>$1</nowiki>',
+'import-rootpage-invalid' => 'Angiven grundsida är en ogiltig titel.',
'import-rootpage-nosubpage' => 'Namnrymden "$1" till grundsidan tillåter inte undersidor.',
# Import log
'pageinfo-length' => 'Sidlängd (i byte)',
'pageinfo-article-id' => 'Sid-ID',
'pageinfo-robot-policy' => 'Sökmotorns status',
+'pageinfo-robot-index' => 'Indexerbar',
+'pageinfo-robot-noindex' => 'Inte indexerbar',
'pageinfo-views' => 'Antal visningar',
'pageinfo-watchers' => 'Antal användare som bevakar sidan',
'pageinfo-redirects-name' => 'Omdirigeringar till denna sida',
'pageinfo-subpages-name' => 'Undersidor till denna sida',
'pageinfo-subpages-value' => '$1 ($2 {{PLURAL:$2|omdirigering|omdirigeringar}}; $3 {{PLURAL:$3|icke-omdirigering|icke-omdirigeringar}})',
+'pageinfo-firstuser' => 'Sidskapare',
+'pageinfo-firsttime' => 'Datum när sidan skapades',
+'pageinfo-lastuser' => 'Senaste redigeraren',
'pageinfo-lasttime' => 'Datum för senaste redigeringen',
'pageinfo-edits' => 'Totalt antal redigeringar',
'pageinfo-authors' => 'Totalt antal olika författare',
+'pageinfo-restriction' => 'Sidskydd (<code>{{lcfirst:$1}}</code>)',
'pageinfo-magic-words' => '{{PLURAL:$1|Magiskt|Magiska}} ord ($1)',
'pageinfo-hidden-categories' => '{{PLURAL:$1|Dold kategori|Dolda kategorier}} ($1)',
'file-info-png-looped' => 'upprepad',
'file-info-png-repeat' => 'spelad $1 {{PLURAL:$1|gång|gånger}}',
'file-info-png-frames' => '$1 {{PLURAL:$1|bild|bilder}}',
+'file-no-thumb-animation' => "'''OBS: På grund av tekniska begränsningar kommer inte miniatyrer av denna fil animeras.'''",
+'file-no-thumb-animation-gif' => "'''OBS: På grund av tekniska begränsningar kommer inte miniatyrer av GIF-bilder med hög upplösning som denna animeras.'''",
# Special:NewFiles
'newimages' => 'Galleri över nya filer',
'youhavenewmessages' => 'Ви отримали $1 ($2).',
'newmessageslink' => 'нові повідомлення',
'newmessagesdifflink' => 'остання зміна',
+'newmessageslinkplural' => '{{PLURAL:$1|нове повідомлення|нові повідомлення}}',
+'newmessagesdifflinkplural' => '{{PLURAL:$1|остання зміна|останні зміни}}',
'youhavenewmessagesmulti' => 'Ви отримали нові повідомлення на $1',
'editsection' => 'ред.',
'editsection-brackets' => '[$1]',
$dbw->update( 'user_groups',
array( 'ug_group' => $newGroup ),
array( 'ug_group' => $oldGroup,
- "ug_user BETWEEN $blockStart AND $blockEnd" )
+ "ug_user BETWEEN $blockStart AND $blockEnd" ),
+ __METHOD__,
+ array( 'IGNORE' )
+ );
+ $count += $dbw->affectedRows();
+ $dbw->delete( 'user_groups',
+ array( 'ug_group' => $oldGroup,
+ "ug_user BETWEEN $blockStart AND $blockEnd" ),
+ __METHOD__
);
$count += $dbw->affectedRows();
$dbw->commit( __METHOD__ );
min-width: 8px;
height: 14px;
border: 1px solid white;
- border-radius: 8px;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
- box-shadow: 0px 1px 4px #ccc;
+ border-radius: 8px;
-moz-box-shadow: 0px 1px 4px #ccc;
-webkit-box-shadow: 0px 1px 4px #ccc;
+ box-shadow: 0px 1px 4px #ccc;
background-color: #b60a00;
- background-image: linear-gradient(bottom, #a70802 0%, #cf0e00 100%);
background-image: -o-linear-gradient(bottom, #a70802 0%, #cf0e00 100%);
background-image: -moz-linear-gradient(bottom, #a70802 0%, #cf0e00 100%);
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #a70802), color-stop(1, #cf0e00));
background-image: -webkit-linear-gradient(bottom, #a70802 0%, #cf0e00 100%);
background-image: -ms-linear-gradient(bottom, #a70802 0%, #cf0e00 100%);
- background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #a70802), color-stop(1, #cf0e00));
+ background-image: linear-gradient(bottom, #a70802 0%, #cf0e00 100%);
padding: 0 3px;
text-align: center;
}
-// Badger v1.0 by Daniel Raftery
-// http://thrivingkings.com/badger
-// http://twitter.com/ThrivingKings
-// Modified by Ryan Kaldari <rkaldari@wikimedia.org>
+/**
+ * jQuery Badge plugin
+ *
+ * Based on Badger plugin by Daniel Raftery (http://thrivingkings.com/badger).
+ *
+ * @license MIT
+ */
/**
+ * @author Ryan Kaldari <rkaldari@wikimedia.org>, 2012
+ * @author Andrew Garrett <agarrett@wikimedia.org>, 2012
+ * @author Marius Hoch <hoo@online.de>, 2012
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
*
* This program is distributed WITHOUT ANY WARRANTY.
*/
+( function ( $ ) {
-(function( $ ) {
- $.fn.badge = function( badge, options ) {
- var existingBadge = this.find( '.mw-badge' );
- options = $.extend( {}, options );
+ /**
+ * Allows you to put a numeric "badge" on an item on the page.
+ * See mediawiki.org/wiki/ResourceLoader/Default_modules#jQuery.badge
+ *
+ * @param {string|number} badgeCount An explicit number, or "+n"/ "-n"
+ * to modify the existing value. If the new value is equal or lower than 0,
+ * any existing badge will be removed. The badge container will be appended
+ * to the selected element(s).
+ * @param {Object} options Optional parameters specified below
+ * type: 'inline' or 'overlay' (default)
+ * callback: will be called with the number now shown on the badge as a parameter
+ */
+ $.fn.badge = function ( badgeCount, options ) {
+ var $badge,
+ oldBadgeCount,
+ newBadgeCount,
+ $existingBadge = this.find( '.mw-badge' );
- badge = String(badge);
- if ( badge.charAt(0) === '+' ) {
- if ( existingBadge.length > 0 ) {
- oldBadge = existingBadge.text();
- badge = Math.round( Number( oldBadge ) + Number( badge.substr(1) ) );
- } else {
- badge = badge.substr(1);
- }
- } else if ( badge.charAt(0) === '-' ) {
- if ( existingBadge.length > 0 ) {
- oldBadge = existingBadge.text();
- badge = Math.round( Number( oldBadge ) - Number( badge.substr(1) ) );
+ options = $.extend( { type : 'overlay' }, options );
+
+ // If there is no existing badge, this will give an empty string
+ oldBadgeCount = Number( $existingBadge.text() );
+ if ( isNaN( oldBadgeCount ) ) {
+ oldBadgeCount = 0;
+ }
+
+ // If badgeCount is a number, use that as the new badge
+ if ( typeof badgeCount === 'number' ) {
+ newBadgeCount = badgeCount;
+ } else if ( typeof badgeCount === 'string' ) {
+ // If badgeCount is "+x", add x to the old badge
+ if ( badgeCount.charAt(0) === '+' ) {
+ newBadgeCount = oldBadgeCount + Number( badgeCount.substr(1) );
+ // If badgeCount is "-x", subtract x from the old badge
+ } else if ( badgeCount.charAt(0) === '-' ) {
+ newBadgeCount = oldBadgeCount - Number( badgeCount.substr(1) );
+ // If badgeCount can be converted into a number, convert it
+ } else if ( !isNaN( Number( badgeCount ) ) ) {
+ newBadgeCount = Number( badgeCount );
} else {
- badge = 0;
+ newBadgeCount = 0;
}
+ // Other types are not supported, fall back to 0.
+ } else {
+ newBadgeCount = 0;
}
- if ( Number(badge) <= 0 ) {
- // Clear any existing badge
- existingBadge.remove();
+ // Badge count must be a whole number
+ newBadgeCount = Math.round( newBadgeCount );
+
+ if ( newBadgeCount <= 0 ) {
+ // Badges should only exist for values > 0.
+ $existingBadge.remove();
} else {
// Don't add duplicates
- var $badge = existingBadge;
- if ( existingBadge.length > 0 ) {
- this.find( '.mw-badge-content' ).text( badge );
+ if ( $existingBadge.length ) {
+ $badge = $existingBadge;
+ // Insert the new count into the badge
+ this.find( '.mw-badge-content' ).text( newBadgeCount );
} else {
- $badge = $('<div/>')
- .addClass('mw-badge')
- .addClass('mw-badge-overlay')
+ // Contruct a new badge with the count
+ $badge = $( '<div>' )
+ .addClass( 'mw-badge' )
.append(
- $('<span/>')
- .addClass('mw-badge-content')
- .text(badge)
+ $( '<span>' )
+ .addClass( 'mw-badge-content' )
+ .text( newBadgeCount )
);
- this.append($badge);
+ this.append( $badge );
}
- if ( options.type ) {
- if ( options.type == 'inline' ) {
- $badge.removeClass('mw-badge-overlay')
- .addClass('mw-badge-inline');
- } else if ( options.type == 'overlay' ) {
- $badge.removeClass('mw-badge-inline')
- .addClass('mw-badge-overlay');
- }
+ if ( options.type === 'inline' ) {
+ $badge
+ .removeClass( 'mw-badge-overlay' )
+ .addClass( 'mw-badge-inline' );
+ // Default: overlay
+ } else {
+ $badge
+ .removeClass( 'mw-badge-inline' )
+ .addClass( 'mw-badge-overlay' );
+
}
- // If a callback was specified, call it with the badge number
- if ( options.callback ) {
- options.callback( badge );
+ // If a callback was specified, call it with the badge count
+ if ( $.isFunction( options.callback ) ) {
+ options.callback( newBadgeCount );
}
}
};
-} ) ( jQuery );
+}( jQuery ) );
&& profile.name === 'safari'
&& profile.layoutVersion > 526 ) {
util.tooltipAccessKeyPrefix = 'ctrl-alt-';
-
+ // Firefox 14+ on Mac
+ } else if ( profile.platform === 'mac'
+ && profile.name === 'firefox'
+ && profile.versionNumber >= 14 ) {
+ util.tooltipAccessKeyPrefix = 'ctrl-option-';
// Safari/Konqueror on any platform, or any browser on Mac
// (but not Safari on Windows)
} else if ( !( profile.platform === 'win' && profile.name === 'safari' )
}
/* Fill $content var */
- if ( $( '#bodyContent' ).length ) {
- // Vector, Monobook, Chick etc.
- util.$content = $( '#bodyContent' );
-
- } else if ( $( '#mw_contentholder' ).length ) {
- // Modern
- util.$content = $( '#mw_contentholder' );
-
- } else if ( $( '#article' ).length ) {
- // Standard, CologneBlue
- util.$content = $( '#article' );
+ util.$content = ( function () {
+ var $content, selectors = [
+ // The preferred standard for setting $content (class="mw-body")
+ // You may also use (class="mw-body mw-body-primary") if you use
+ // mw-body in multiple locations.
+ // Or class="mw-body-primary" if you want $content to be deeper
+ // in the dom than mw-body
+ '.mw-body-primary',
+ '.mw-body',
+
+ /* Legacy fallbacks for setting the content */
+ // Vector, Monobook, Chick, etc... based skins
+ '#bodyContent',
+
+ // Modern based skins
+ '#mw_contentholder',
+
+ // Standard, CologneBlue
+ '#article',
+
+ // #content is present on almost all if not all skins. Most skins (the above cases)
+ // have #content too, but as an outer wrapper instead of the article text container.
+ // The skins that don't have an outer wrapper do have #content for everything
+ // so it's a good fallback
+ '#content',
+
+ // If nothing better is found fall back to our bodytext div that is guaranteed to be here
+ '#mw-content-text',
+
+ // Should never happen... well, it could if someone is not finished writing a skin and has
+ // not inserted bodytext yet. But in any case <body> should always exist
+ 'body'
+ ];
+ for ( var i = 0, l = selectors.length; i < l; i++ ) {
+ $content = $( selectors[i] ).first();
+ if ( $content.length ) {
+ return $content;
+ }
+ }
- } else {
- // #content is present on almost all if not all skins. Most skins (the above cases)
- // have #content too, but as an outer wrapper instead of the article text container.
- // The skins that don't have an outer wrapper do have #content for everything
- // so it's a good fallback
- util.$content = $( '#content' );
- }
+ // Make sure we don't unset util.$content if it was preset and we don't find anything
+ return util.$content;
+ } )();
// Table of contents toggle
$tocTitle = $( '#toctitle' );
/*
* @var jQuery
- * A jQuery object that refers to the page-content element
+ * A jQuery object that refers to the content area element
* Populated by init().
*/
$content: null,
<!-- contentholder does nothing by default, but it allows users to style the text inside
the content area without affecting the meaning of 'em' in #mw_content, which is used
for the margins -->
- <div id="mw_contentholder">
+ <div id="mw_contentholder" class="mw-body">
<div class='mw-topboxes'>
<div id="mw-js-message" style="display:none;"<?php $this->html('userlangattributes')?>></div>
<div class="mw-topbox" id="siteSub"><?php $this->msg('tagline') ?></div>
$this->html( 'headelement' );
?><div id="globalWrapper">
-<div id="column-content"><div id="content">
+<div id="column-content"><div id="content" class="mw-body-primary">
<a id="top"></a>
<?php if($this->data['sitenotice']) { ?><div id="siteNotice"><?php $this->html('sitenotice') ?></div><?php } ?>
--- /dev/null
+<?php
+
+/**
+ * Tests timestamp parsing and output.
+ */
+class TimestampTest extends MediaWikiTestCase {
+ /**
+ * Test parsing of valid timestamps and outputing to MW format.
+ * @dataProvider provideValidTimestamps
+ */
+ function testValidParse( $format, $original, $expected ) {
+ $timestamp = new MWTimestamp( $original );
+ $this->assertEquals( $expected, $timestamp->getTimestamp( TS_MW ) );
+ }
+
+ /**
+ * Test outputting valid timestamps to different formats.
+ * @dataProvider provideValidTimestamps
+ */
+ function testValidOutput( $format, $expected, $original ) {
+ $timestamp = new MWTimestamp( $original );
+ $this->assertEquals( $expected, (string) $timestamp->getTimestamp( $format ) );
+ }
+
+ /**
+ * Test an invalid timestamp.
+ * @expectedException TimestampException
+ */
+ function testInvalidParse() {
+ $timestamp = new MWTimestamp( "This is not a timestamp." );
+ }
+
+ /**
+ * Test requesting an invalid output format.
+ * @expectedException TimestampException
+ */
+ function testInvalidOutput() {
+ $timestamp = new MWTimestamp( '1343761268' );
+ $timestamp->getTimestamp( 98 );
+ }
+
+ /**
+ * Test human readable timestamp format.
+ */
+ function testHumanOutput() {
+ $timestamp = new MWTimestamp( time() - 3600 );
+ $this->assertEquals( "1 hour ago", $timestamp->getHumanTimestamp()->toString() );
+ }
+
+ /**
+ * Returns a list of valid timestamps in the format:
+ * array( type, timestamp_of_type, timestamp_in_MW )
+ */
+ function provideValidTimestamps() {
+ return array(
+ // Various formats
+ array( TS_UNIX, '1343761268', '20120731190108' ),
+ array( TS_MW, '20120731190108', '20120731190108' ),
+ array( TS_DB, '2012-07-31 19:01:08', '20120731190108' ),
+ array( TS_ISO_8601, '2012-07-31T19:01:08Z', '20120731190108' ),
+ array( TS_ISO_8601_BASIC, '20120731T190108Z', '20120731190108' ),
+ array( TS_EXIF, '2012:07:31 19:01:08', '20120731190108' ),
+ array( TS_RFC2822, 'Tue, 31 Jul 2012 19:01:08 GMT', '20120731190108' ),
+ array( TS_ORACLE, '31-07-2012 19:01:08.000000', '20120731190108' ),
+ array( TS_POSTGRES, '2012-07-31 19:01:08 GMT', '20120731190108' ),
+ array( TS_DB2, '2012-07-31 19:01:08', '20120731190108' ),
+ // Some extremes and weird values
+ array( TS_ISO_8601, '9999-12-31T23:59:59Z', '99991231235959' ),
+ array( TS_UNIX, '-62135596801', '00001231235959' )
+ );
+ }
+}
$this->assertEquals( '2020:07:14 01:36:05', $meta['DateTimeDigitized'] );
$this->assertEquals( '1997:03:02 00:01:02', $meta['DateTimeOriginal'] );
}
- /* File has an invalid time (+ one valid but really weird time)
+ /**
+ * File has an invalid time (+ one valid but really weird time)
* that shouldn't be included
+ * @expectedException TimestampException
*/
public function testIPTCDatesInvalid() {
$meta = BitmapMetadataHandler::Jpeg( $this->filePath .