function convert( $t ) { return $t; }
function convertTo( $text, $variant ) { return $text; }
function convertTitle( $t ) { return $t->getPrefixedText(); }
+ function convertNamespace( $ns ) { return $this->mLang->getFormattedNsText( $ns ); }
function getVariants() { return array( $this->mLang->getCode() ); }
function getPreferredVariant() { return $this->mLang->getCode(); }
function getDefaultVariant() { return $this->mLang->getCode(); }
'hijri-calendar-m10', 'hijri-calendar-m11', 'hijri-calendar-m12'
);
- // For pretty timestamps
- // Cutoff for specifying "weekday at XX:XX" format
- protected $mWeekdayAtCutoff = 432000; // 5 days
-
/**
* @since 1.20
* @var array
* @deprecated in 1.19
*/
function getFallbackLanguageCode() {
- wfDeprecated( __METHOD__ );
+ wfDeprecated( __METHOD__, '1.19' );
return self::getFallbackFor( $this->mCode );
}
*/
public function setNamespaces( array $namespaces ) {
$this->namespaceNames = $namespaces;
+ $this->mNamespaceIds = null;
+ }
+
+ /**
+ * Resets all of the namespace caches. Mainly used for testing
+ */
+ public function resetNamespaces( ) {
+ $this->namespaceNames = null;
+ $this->mNamespaceIds = null;
+ $this->namespaceAliases = null;
}
/**
* @param $usePrefs Mixed: if true, the user's preference is used
* if false, the site/language default is used
* if int/string, assumed to be a format.
- * if User object, assumed to be a User to get preference from
* @return string
*/
function dateFormat( $usePrefs = true ) {
} else {
$datePreference = (string)User::getDefaultOption( 'date' );
}
- } elseif ( $usePrefs instanceof User ) {
- $datePreference = $usePrefs->getDatePreference();
} else {
$datePreference = (string)$usePrefs;
}
$df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
} else {
$df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
-
- if ( $type === 'shortdate' && is_null( $df ) ) {
- $df = $this->getDateFormatString( 'date', $pref );
- }
-
if ( is_null( $df ) ) {
$pref = $this->getDefaultDateFormat();
$df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
}
}
-
$this->dateFormatStrings[$type][$pref] = $df;
}
return $this->dateFormatStrings[$type][$pref];
return $this->internalUserTimeAndDate( 'both', $ts, $user, $options );
}
- /**
- * Formats a timestamp in a pretty, human-readable format.
- * Instead of "13:04, 16 July 2012", we have:
- * - Just now
- * - 35 minutes ago
- * - At 13:04
- * - Yesterday at 13:04
- * - Wednesday at 13:04
- * - July 16, 13:04
- * - July 16 2012 at 13:04
- *
- * @todo Port to JavaScript
- *
- * @param $ts Mixed: the time format which needs to be turned into a
- * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
- * @param $relativeTo Mixed: The timestamp to use as "now"
- * @param $user User: The user to format for (needed for timezone information)
- * @since 1.20
- * @return string Formatted timestamp
- */
- public function prettyTimestamp( $timestamp, $relativeTo = false, $user ) {
- // Parameter defaults
- if ( $relativeTo === false ) {
- $relativeTo = wfTimestampNow();
- }
-
- // Normalise input to UNIX time
- $relativeTo = wfTimestamp( TS_UNIX, $relativeTo );
- $timestamp = wfTimestamp( TS_UNIX, $timestamp );
- $timeAgo = $relativeTo - $timestamp;
-
- $adjustedRelativeTo = $this->userAdjust( wfTimestamp( TS_MW, $relativeTo ), $user->getOption('timecorrection') );
- $adjustedRelativeTo = wfTimestamp( TS_UNIX, $adjustedRelativeTo );
- $relativeToYear = gmdate( 'Y', $adjustedRelativeTo );
-
- $adjustedTimestamp = $this->userAdjust( wfTimestamp( TS_MW, $timestamp ), $user->getOption('timecorrection') );
- $adjustedTimestamp = wfTimestamp( TS_UNIX, $adjustedTimestamp );
- $timestampYear = gmdate( 'Y', $adjustedTimestamp );
-
- if ( $timeAgo < 0 ) {
- throw new MWException( "Future timestamps not currently supported" );
- } elseif ( $timeAgo < 30 ) {
- return wfMessage( 'just-now' )
- ->inLanguage( $this )
- ->text();
- } elseif ( $timeAgo < 5400 ) {
- // Less than 90 minutes ago. Return number of hours, minutes or seconds ago.
- return $this->formatRelativeTime( $timeAgo );
- } elseif ( // Same day
- intval( $adjustedRelativeTo / (24*60*60) ) ===
- intval( $adjustedTimestamp / (24*60*60) )
- ) {
- // Today at XX:XX
- $time = $this->time( $adjustedTimestamp );
- return wfMessage( 'today-at' )
- ->inLanguage( $this )
- ->params( $time )
- ->text();
- } elseif ( // Previous day
- intval( $adjustedRelativeTo / (24*60*60) ) ===
- ( intval( $adjustedTimestamp / (24*60*60) ) + 1 )
- ) {
- // Yesterday at XX:XX
- $time = $this->time( $adjustedTimestamp );
-
- return wfMessage( 'yesterday-at' )
- ->inLanguage( $this )
- ->params( $time )
- ->text();
- } elseif ( $timeAgo < ( $this->mWeekdayAtCutoff ) ) { // Less than 5 days ago
- // Xday at XX:XX
- return $this->formatPastWeekTimestamp( $adjustedTimestamp, $adjustedRelativeTo );
- } elseif ( $relativeToYear == $timestampYear ) {
- // XX XMonth
- $df = $this->getDateFormatString( 'shortdate', $this->dateFormat( $user ) );
- $mwTimestamp = wfTimestamp( TS_MW, $timestamp );
- return $this->sprintfDate( $df, $mwTimestamp );
- } else {
- // Full timestamp
- $mwTimestamp = wfTimestamp( TS_MW, $timestamp );
- return $this->userDate( $mwTimestamp, $user );
- }
- }
-
- /**
- * For pretty timestamps: Formats the "X {hours,minutes,seconds} ago" message.
- *
- * @param $timeAgo The number of seconds ago the event occurred
- * @return Formatted string
- */
- protected function formatRelativeTime( $timeAgo ) {
- $count = false;
- if ( $timeAgo < 60 ) {
- $unit = 'seconds';
- $count = $timeAgo;
- } elseif ( $timeAgo < 3600 ) {
- $unit = 'minutes';
- $count = intval( $timeAgo / 60 );
- } else {
- $unit = 'hours';
- $count = intval( $timeAgo / 3600 );
- }
-
- return wfMessage( "{$unit}-ago" )->inLanguage( $this )->params( $count )->text();
- }
-
- /**
- * For pretty timestamps: Formats the timestamp for events that occurred
- * "in the last few days".
- * (cutoff is configurable by the member variable $mWeekdayAtCutoff)
- *
- * @param $eventTimestamp The timestamp of the event, adjusted to
- * the user's local timezone, in UNIX format (# of seconds since epoch)
- * @param $relativeTo The timestamp to format relative to, adjusted to
- * the user's local timezone, in UNIX format (# of seconds since epoch)
- * @return String: The date formatted in a human-friendly way.
- */
- protected function formatPastWeekTimestamp( $adjustedTimestamp, $relativeTo ) {
- $day = date( 'w', $adjustedTimestamp );
- $weekday = self::$mWeekdayMsgs[$day];
- $time = $this->time( $adjustedTimestamp );
-
- return wfMessage( "$weekday-at" )
- ->inLanguage( $this )
- ->params( $time )
- ->text();
- }
-
/**
* @param $key string
* @return array|null
return $this->mConverter->convertTitle( $title );
}
+ /**
+ * Convert a namespace index to a string in the preferred variant
+ *
+ * @param $ns int
+ * @return string
+ */
+ public function convertNamespace( $ns ) {
+ return $this->mConverter->convertNamespace( $ns );
+ }
+
/**
* Check if this is a language with variants
*
'mdy time' => 'H:i',
'mdy date' => 'F j, Y',
'mdy both' => 'H:i, F j, Y',
- 'mdy shortdate' => 'F j',
'dmy time' => 'H:i',
'dmy date' => 'j F Y',
'dmy both' => 'H:i, j F Y',
- 'dmy shortdate' => 'j F',
'ymd time' => 'H:i',
'ymd date' => 'Y F j',
'ymd both' => 'H:i, Y F j',
- 'ymd shortdate' => 'F j',
'ISO 8601 time' => 'xnH:xni:xns',
'ISO 8601 date' => 'xnY-xnm-xnd',
'ISO 8601 both' => 'xnY-xnm-xnd"T"xnH:xni:xns',
- // 'ISO 8601 shortdate' => 'xnm-xnd', // This is just confusing
);
/**
'qbbrowse' => 'Browse',
'qbedit' => 'Edit',
'qbpageoptions' => 'This page',
-'qbpageinfo' => 'Context',
'qbmyoptions' => 'My pages',
'qbspecialpages' => 'Special pages',
'faq' => 'FAQ',
# Login and logout pages
'logouttext' => "'''You are now logged out.'''
-You can continue to use {{SITENAME}} anonymously, or you can [[Special:UserLogin|log in again]] as the same or as a different user.
+You can continue to use {{SITENAME}} anonymously, or you can <span class='plainlinks'>[$1 log in again]</span> as the same or as a different user.
Note that some pages may continue to be displayed as if you were still logged in, until you clear your browser cache.",
'welcomecreation' => '== Welcome, $1! ==
Your account has been created.
'note' => "'''Note:'''",
'previewnote' => "'''Remember that this is only a preview.'''
Your changes have not yet been saved!",
-'continue-editing' => 'Continue editing',
+'continue-editing' => 'Go to editing area',
'previewconflict' => 'This preview reflects the text in the upper text editing area as it will appear if you choose to save.',
'session_fail_preview' => "'''Sorry! We could not process your edit due to a loss of session data.'''
Please try again.
'addsection-preload' => '', # do not translate or duplicate this message to other languages
'addsection-editintro' => '', # do not translate or duplicate this message to other languages
'defaultmessagetext' => 'Default message text',
+'content-failed-to-parse' => 'Failed to parse $2 content for $1 model: $3',
+'invalid-content-data' => 'Invalid content data',
+'content-not-allowed-here' => '"$1" content is not allowed on page [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'wikitext',
+'content-model-text' => 'plain text',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
# Parser/template warnings
'expensive-parserfunction-warning' => "'''Warning:''' This page contains too many expensive parser function calls.
'shared-repo' => 'a shared repository',
'shared-repo-name-wikimediacommons' => 'Wikimedia Commons', # only translate this message to other languages if you have to change it
'filepage.css' => '/* CSS placed here is included on the file description page, also included on foreign client wikis */', # only translate this message to other languages if you have to change it
-'upload-disallowed-here' => 'Unfortunately you cannot overwrite this image.',
+'upload-disallowed-here' => 'You cannot overwrite this file.',
# File reversion
'filerevert' => 'Revert $1',
'undeletedrevisions' => '{{PLURAL:$1|1 revision|$1 revisions}} restored',
'undeletedrevisions-files' => '{{PLURAL:$1|1 revision|$1 revisions}} and {{PLURAL:$2|1 file|$2 files}} restored',
'undeletedfiles' => '{{PLURAL:$1|1 file|$1 files}} restored',
-'cannotundelete' => 'Undelete failed;
-someone else may have undeleted the page first.',
+'cannotundelete' => 'Undelete failed:
+$1',
'undeletedpage' => "'''$1 has been restored'''
Consult the [[Special:Log/delete|deletion log]] for a record of recent deletions and restorations.",
'immobile-target-namespace-iw' => 'Interwiki link is not a valid target for page move.',
'immobile-source-page' => 'This page is not movable.',
'immobile-target-page' => 'Cannot move to that destination title.',
+'bad-target-model' => 'The desired destination uses a different content model. Can not convert from $1 to $2.',
'imagenocrossnamespace' => 'Cannot move file to non-file namespace',
'nonfile-cannot-move-to-file' => 'Cannot move non-file to file namespace',
'imagetypemismatch' => 'The new file extension does not match its type',
'standard.css' => '/* CSS placed here will affect users of the Standard skin */', # only translate this message to other languages if you have to change it
'nostalgia.css' => '/* CSS placed here will affect users of the Nostalgia skin */', # only translate this message to other languages if you have to change it
'cologneblue.css' => '/* CSS placed here will affect users of the Cologne Blue skin */', # only translate this message to other languages if you have to change it
-'monobook.css' => '/* CSS placed here will affect users of the Monobook skin */', # only translate this message to other languages if you have to change it
+'monobook.css' => '/* CSS placed here will affect users of the MonoBook skin */', # only translate this message to other languages if you have to change it
'myskin.css' => '/* CSS placed here will affect users of the MySkin skin */', # only translate this message to other languages if you have to change it
'chick.css' => '/* CSS placed here will affect users of the Chick skin */', # only translate this message to other languages if you have to change it
'simple.css' => '/* CSS placed here will affect users of the Simple skin */', # only translate this message to other languages if you have to change it
# Info page
'pageinfo-header' => '-', # do not translate or duplicate this message to other languages
'pageinfo-title' => 'Information for "$1"',
+'pageinfo-not-current' => 'Information may only be displayed for the current revision.',
'pageinfo-header-basic' => 'Basic information',
'pageinfo-header-edits' => 'Edit history',
'pageinfo-header-restrictions' => 'Page protection',
'pageinfo-authors' => 'Total number of distinct authors',
'pageinfo-recent-edits' => 'Recent number of edits (within past $1)',
'pageinfo-recent-authors' => 'Recent number of distinct authors',
-'pageinfo-restriction' => 'Page protection ({{lcfirst:$1}})',
'pageinfo-magic-words' => 'Magic {{PLURAL:$1|word|words}} ($1)',
'pageinfo-hidden-categories' => 'Hidden {{PLURAL:$1|category|categories}} ($1)',
'pageinfo-templates' => 'Transcluded {{PLURAL:$1|template|templates}} ($1)',
'pageinfo-footer' => '-', # do not translate or duplicate this message to other languages
'pageinfo-toolboxlink' => 'Page information',
+'pageinfo-redirectsto' => 'Redirects to',
+'pageinfo-redirectsto-info' => 'info',
+'pageinfo-contentpage' => 'Counted as a content page',
+'pageinfo-contentpage-yes' => 'Yes',
+'pageinfo-protect-cascading' => 'Protections are cascading from here',
+'pageinfo-protect-cascading-yes' => 'Yes',
+'pageinfo-protect-cascading-from' => 'Protections are cascading from',
# Skin names
'skinname-standard' => 'Classic', # only translate this message to other languages if you have to change it
# Video information, used by Language::formatTimePeriod() to format lengths in the above messages
'video-dims' => '$1, $2 × $3', # only translate this message to other languages if you have to change it
-'seconds-abbrev' => '$1s', # only translate this message to other languages if you have to change it
-'minutes-abbrev' => '$1m', # only translate this message to other languages if you have to change it
-'hours-abbrev' => '$1h', # only translate this message to other languages if you have to change it
-'days-abbrev' => '$1d', # only translate this message to other languages if you have to change it
+'seconds-abbrev' => '$1 s', # only translate this message to other languages if you have to change it
+'minutes-abbrev' => '$1 min', # only translate this message to other languages if you have to change it
+'hours-abbrev' => '$1 h', # only translate this message to other languages if you have to change it
+'days-abbrev' => '$1 d', # only translate this message to other languages if you have to change it
'seconds' => '{{PLURAL:$1|$1 second|$1 seconds}}',
'minutes' => '{{PLURAL:$1|$1 minute|$1 minutes}}',
'hours' => '{{PLURAL:$1|$1 hour|$1 hours}}',
'days' => '{{PLURAL:$1|$1 day|$1 days}}',
'ago' => '$1 ago',
- 'hours-ago' => '$1 {{PLURAL:$1|hour|hours}} ago',
- 'minutes-ago' => '$1 {{PLURAL:$1|minute|minutes}} ago',
- 'seconds-ago' => '$1 {{PLURAL:$1|seconds|seconds}} ago',
-
- 'monday-at' => 'Monday at $1',
- 'tuesday-at' => 'Tuesday at $1',
- 'wednesday-at' => 'Wednesday at $1',
- 'thursday-at' => 'Thursday at $1',
- 'friday-at' => 'Friday at $1',
- 'saturday-at' => 'Saturday at $1',
- 'sunday-at' => 'Sunday at $1',
-
- 'today-at' => '$1',
- 'yesterday-at' => 'Yesterday at $1',
- 'just-now' => 'Just now',
-
# Bad image list
'bad_image_list' => 'The format is as follows:
'nov',
'dec',
),
- 'pretty-timestamps' => array(
- 'monday-at',
- 'tuesday-at',
- 'wednesday-at',
- 'thursday-at',
- 'friday-at',
- 'saturday-at',
- 'sunday-at',
- 'today-at',
- 'yesterday-at',
- 'just-now',
- ),
'categorypages' => array(
'pagecategories',
'pagecategorieslink',
'qbbrowse',
'qbedit',
'qbpageoptions',
- 'qbpageinfo',
'qbmyoptions',
'qbspecialpages',
'faq',
'addsection-preload',
'addsection-editintro',
'defaultmessagetext',
+ 'content-failed-to-parse',
+ 'invalid-content-data',
+ 'content-not-allowed-here',
+ ),
+ 'contentmodels' => array(
+ 'content-model-wikitext',
+ 'content-model-text',
+ 'content-model-javascript',
+ 'content-model-css',
),
'parserwarnings' => array(
'expensive-parserfunction-warning',
'immobile-target-namespace-iw',
'immobile-source-page',
'immobile-target-page',
+ 'bad-target-model',
'immobile_namespace',
'imagenocrossnamespace',
'nonfile-cannot-move-to-file',
'info' => array(
'pageinfo-header',
'pageinfo-title',
+ 'pageinfo-not-current',
'pageinfo-header-basic',
'pageinfo-header-edits',
'pageinfo-header-restrictions',
'pageinfo-authors',
'pageinfo-recent-edits',
'pageinfo-recent-authors',
- 'pageinfo-restriction',
'pageinfo-magic-words',
'pageinfo-hidden-categories',
'pageinfo-templates',
'pageinfo-footer',
'pageinfo-toolboxlink',
+ 'pageinfo-redirectsto',
+ 'pageinfo-redirectsto-info',
+ 'pageinfo-contentpage',
+ 'pageinfo-contentpage-yes',
+ 'pageinfo-protect-cascading',
+ 'pageinfo-protect-cascading-yes',
+ 'pageinfo-protect-cascading-from',
),
'skin' => array(
'skinname-standard',
'toolbar' => 'Edit page toolbar',
'edit' => 'Edit pages',
'parserwarnings' => 'Parser/template warnings',
+ 'contentmodels' => 'Content models',
'undo' => '"Undo" feature',
'cantcreateaccount' => 'Account creation failure',
'history' => 'History pages',
*/
private $lang;
- function setUp() {
+ protected function setUp() {
$this->lang = Language::factory( 'en' );
}
- function tearDown() {
+ protected function tearDown() {
unset( $this->lang );
}
array(
9.45,
array(),
- '9.5s',
+ '9.5 s',
'formatTimePeriod() rounding (<10s)'
),
array(
array(
9.95,
array(),
- '10s',
+ '10 s',
'formatTimePeriod() rounding (<10s)'
),
array(
array(
59.55,
array(),
- '1m 0s',
+ '1 min 0 s',
'formatTimePeriod() rounding (<60s)'
),
array(
array(
119.55,
array(),
- '2m 0s',
+ '2 min 0 s',
'formatTimePeriod() rounding (<1h)'
),
array(
array(
3599.55,
array(),
- '1h 0m 0s',
+ '1 h 0 min 0 s',
'formatTimePeriod() rounding (<1h)'
),
array(
array(
7199.55,
array(),
- '2h 0m 0s',
+ '2 h 0 min 0 s',
'formatTimePeriod() rounding (>=1h)'
),
array(
array(
7199.55,
'avoidseconds',
- '2h 0m',
+ '2 h 0 min',
'formatTimePeriod() rounding (>=1h), avoidseconds'
),
array(
array(
7199.55,
'avoidminutes',
- '2h 0m',
+ '2 h 0 min',
'formatTimePeriod() rounding (>=1h), avoidminutes'
),
array(
array(
172799.55,
'avoidseconds',
- '48h 0m',
+ '48 h 0 min',
'formatTimePeriod() rounding (=48h), avoidseconds'
),
array(
array(
259199.55,
'avoidminutes',
- '3d 0h',
+ '3 d 0 h',
'formatTimePeriod() rounding (>48h), avoidminutes'
),
array(
array(
176399.55,
'avoidseconds',
- '2d 1h 0m',
+ '2 d 1 h 0 min',
'formatTimePeriod() rounding (>48h), avoidseconds'
),
array(
array(
176399.55,
'avoidminutes',
- '2d 1h',
+ '2 d 1 h',
'formatTimePeriod() rounding (>48h), avoidminutes'
),
array(
array(
259199.55,
'avoidseconds',
- '3d 0h 0m',
+ '3 d 0 h 0 min',
'formatTimePeriod() rounding (>48h), avoidseconds'
),
array(
array(
172801.55,
'avoidseconds',
- '2d 0h 0m',
+ '2 d 0 h 0 min',
'formatTimePeriod() rounding, (>48h), avoidseconds'
),
array(
array(
176460.55,
array(),
- '2d 1h 1m 1s',
+ '2 d 1 h 1 min 1 s',
'formatTimePeriod() rounding, recursion, (>48h)'
),
array(
) ),
);
}
-
- /**
- * @test
- * @dataProvider providePrettyTimestampTests
- */
- public function testPrettyTimestamp(
- $tsTime, // The timestamp to format
- $currentTime, // The time to consider "now"
- $timeCorrection, // The time offset to use
- $dateFormat, // The date preference to use
- $expectedOutput, // The expected output
- $desc // Description
- ) {
- $user = new User;
- $user->setOption( 'timecorrection', $timeCorrection );
- $user->setOption( 'date', $dateFormat );
-
- $this->assertEquals(
- $expectedOutput,
- $this->lang->prettyTimestamp( $tsTime, $currentTime, $user ),
- $desc
- );
- }
-
- public function providePrettyTimestampTests() {
- return array(
- array(
- '20111231170000',
- '20120101000000',
- 'Offset|0',
- 'mdy',
- 'Yesterday at 17:00',
- '"Yesterday" across years',
- ),
- array(
- '20120717190900',
- '20120717190929',
- 'Offset|0',
- 'mdy',
- 'Just now',
- '"Just now"',
- ),
- array(
- '20120717190900',
- '20120717191530',
- 'Offset|0',
- 'mdy',
- '6 minutes ago',
- 'X minutes ago',
- ),
- array(
- '20121006173100',
- '20121006173200',
- 'Offset|0',
- 'mdy',
- '1 minute ago',
- '"1 minute ago"',
- ),
- array(
- '20120617190900',
- '20120717190900',
- 'Offset|0',
- 'mdy',
- 'June 17',
- 'Another month'
- ),
- array(
- '19910130151500',
- '20120716193700',
- 'Offset|0',
- 'mdy',
- 'January 30, 1991',
- 'Different year',
- ),
- array(
- '20120101050000',
- '20120101080000',
- 'Offset|-360',
- 'mdy',
- 'Yesterday at 23:00',
- '"Yesterday" across years with time correction',
- ),
- array(
- '20120714184300',
- '20120716184300',
- 'Offset|-420',
- 'mdy',
- 'Saturday at 11:43',
- 'Recent weekday with time correction',
- ),
- array(
- '20120714184300',
- '20120715040000',
- 'Offset|-420',
- 'mdy',
- '11:43',
- 'Today at another time with time correction',
- ),
- array(
- '20120617190900',
- '20120717190900',
- 'Offset|0',
- 'dmy',
- '17 June',
- 'Another month with dmy'
- ),
- array(
- '20120617190900',
- '20120717190900',
- 'Offset|0',
- 'ISO 8601',
- '2012-06-17',
- 'Another month with ISO-8601'
- ),
- array(
- '19910130151500',
- '20120716193700',
- 'Offset|0',
- 'ISO 8601',
- '1991-01-30',
- 'Different year with ISO-8601',
- ),
- );
- }
}
+