/**
* Includes language class files
*
- * @param $class Name of the language class
+ * @param $class string Name of the language class
*/
public static function preloadLanguageClass( $class ) {
global $IP;
}
global $wgExtraGenderNamespaces;
- $genders = $wgExtraGenderNamespaces + self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
+ $genders = $wgExtraGenderNamespaces + (array)self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
foreach ( $genders as $index => $forms ) {
foreach ( $forms as $alias ) {
$aliases[$alias] = $index;
* @return array
*/
function getExtraUserToggles() {
- return self::$dataCache->getItem( $this->mCode, 'extraUserToggles' );
+ return (array)self::$dataCache->getItem( $this->mCode, 'extraUserToggles' );
}
/**
return $this->getMessageFromDB( self::$mHijriCalendarMonthMsgs[$key - 1] );
}
- /**
- * Used by date() and time() to adjust the time output.
- *
- * @param $ts Int the time in date('YmdHis') format
- * @param $tz Mixed: adjust the time by this amount (default false, mean we
- * get user timecorrection setting)
- * @return int
- */
- function userAdjust( $ts, $tz = false ) {
- global $wgUser, $wgLocalTZoffset;
-
- if ( $tz === false ) {
- $tz = $wgUser->getOption( 'timecorrection' );
- }
-
- $data = explode( '|', $tz, 3 );
-
- if ( $data[0] == 'ZoneInfo' ) {
- wfSuppressWarnings();
- $userTZ = timezone_open( $data[2] );
- wfRestoreWarnings();
- if ( $userTZ !== false ) {
- $date = date_create( $ts, timezone_open( 'UTC' ) );
- date_timezone_set( $date, $userTZ );
- $date = date_format( $date, 'YmdHis' );
- return $date;
- }
- # Unrecognized timezone, default to 'Offset' with the stored offset.
- $data[0] = 'Offset';
- }
-
- $minDiff = 0;
- if ( $data[0] == 'System' || $tz == '' ) {
- # Global offset in minutes.
- if ( isset( $wgLocalTZoffset ) ) {
- $minDiff = $wgLocalTZoffset;
- }
- } elseif ( $data[0] == 'Offset' ) {
- $minDiff = intval( $data[1] );
- } else {
- $data = explode( ':', $tz );
- if ( count( $data ) == 2 ) {
- $data[0] = intval( $data[0] );
- $data[1] = intval( $data[1] );
- $minDiff = abs( $data[0] ) * 60 + $data[1];
- if ( $data[0] < 0 ) {
- $minDiff = -$minDiff;
- }
- } else {
- $minDiff = intval( $data[0] ) * 60;
- }
- }
-
- # No difference ? Return time unchanged
- if ( 0 == $minDiff ) {
- return $ts;
- }
-
- wfSuppressWarnings(); // E_STRICT system time bitching
- # Generate an adjusted date; take advantage of the fact that mktime
- # will normalize out-of-range values so we don't have to split $minDiff
- # into hours and minutes.
- $t = mktime( (
- (int)substr( $ts, 8, 2 ) ), # Hours
- (int)substr( $ts, 10, 2 ) + $minDiff, # Minutes
- (int)substr( $ts, 12, 2 ), # Seconds
- (int)substr( $ts, 4, 2 ), # Month
- (int)substr( $ts, 6, 2 ), # Day
- (int)substr( $ts, 0, 4 ) ); # Year
-
- $date = date( 'YmdHis', $t );
- wfRestoreWarnings();
-
- return $date;
- }
-
/**
* This is a workalike of PHP's date() function, but with better
* internationalisation, a reduced set of format characters, and a better
}
// Days passed in current month
- $gDayNo += $gd;
+ $gDayNo += (int)$gd;
$jDayNo = $gDayNo - 79;
$s = '';
for ( $pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i-- ) {
if ( $num >= $pow10 ) {
- $s .= $table[$i][floor( $num / $pow10 )];
+ $s .= $table[$i][(int)floor( $num / $pow10 )];
}
$num = $num % $pow10;
}
return $str;
}
+ /**
+ * Used by date() and time() to adjust the time output.
+ *
+ * @param $ts Int the time in date('YmdHis') format
+ * @param $tz Mixed: adjust the time by this amount (default false, mean we
+ * get user timecorrection setting)
+ * @return int
+ */
+ function userAdjust( $ts, $tz = false ) {
+ global $wgUser, $wgLocalTZoffset;
+
+ if ( $tz === false ) {
+ $tz = $wgUser->getOption( 'timecorrection' );
+ }
+
+ $data = explode( '|', $tz, 3 );
+
+ if ( $data[0] == 'ZoneInfo' ) {
+ wfSuppressWarnings();
+ $userTZ = timezone_open( $data[2] );
+ wfRestoreWarnings();
+ if ( $userTZ !== false ) {
+ $date = date_create( $ts, timezone_open( 'UTC' ) );
+ date_timezone_set( $date, $userTZ );
+ $date = date_format( $date, 'YmdHis' );
+ return $date;
+ }
+ # Unrecognized timezone, default to 'Offset' with the stored offset.
+ $data[0] = 'Offset';
+ }
+
+ $minDiff = 0;
+ if ( $data[0] == 'System' || $tz == '' ) {
+ # Global offset in minutes.
+ if ( isset( $wgLocalTZoffset ) ) {
+ $minDiff = $wgLocalTZoffset;
+ }
+ } elseif ( $data[0] == 'Offset' ) {
+ $minDiff = intval( $data[1] );
+ } else {
+ $data = explode( ':', $tz );
+ if ( count( $data ) == 2 ) {
+ $data[0] = intval( $data[0] );
+ $data[1] = intval( $data[1] );
+ $minDiff = abs( $data[0] ) * 60 + $data[1];
+ if ( $data[0] < 0 ) {
+ $minDiff = -$minDiff;
+ }
+ } else {
+ $minDiff = intval( $data[0] ) * 60;
+ }
+ }
+
+ # No difference ? Return time unchanged
+ if ( 0 == $minDiff ) {
+ return $ts;
+ }
+
+ wfSuppressWarnings(); // E_STRICT system time bitching
+ # Generate an adjusted date; take advantage of the fact that mktime
+ # will normalize out-of-range values so we don't have to split $minDiff
+ # into hours and minutes.
+ $t = mktime( (
+ (int)substr( $ts, 8, 2 ) ), # Hours
+ (int)substr( $ts, 10, 2 ) + $minDiff, # Minutes
+ (int)substr( $ts, 12, 2 ), # Seconds
+ (int)substr( $ts, 4, 2 ), # Month
+ (int)substr( $ts, 6, 2 ), # Day
+ (int)substr( $ts, 0, 4 ) ); # Year
+
+ $date = date( 'YmdHis', $t );
+ wfRestoreWarnings();
+
+ return $date;
+ }
+
/**
* This is meant to be used by time(), date(), and timeanddate() to get
* the date preference they're supposed to use, it should be used in
return $this->sprintfDate( $df, $ts );
}
+ /**
+ * Internal helper function for userDate(), userTime() and userTimeAndDate()
+ *
+ * @param $type String: can be 'date', 'time' or 'both'
+ * @param $ts Mixed: the time format which needs to be turned into a
+ * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
+ * @param $user User object used to get preferences for timezone and format
+ * @param $options Array, can contain the following keys:
+ * - 'timecorrection': time correction, can have the following values:
+ * - true: use user's preference
+ * - false: don't use time correction
+ * - integer: value of time correction in minutes
+ * - 'format': format to use, can have the following values:
+ * - true: use user's preference
+ * - false: use default preference
+ * - string: format to use
+ * @return String
+ */
+ private function internalUserTimeAndDate( $type, $ts, User $user, array $options ) {
+ $ts = wfTimestamp( TS_MW, $ts );
+ $options += array( 'timecorrection' => true, 'format' => true );
+ if ( $options['timecorrection'] !== false ) {
+ if ( $options['timecorrection'] === true ) {
+ $offset = $user->getOption( 'timecorrection' );
+ } else {
+ $offset = $options['timecorrection'];
+ }
+ $ts = $this->userAdjust( $ts, $offset );
+ }
+ if ( $options['format'] === true ) {
+ $format = $user->getDatePreference();
+ } else {
+ $format = $options['format'];
+ }
+ $df = $this->getDateFormatString( $type, $this->dateFormat( $format ) );
+ return $this->sprintfDate( $df, $ts );
+ }
+
+ /**
+ * Get the formatted date for the given timestamp and formatted for
+ * the given user.
+ *
+ * @param $ts Mixed: the time format which needs to be turned into a
+ * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
+ * @param $user User object used to get preferences for timezone and format
+ * @param $options Array, can contain the following keys:
+ * - 'timecorrection': time correction, can have the following values:
+ * - true: use user's preference
+ * - false: don't use time correction
+ * - integer: value of time correction in minutes
+ * - 'format': format to use, can have the following values:
+ * - true: use user's preference
+ * - false: use default preference
+ * - string: format to use
+ * @return String
+ */
+ public function userDate( $ts, User $user, array $options = array() ) {
+ return $this->internalUserTimeAndDate( 'date', $ts, $user, $options );
+ }
+
+ /**
+ * Get the formatted time for the given timestamp and formatted for
+ * the given user.
+ *
+ * @param $ts Mixed: the time format which needs to be turned into a
+ * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
+ * @param $user User object used to get preferences for timezone and format
+ * @param $options Array, can contain the following keys:
+ * - 'timecorrection': time correction, can have the following values:
+ * - true: use user's preference
+ * - false: don't use time correction
+ * - integer: value of time correction in minutes
+ * - 'format': format to use, can have the following values:
+ * - true: use user's preference
+ * - false: use default preference
+ * - string: format to use
+ * @return String
+ */
+ public function userTime( $ts, User $user, array $options = array() ) {
+ return $this->internalUserTimeAndDate( 'time', $ts, $user, $options );
+ }
+
+ /**
+ * Get the formatted date and time for the given timestamp and formatted for
+ * the given user.
+ *
+ * @param $ts Mixed: the time format which needs to be turned into a
+ * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
+ * @param $user User object used to get preferences for timezone and format
+ * @param $options Array, can contain the following keys:
+ * - 'timecorrection': time correction, can have the following values:
+ * - true: use user's preference
+ * - false: don't use time correction
+ * - integer: value of time correction in minutes
+ * - 'format': format to use, can have the following values:
+ * - true: use user's preference
+ * - false: use default preference
+ * - string: format to use
+ * @return String
+ */
+ public function userTimeAndDate( $ts, User $user, array $options = array() ) {
+ return $this->internalUserTimeAndDate( 'both', $ts, $user, $options );
+ }
+
/**
* @param $key string
* @return array|null
$digitGroupingPattern = $this->digitGroupingPattern();
if ( !$digitGroupingPattern || $digitGroupingPattern === "###,###,###" ) {
- //default grouping is at thousands, use the same for ###,###,### pattern too.
+ // default grouping is at thousands, use the same for ###,###,### pattern too.
return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
} else {
// Ref: http://cldr.unicode.org/translation/number-patterns
+ $sign = "";
+ if ( intval( $_ ) < 0 ) {
+ // For negative numbers apply the algorithm like positive number and add sign.
+ $sign = "-";
+ $_ = substr( $_,1 );
+ }
$numberpart = array();
$decimalpart = array();
$numMatches = preg_match_all( "/(#+)/", $digitGroupingPattern, $matches );
preg_match( "/\d+/", $_, $numberpart );
preg_match( "/\.\d*/", $_, $decimalpart );
$groupedNumber = ( count( $decimalpart ) > 0 ) ? $decimalpart[0]:"";
- if ( $groupedNumber === $_ ){
- //the string does not have any number part. Eg: .12345
- return $groupedNumber;
+ if ( $groupedNumber === $_ ) {
+ // the string does not have any number part. Eg: .12345
+ return $sign . $groupedNumber;
}
$start = $end = strlen( $numberpart[0] );
while ( $start > 0 ) {
$groupedNumber = "," . $groupedNumber;
}
}
- return $groupedNumber;
+ return $sign . $groupedNumber;
}
}
/**
* truncateHtml() helper function
* (a) push or pop $tag from $openTags as needed
* (b) clear $tag value
- * @param String &$tag Current HTML tag name we are looking at
- * @param int $tagType (0-open tag, 1-close tag)
- * @param char $lastCh Character before the '>' that ended this tag
- * @param array &$openTags Open tag stack (not accounting for $tag)
+ * @param &$tag string Current HTML tag name we are looking at
+ * @param $tagType int (0-open tag, 1-close tag)
+ * @param $lastCh char|string Character before the '>' that ended this tag
+ * @param &$openTags array Open tag stack (not accounting for $tag)
*/
private function truncate_endBracket( &$tag, $tagType, $lastCh, &$openTags ) {
$tag = ltrim( $tag );
}
/**
- * This translates the duration ("1 week", "4 days", etc)
- * as well as the expiry time (which is an absolute timestamp).
+ * @todo Maybe translate block durations. Note that this function is somewhat misnamed: it
+ * deals with translating the *duration* ("1 week", "4 days", etc), not the expiry time
+ * (which is an absolute timestamp). Please note: do NOT add this blindly, as it is used
+ * on old expiry lengths recorded in log entries. You'd need to provide the start date to
+ * match up with it.
+ *
* @param $str String: the validated block duration in English
* @return Somehow translated block duration
* @see LanguageFi.php for example implementation
}
}
}
- // If no duration is given, but a timestamp, display that
- return ( strtotime( $str ) ? $this->timeanddate( strtotime( $str ) ) : $str );
+ // If all else fails, return the original string.
+ return $str;
}
/**
: $infinity;
} else {
return $format === true
- ? $this->timeanddate( $expiry )
+ ? $this->timeanddate( $expiry, /* User preference timezone */ true )
: wfTimestamp( $format, $expiry );
}
}
/**
* @todo Document
* @param $seconds int|float
- * @param $format String Optional, one of ("avoidseconds","avoidminutes"):
- * "avoidseconds" - don't mention seconds if $seconds >= 1 hour
- * "avoidminutes" - don't mention seconds/minutes if $seconds > 48 hours
+ * @param $format Array Optional
+ * If $format['avoid'] == 'avoidseconds' - don't mention seconds if $seconds >= 1 hour
+ * If $format['avoid'] == 'avoidminutes' - don't mention seconds/minutes if $seconds > 48 hours
+ * If $format['noabbrevs'] is true - use 'seconds' and friends instead of 'seconds-abbrev' and friends
+ * For backwards compatibility, $format may also be one of the strings 'avoidseconds' or 'avoidminutes'
* @return string
*/
- function formatTimePeriod( $seconds, $format = false ) {
+ function formatTimePeriod( $seconds, $format = array() ) {
+ if ( !is_array( $format ) ) {
+ $format = array( 'avoid' => $format ); // For backwards compatibility
+ }
+ if ( !isset( $format['avoid'] ) ) {
+ $format['avoid'] = false;
+ }
+ if ( !isset( $format['noabbrevs' ] ) ) {
+ $format['noabbrevs'] = false;
+ }
+ $secondsMsg = wfMessage(
+ $format['noabbrevs'] ? 'seconds' : 'seconds-abbrev' )->inLanguage( $this );
+ $minutesMsg = wfMessage(
+ $format['noabbrevs'] ? 'minutes' : 'minutes-abbrev' )->inLanguage( $this );
+ $hoursMsg = wfMessage(
+ $format['noabbrevs'] ? 'hours' : 'hours-abbrev' )->inLanguage( $this );
+ $daysMsg = wfMessage(
+ $format['noabbrevs'] ? 'days' : 'days-abbrev' )->inLanguage( $this );
+
if ( round( $seconds * 10 ) < 100 ) {
$s = $this->formatNum( sprintf( "%.1f", round( $seconds * 10 ) / 10 ) );
- $s .= $this->getMessageFromDB( 'seconds-abbrev' );
+ $s = $secondsMsg->params( $s )->text();
} elseif ( round( $seconds ) < 60 ) {
$s = $this->formatNum( round( $seconds ) );
- $s .= $this->getMessageFromDB( 'seconds-abbrev' );
+ $s = $secondsMsg->params( $s )->text();
} elseif ( round( $seconds ) < 3600 ) {
$minutes = floor( $seconds / 60 );
$secondsPart = round( fmod( $seconds, 60 ) );
$secondsPart = 0;
$minutes++;
}
- $s = $this->formatNum( $minutes ) . $this->getMessageFromDB( 'minutes-abbrev' );
+ $s = $minutesMsg->params( $this->formatNum( $minutes ) )->text();
$s .= ' ';
- $s .= $this->formatNum( $secondsPart ) . $this->getMessageFromDB( 'seconds-abbrev' );
+ $s .= $secondsMsg->params( $this->formatNum( $secondsPart ) )->text();
} elseif ( round( $seconds ) <= 2 * 86400 ) {
$hours = floor( $seconds / 3600 );
$minutes = floor( ( $seconds - $hours * 3600 ) / 60 );
$minutes = 0;
$hours++;
}
- $s = $this->formatNum( $hours ) . $this->getMessageFromDB( 'hours-abbrev' );
+ $s = $hoursMsg->params( $this->formatNum( $hours ) )->text();
$s .= ' ';
- $s .= $this->formatNum( $minutes ) . $this->getMessageFromDB( 'minutes-abbrev' );
- if ( !in_array( $format, array( 'avoidseconds', 'avoidminutes' ) ) ) {
- $s .= ' ' . $this->formatNum( $secondsPart ) .
- $this->getMessageFromDB( 'seconds-abbrev' );
+ $s .= $minutesMsg->params( $this->formatNum( $minutes ) )->text();
+ if ( !in_array( $format['avoid'], array( 'avoidseconds', 'avoidminutes' ) ) ) {
+ $s .= ' ' . $secondsMsg->params( $this->formatNum( $secondsPart ) )->text();
}
} else {
$days = floor( $seconds / 86400 );
- if ( $format === 'avoidminutes' ) {
+ if ( $format['avoid'] === 'avoidminutes' ) {
$hours = round( ( $seconds - $days * 86400 ) / 3600 );
if ( $hours == 24 ) {
$hours = 0;
$days++;
}
- $s = $this->formatNum( $days ) . $this->getMessageFromDB( 'days-abbrev' );
+ $s = $daysMsg->params( $this->formatNum( $days ) )->text();
$s .= ' ';
- $s .= $this->formatNum( $hours ) . $this->getMessageFromDB( 'hours-abbrev' );
- } elseif ( $format === 'avoidseconds' ) {
+ $s .= $hoursMsg->params( $this->formatNum( $hours ) )->text();
+ } elseif ( $format['avoid'] === 'avoidseconds' ) {
$hours = floor( ( $seconds - $days * 86400 ) / 3600 );
$minutes = round( ( $seconds - $days * 86400 - $hours * 3600 ) / 60 );
if ( $minutes == 60 ) {
$hours = 0;
$days++;
}
- $s = $this->formatNum( $days ) . $this->getMessageFromDB( 'days-abbrev' );
+ $s = $daysMsg->params( $this->formatNum( $days ) )->text();
$s .= ' ';
- $s .= $this->formatNum( $hours ) . $this->getMessageFromDB( 'hours-abbrev' );
+ $s .= $hoursMsg->params( $this->formatNum( $hours ) )->text();
$s .= ' ';
- $s .= $this->formatNum( $minutes ) . $this->getMessageFromDB( 'minutes-abbrev' );
+ $s .= $minutesMsg->params( $this->formatNum( $minutes ) )->text();
} else {
- $s = $this->formatNum( $days ) . $this->getMessageFromDB( 'days-abbrev' );
+ $s = $daysMsg->params( $this->formatNum( $days ) )->text();
$s .= ' ';
$s .= $this->formatTimePeriod( $seconds - $days * 86400, $format );
}
if ( $bps <= 0 ) {
return $this->formatNum( $bps ) . $units[0];
}
- $unitIndex = floor( log10( $bps ) / 3 );
+ $unitIndex = (int)floor( log10( $bps ) / 3 );
$mantissa = $bps / pow( 1000, $unitIndex );
if ( $mantissa < 10 ) {
$mantissa = round( $mantissa, 1 );
return str_replace( '$1', $this->formatNum( $size ), $text );
}
+ /**
+ * Make a list item, used by various special pages
+ *
+ * @param $page String Page link
+ * @param $details String Text between brackets
+ * @param $oppositedm Boolean Add the direction mark opposite to your
+ * language, to display text properly
+ * @return String
+ */
+ function specialList( $page, $details, $oppositedm = true ) {
+ $dirmark = ( $oppositedm ? $this->getDirMark( true ) : '' ) .
+ $this->getDirMark();
+ $details = $details ? $dirmark . $this->getMessageFromDB( 'word-separator' ) .
+ wfMsgExt( 'parentheses', array( 'escape', 'replaceafter', 'language' => $this ), $details ) : '';
+ return $page . $details;
+ }
+
+ /**
+ * Generate (prev x| next x) (20|50|100...) type links for paging
+ *
+ * @param $title Title object to link
+ * @param $offset Integer offset parameter
+ * @param $limit Integer limit parameter
+ * @param $query String optional URL query parameter string
+ * @param $atend Bool optional param for specified if this is the last page
+ * @return String
+ */
+ public function viewPrevNext( Title $title, $offset, $limit, array $query = array(), $atend = false ) {
+ // @todo FIXME: Why on earth this needs one message for the text and another one for tooltip?
+
+ # Make 'previous' link
+ $prev = wfMessage( 'prevn' )->inLanguage( $this )->title( $title )->numParams( $limit )->text();
+ if( $offset > 0 ) {
+ $plink = $this->numLink( $title, max( $offset - $limit, 0 ), $limit,
+ $query, $prev, 'prevn-title', 'mw-prevlink' );
+ } else {
+ $plink = htmlspecialchars( $prev );
+ }
+
+ # Make 'next' link
+ $next = wfMessage( 'nextn' )->inLanguage( $this )->title( $title )->numParams( $limit )->text();
+ if( $atend ) {
+ $nlink = htmlspecialchars( $next );
+ } else {
+ $nlink = $this->numLink( $title, $offset + $limit, $limit,
+ $query, $next, 'prevn-title', 'mw-nextlink' );
+ }
+
+ # Make links to set number of items per page
+ $numLinks = array();
+ foreach( array( 20, 50, 100, 250, 500 ) as $num ) {
+ $numLinks[] = $this->numLink( $title, $offset, $num,
+ $query, $this->formatNum( $num ), 'shown-title', 'mw-numlink' );
+ }
+
+ return wfMessage( 'viewprevnext' )->inLanguage( $this )->title( $title
+ )->rawParams( $plink, $nlink, $this->pipeList( $numLinks ) )->escaped();
+ }
+
+ /**
+ * Helper function for viewPrevNext() that generates links
+ *
+ * @param $title Title object to link
+ * @param $offset Integer offset parameter
+ * @param $limit Integer limit parameter
+ * @param $query Array extra query parameters
+ * @param $link String text to use for the link; will be escaped
+ * @param $tooltipMsg String name of the message to use as tooltip
+ * @param $class String value of the "class" attribute of the link
+ * @return String HTML fragment
+ */
+ private function numLink( Title $title, $offset, $limit, array $query, $link, $tooltipMsg, $class ) {
+ $query = array( 'limit' => $limit, 'offset' => $offset ) + $query;
+ $tooltip = wfMessage( $tooltipMsg )->inLanguage( $this )->title( $title )->numParams( $limit )->text();
+ return Html::element( 'a', array( 'href' => $title->getLocalURL( $query ),
+ 'title' => $tooltip, 'class' => $class ), $link );
+ }
+
/**
* Get the conversion rule title, if any.
*