00001 <?php
00009 if( !defined( 'MEDIAWIKI' ) ) {
00010 echo "This file is part of MediaWiki, it is not a valid entry point.\n";
00011 exit( 1 );
00012 }
00013
00014 # Read language names
00015 global $wgLanguageNames;
00016 require_once( dirname(__FILE__) . '/Names.php' ) ;
00017
00018 global $wgInputEncoding, $wgOutputEncoding;
00019
00023 $wgInputEncoding = "UTF-8";
00024 $wgOutputEncoding = "UTF-8";
00025
00026 if( function_exists( 'mb_strtoupper' ) ) {
00027 mb_internal_encoding('UTF-8');
00028 }
00029
00035 class FakeConverter {
00036 var $mLang;
00037 function FakeConverter( $langobj ) { $this->mLang = $langobj; }
00038 function autoConvertToAllVariants( $text ) { return $text; }
00039 function convert( $t ) { return $t; }
00040 function convertTitle( $t ) { return $t->getPrefixedText(); }
00041 function getVariants() { return array( $this->mLang->getCode() ); }
00042 function getPreferredVariant() { return $this->mLang->getCode(); }
00043 function getConvRuleTitle() { return false; }
00044 function findVariantLink(&$l, &$n, $ignoreOtherCond = false) {}
00045 function getExtraHashOptions() {return '';}
00046 function getParsedTitle() {return '';}
00047 function markNoConversion($text, $noParse=false) {return $text;}
00048 function convertCategoryKey( $key ) {return $key; }
00049 function convertLinkToAllVariants($text){ return array( $this->mLang->getCode() => $text); }
00050 function armourMath($text){ return $text; }
00051 }
00052
00057 class Language {
00058 var $mConverter, $mVariants, $mCode, $mLoaded = false;
00059 var $mMagicExtensions = array(), $mMagicHookDone = false;
00060
00061 var $mNamespaceIds, $namespaceNames, $namespaceAliases;
00062 var $dateFormatStrings = array();
00063 var $mExtendedSpecialPageAliases;
00064
00068 var $transformData = array();
00069
00070 static public $dataCache;
00071 static public $mLangObjCache = array();
00072
00073 static public $mWeekdayMsgs = array(
00074 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday',
00075 'friday', 'saturday'
00076 );
00077
00078 static public $mWeekdayAbbrevMsgs = array(
00079 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'
00080 );
00081
00082 static public $mMonthMsgs = array(
00083 'january', 'february', 'march', 'april', 'may_long', 'june',
00084 'july', 'august', 'september', 'october', 'november',
00085 'december'
00086 );
00087 static public $mMonthGenMsgs = array(
00088 'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen',
00089 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen',
00090 'december-gen'
00091 );
00092 static public $mMonthAbbrevMsgs = array(
00093 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug',
00094 'sep', 'oct', 'nov', 'dec'
00095 );
00096
00097 static public $mIranianCalendarMonthMsgs = array(
00098 'iranian-calendar-m1', 'iranian-calendar-m2', 'iranian-calendar-m3',
00099 'iranian-calendar-m4', 'iranian-calendar-m5', 'iranian-calendar-m6',
00100 'iranian-calendar-m7', 'iranian-calendar-m8', 'iranian-calendar-m9',
00101 'iranian-calendar-m10', 'iranian-calendar-m11', 'iranian-calendar-m12'
00102 );
00103
00104 static public $mHebrewCalendarMonthMsgs = array(
00105 'hebrew-calendar-m1', 'hebrew-calendar-m2', 'hebrew-calendar-m3',
00106 'hebrew-calendar-m4', 'hebrew-calendar-m5', 'hebrew-calendar-m6',
00107 'hebrew-calendar-m7', 'hebrew-calendar-m8', 'hebrew-calendar-m9',
00108 'hebrew-calendar-m10', 'hebrew-calendar-m11', 'hebrew-calendar-m12',
00109 'hebrew-calendar-m6a', 'hebrew-calendar-m6b'
00110 );
00111
00112 static public $mHebrewCalendarMonthGenMsgs = array(
00113 'hebrew-calendar-m1-gen', 'hebrew-calendar-m2-gen', 'hebrew-calendar-m3-gen',
00114 'hebrew-calendar-m4-gen', 'hebrew-calendar-m5-gen', 'hebrew-calendar-m6-gen',
00115 'hebrew-calendar-m7-gen', 'hebrew-calendar-m8-gen', 'hebrew-calendar-m9-gen',
00116 'hebrew-calendar-m10-gen', 'hebrew-calendar-m11-gen', 'hebrew-calendar-m12-gen',
00117 'hebrew-calendar-m6a-gen', 'hebrew-calendar-m6b-gen'
00118 );
00119
00120 static public $mHijriCalendarMonthMsgs = array(
00121 'hijri-calendar-m1', 'hijri-calendar-m2', 'hijri-calendar-m3',
00122 'hijri-calendar-m4', 'hijri-calendar-m5', 'hijri-calendar-m6',
00123 'hijri-calendar-m7', 'hijri-calendar-m8', 'hijri-calendar-m9',
00124 'hijri-calendar-m10', 'hijri-calendar-m11', 'hijri-calendar-m12'
00125 );
00126
00130 static function factory( $code ) {
00131 if ( !isset( self::$mLangObjCache[$code] ) ) {
00132 if( count( self::$mLangObjCache ) > 10 ) {
00133
00134 self::$mLangObjCache = array();
00135 }
00136 self::$mLangObjCache[$code] = self::newFromCode( $code );
00137 }
00138 return self::$mLangObjCache[$code];
00139 }
00140
00144 protected static function newFromCode( $code ) {
00145 global $IP;
00146 static $recursionLevel = 0;
00147
00148
00149 if ( !Language::isValidCode( $code )
00150 || strcspn( $code, "/\\\000" ) !== strlen( $code ) )
00151 {
00152 throw new MWException( "Invalid language code \"$code\"" );
00153 }
00154
00155 if ( $code == 'en' ) {
00156 $class = 'Language';
00157 } else {
00158 $class = 'Language' . str_replace( '-', '_', ucfirst( $code ) );
00159
00160 if ( file_exists( "$IP/languages/classes/$class.deps.php" ) ) {
00161 include_once("$IP/languages/classes/$class.deps.php");
00162 }
00163 if ( file_exists( "$IP/languages/classes/$class.php" ) ) {
00164 include_once("$IP/languages/classes/$class.php");
00165 }
00166 }
00167
00168 if ( $recursionLevel > 5 ) {
00169 throw new MWException( "Language fallback loop detected when creating class $class\n" );
00170 }
00171
00172 if( ! class_exists( $class ) ) {
00173 $fallback = Language::getFallbackFor( $code );
00174 ++$recursionLevel;
00175 $lang = Language::newFromCode( $fallback );
00176 --$recursionLevel;
00177 $lang->setCode( $code );
00178 } else {
00179 $lang = new $class;
00180 }
00181 return $lang;
00182 }
00183
00188 public static function isValidCode( $code ) {
00189 return strcspn( $code, "/\\\000" ) === strlen( $code );
00190 }
00191
00195 public static function getLocalisationCache() {
00196 if ( is_null( self::$dataCache ) ) {
00197 global $wgLocalisationCacheConf;
00198 $class = $wgLocalisationCacheConf['class'];
00199 self::$dataCache = new $class( $wgLocalisationCacheConf );
00200 }
00201 return self::$dataCache;
00202 }
00203
00204 function __construct() {
00205 $this->mConverter = new FakeConverter($this);
00206
00207 if ( get_class( $this ) == 'Language' ) {
00208 $this->mCode = 'en';
00209 } else {
00210 $this->mCode = str_replace( '_', '-', strtolower( substr( get_class( $this ), 8 ) ) );
00211 }
00212 self::getLocalisationCache();
00213 }
00214
00218 function __destruct() {
00219 foreach ( $this as $name => $value ) {
00220 unset( $this->$name );
00221 }
00222 }
00223
00228 function initContLang() {}
00229
00234 function getDefaultUserOptions() {
00235 wfDeprecated( __METHOD__ );
00236 return User::getDefaultOptions();
00237 }
00238
00239 function getFallbackLanguageCode() {
00240 if ( $this->mCode === 'en' ) {
00241 return false;
00242 } else {
00243 return self::$dataCache->getItem( $this->mCode, 'fallback' );
00244 }
00245 }
00246
00251 function getBookstoreList() {
00252 return self::$dataCache->getItem( $this->mCode, 'bookstoreList' );
00253 }
00254
00258 function getNamespaces() {
00259 if ( is_null( $this->namespaceNames ) ) {
00260 global $wgExtraNamespaces, $wgMetaNamespace, $wgMetaNamespaceTalk;
00261
00262 $this->namespaceNames = self::$dataCache->getItem( $this->mCode, 'namespaceNames' );
00263 if ( $wgExtraNamespaces ) {
00264 $this->namespaceNames = $wgExtraNamespaces + $this->namespaceNames;
00265 }
00266
00267 $this->namespaceNames[NS_PROJECT] = $wgMetaNamespace;
00268 if ( $wgMetaNamespaceTalk ) {
00269 $this->namespaceNames[NS_PROJECT_TALK] = $wgMetaNamespaceTalk;
00270 } else {
00271 $talk = $this->namespaceNames[NS_PROJECT_TALK];
00272 $this->namespaceNames[NS_PROJECT_TALK] =
00273 $this->fixVariableInNamespace( $talk );
00274 }
00275
00276 # The above mixing may leave namespaces out of canonical order.
00277 # Re-order by namespace ID number...
00278 ksort( $this->namespaceNames );
00279 }
00280 return $this->namespaceNames;
00281 }
00282
00291 function getFormattedNamespaces() {
00292 $ns = $this->getNamespaces();
00293 foreach($ns as $k => $v) {
00294 $ns[$k] = strtr($v, '_', ' ');
00295 }
00296 return $ns;
00297 }
00298
00309 function getNsText( $index ) {
00310 $ns = $this->getNamespaces();
00311 return isset( $ns[$index] ) ? $ns[$index] : false;
00312 }
00313
00321 function getFormattedNsText( $index ) {
00322 $ns = $this->getNsText( $index );
00323 return strtr($ns, '_', ' ');
00324 }
00325
00334 function getLocalNsIndex( $text ) {
00335 $lctext = $this->lc($text);
00336 $ids = $this->getNamespaceIds();
00337 return isset( $ids[$lctext] ) ? $ids[$lctext] : false;
00338 }
00339
00340 function getNamespaceAliases() {
00341 if ( is_null( $this->namespaceAliases ) ) {
00342 $aliases = self::$dataCache->getItem( $this->mCode, 'namespaceAliases' );
00343 if ( !$aliases ) {
00344 $aliases = array();
00345 } else {
00346 foreach ( $aliases as $name => $index ) {
00347 if ( $index === NS_PROJECT_TALK ) {
00348 unset( $aliases[$name] );
00349 $name = $this->fixVariableInNamespace( $name );
00350 $aliases[$name] = $index;
00351 }
00352 }
00353 }
00354 $this->namespaceAliases = $aliases;
00355 }
00356 return $this->namespaceAliases;
00357 }
00358
00359 function getNamespaceIds() {
00360 if ( is_null( $this->mNamespaceIds ) ) {
00361 global $wgNamespaceAliases;
00362 # Put namespace names and aliases into a hashtable.
00363 # If this is too slow, then we should arrange it so that it is done
00364 # before caching. The catch is that at pre-cache time, the above
00365 # class-specific fixup hasn't been done.
00366 $this->mNamespaceIds = array();
00367 foreach ( $this->getNamespaces() as $index => $name ) {
00368 $this->mNamespaceIds[$this->lc($name)] = $index;
00369 }
00370 foreach ( $this->getNamespaceAliases() as $name => $index ) {
00371 $this->mNamespaceIds[$this->lc($name)] = $index;
00372 }
00373 if ( $wgNamespaceAliases ) {
00374 foreach ( $wgNamespaceAliases as $name => $index ) {
00375 $this->mNamespaceIds[$this->lc($name)] = $index;
00376 }
00377 }
00378 }
00379 return $this->mNamespaceIds;
00380 }
00381
00382
00390 function getNsIndex( $text ) {
00391 $lctext = $this->lc($text);
00392 if ( ( $ns = MWNamespace::getCanonicalIndex( $lctext ) ) !== null ) {
00393 return $ns;
00394 }
00395 $ids = $this->getNamespaceIds();
00396 return isset( $ids[$lctext] ) ? $ids[$lctext] : false;
00397 }
00398
00405 function getVariantname( $code ) {
00406 return $this->getMessageFromDB( "variantname-$code" );
00407 }
00408
00409 function specialPage( $name ) {
00410 $aliases = $this->getSpecialPageAliases();
00411 if ( isset( $aliases[$name][0] ) ) {
00412 $name = $aliases[$name][0];
00413 }
00414 return $this->getNsText( NS_SPECIAL ) . ':' . $name;
00415 }
00416
00417 function getQuickbarSettings() {
00418 return array(
00419 $this->getMessage( 'qbsettings-none' ),
00420 $this->getMessage( 'qbsettings-fixedleft' ),
00421 $this->getMessage( 'qbsettings-fixedright' ),
00422 $this->getMessage( 'qbsettings-floatingleft' ),
00423 $this->getMessage( 'qbsettings-floatingright' )
00424 );
00425 }
00426
00427 function getMathNames() {
00428 return self::$dataCache->getItem( $this->mCode, 'mathNames' );
00429 }
00430
00431 function getDatePreferences() {
00432 return self::$dataCache->getItem( $this->mCode, 'datePreferences' );
00433 }
00434
00435 function getDateFormats() {
00436 return self::$dataCache->getItem( $this->mCode, 'dateFormats' );
00437 }
00438
00439 function getDefaultDateFormat() {
00440 $df = self::$dataCache->getItem( $this->mCode, 'defaultDateFormat' );
00441 if ( $df === 'dmy or mdy' ) {
00442 global $wgAmericanDates;
00443 return $wgAmericanDates ? 'mdy' : 'dmy';
00444 } else {
00445 return $df;
00446 }
00447 }
00448
00449 function getDatePreferenceMigrationMap() {
00450 return self::$dataCache->getItem( $this->mCode, 'datePreferenceMigrationMap' );
00451 }
00452
00453 function getImageFile( $image ) {
00454 return self::$dataCache->getSubitem( $this->mCode, 'imageFiles', $image );
00455 }
00456
00457 function getDefaultUserOptionOverrides() {
00458 return self::$dataCache->getItem( $this->mCode, 'defaultUserOptionOverrides' );
00459 }
00460
00461 function getExtraUserToggles() {
00462 return self::$dataCache->getItem( $this->mCode, 'extraUserToggles' );
00463 }
00464
00465 function getUserToggle( $tog ) {
00466 return $this->getMessageFromDB( "tog-$tog" );
00467 }
00468
00473 public static function getLanguageNames( $customisedOnly = false ) {
00474 global $wgLanguageNames, $wgExtraLanguageNames;
00475 $allNames = $wgExtraLanguageNames + $wgLanguageNames;
00476 if ( !$customisedOnly ) {
00477 return $allNames;
00478 }
00479
00480 global $IP;
00481 $names = array();
00482 $dir = opendir( "$IP/languages/messages" );
00483 while( false !== ( $file = readdir( $dir ) ) ) {
00484 $code = self::getCodeFromFileName( $file, 'Messages' );
00485 if ( $code && isset( $allNames[$code] ) ) {
00486 $names[$code] = $allNames[$code];
00487 }
00488 }
00489 closedir( $dir );
00490 return $names;
00491 }
00492
00499 function getMessageFromDB( $msg ) {
00500 return wfMsgExt( $msg, array( 'parsemag', 'language' => $this ) );
00501 }
00502
00503 function getLanguageName( $code ) {
00504 $names = self::getLanguageNames();
00505 if ( !array_key_exists( $code, $names ) ) {
00506 return '';
00507 }
00508 return $names[$code];
00509 }
00510
00511 function getMonthName( $key ) {
00512 return $this->getMessageFromDB( self::$mMonthMsgs[$key-1] );
00513 }
00514
00515 function getMonthNameGen( $key ) {
00516 return $this->getMessageFromDB( self::$mMonthGenMsgs[$key-1] );
00517 }
00518
00519 function getMonthAbbreviation( $key ) {
00520 return $this->getMessageFromDB( self::$mMonthAbbrevMsgs[$key-1] );
00521 }
00522
00523 function getWeekdayName( $key ) {
00524 return $this->getMessageFromDB( self::$mWeekdayMsgs[$key-1] );
00525 }
00526
00527 function getWeekdayAbbreviation( $key ) {
00528 return $this->getMessageFromDB( self::$mWeekdayAbbrevMsgs[$key-1] );
00529 }
00530
00531 function getIranianCalendarMonthName( $key ) {
00532 return $this->getMessageFromDB( self::$mIranianCalendarMonthMsgs[$key-1] );
00533 }
00534
00535 function getHebrewCalendarMonthName( $key ) {
00536 return $this->getMessageFromDB( self::$mHebrewCalendarMonthMsgs[$key-1] );
00537 }
00538
00539 function getHebrewCalendarMonthNameGen( $key ) {
00540 return $this->getMessageFromDB( self::$mHebrewCalendarMonthGenMsgs[$key-1] );
00541 }
00542
00543 function getHijriCalendarMonthName( $key ) {
00544 return $this->getMessageFromDB( self::$mHijriCalendarMonthMsgs[$key-1] );
00545 }
00546
00555 function userAdjust( $ts, $tz = false ) {
00556 global $wgUser, $wgLocalTZoffset;
00557
00558 if ( $tz === false ) {
00559 $tz = $wgUser->getOption( 'timecorrection' );
00560 }
00561
00562 $data = explode( '|', $tz, 3 );
00563
00564 if ( $data[0] == 'ZoneInfo' ) {
00565 if ( function_exists( 'timezone_open' ) && @timezone_open( $data[2] ) !== false ) {
00566 $date = date_create( $ts, timezone_open( 'UTC' ) );
00567 date_timezone_set( $date, timezone_open( $data[2] ) );
00568 $date = date_format( $date, 'YmdHis' );
00569 return $date;
00570 }
00571 # Unrecognized timezone, default to 'Offset' with the stored offset.
00572 $data[0] = 'Offset';
00573 }
00574
00575 $minDiff = 0;
00576 if ( $data[0] == 'System' || $tz == '' ) {
00577 # Global offset in minutes.
00578 if( isset($wgLocalTZoffset) ) $minDiff = $wgLocalTZoffset;
00579 } else if ( $data[0] == 'Offset' ) {
00580 $minDiff = intval( $data[1] );
00581 } else {
00582 $data = explode( ':', $tz );
00583 if( count( $data ) == 2 ) {
00584 $data[0] = intval( $data[0] );
00585 $data[1] = intval( $data[1] );
00586 $minDiff = abs( $data[0] ) * 60 + $data[1];
00587 if ( $data[0] < 0 ) $minDiff = -$minDiff;
00588 } else {
00589 $minDiff = intval( $data[0] ) * 60;
00590 }
00591 }
00592
00593 # No difference ? Return time unchanged
00594 if ( 0 == $minDiff ) return $ts;
00595
00596 wfSuppressWarnings();
00597 # Generate an adjusted date; take advantage of the fact that mktime
00598 # will normalize out-of-range values so we don't have to split $minDiff
00599 # into hours and minutes.
00600 $t = mktime( (
00601 (int)substr( $ts, 8, 2) ), # Hours
00602 (int)substr( $ts, 10, 2 ) + $minDiff, # Minutes
00603 (int)substr( $ts, 12, 2 ), # Seconds
00604 (int)substr( $ts, 4, 2 ), # Month
00605 (int)substr( $ts, 6, 2 ), # Day
00606 (int)substr( $ts, 0, 4 ) ); #Year
00607
00608 $date = date( 'YmdHis', $t );
00609 wfRestoreWarnings();
00610
00611 return $date;
00612 }
00613
00675 function sprintfDate( $format, $ts ) {
00676 $s = '';
00677 $raw = false;
00678 $roman = false;
00679 $hebrewNum = false;
00680 $unix = false;
00681 $rawToggle = false;
00682 $iranian = false;
00683 $hebrew = false;
00684 $hijri = false;
00685 $thai = false;
00686 $minguo = false;
00687 $tenno = false;
00688 for ( $p = 0; $p < strlen( $format ); $p++ ) {
00689 $num = false;
00690 $code = $format[$p];
00691 if ( $code == 'x' && $p < strlen( $format ) - 1 ) {
00692 $code .= $format[++$p];
00693 }
00694
00695 if ( ( $code === 'xi' || $code == 'xj' || $code == 'xk' || $code == 'xm' || $code == 'xo' || $code == 'xt' ) && $p < strlen( $format ) - 1 ) {
00696 $code .= $format[++$p];
00697 }
00698
00699 switch ( $code ) {
00700 case 'xx':
00701 $s .= 'x';
00702 break;
00703 case 'xn':
00704 $raw = true;
00705 break;
00706 case 'xN':
00707 $rawToggle = !$rawToggle;
00708 break;
00709 case 'xr':
00710 $roman = true;
00711 break;
00712 case 'xh':
00713 $hebrewNum = true;
00714 break;
00715 case 'xg':
00716 $s .= $this->getMonthNameGen( substr( $ts, 4, 2 ) );
00717 break;
00718 case 'xjx':
00719 if ( !$hebrew ) $hebrew = self::tsToHebrew( $ts );
00720 $s .= $this->getHebrewCalendarMonthNameGen( $hebrew[1] );
00721 break;
00722 case 'd':
00723 $num = substr( $ts, 6, 2 );
00724 break;
00725 case 'D':
00726 if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
00727 $s .= $this->getWeekdayAbbreviation( gmdate( 'w', $unix ) + 1 );
00728 break;
00729 case 'j':
00730 $num = intval( substr( $ts, 6, 2 ) );
00731 break;
00732 case 'xij':
00733 if ( !$iranian ) $iranian = self::tsToIranian( $ts );
00734 $num = $iranian[2];
00735 break;
00736 case 'xmj':
00737 if ( !$hijri ) $hijri = self::tsToHijri( $ts );
00738 $num = $hijri[2];
00739 break;
00740 case 'xjj':
00741 if ( !$hebrew ) $hebrew = self::tsToHebrew( $ts );
00742 $num = $hebrew[2];
00743 break;
00744 case 'l':
00745 if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
00746 $s .= $this->getWeekdayName( gmdate( 'w', $unix ) + 1 );
00747 break;
00748 case 'N':
00749 if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
00750 $w = gmdate( 'w', $unix );
00751 $num = $w ? $w : 7;
00752 break;
00753 case 'w':
00754 if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
00755 $num = gmdate( 'w', $unix );
00756 break;
00757 case 'z':
00758 if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
00759 $num = gmdate( 'z', $unix );
00760 break;
00761 case 'W':
00762 if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
00763 $num = gmdate( 'W', $unix );
00764 break;
00765 case 'F':
00766 $s .= $this->getMonthName( substr( $ts, 4, 2 ) );
00767 break;
00768 case 'xiF':
00769 if ( !$iranian ) $iranian = self::tsToIranian( $ts );
00770 $s .= $this->getIranianCalendarMonthName( $iranian[1] );
00771 break;
00772 case 'xmF':
00773 if ( !$hijri ) $hijri = self::tsToHijri( $ts );
00774 $s .= $this->getHijriCalendarMonthName( $hijri[1] );
00775 break;
00776 case 'xjF':
00777 if ( !$hebrew ) $hebrew = self::tsToHebrew( $ts );
00778 $s .= $this->getHebrewCalendarMonthName( $hebrew[1] );
00779 break;
00780 case 'm':
00781 $num = substr( $ts, 4, 2 );
00782 break;
00783 case 'M':
00784 $s .= $this->getMonthAbbreviation( substr( $ts, 4, 2 ) );
00785 break;
00786 case 'n':
00787 $num = intval( substr( $ts, 4, 2 ) );
00788 break;
00789 case 'xin':
00790 if ( !$iranian ) $iranian = self::tsToIranian( $ts );
00791 $num = $iranian[1];
00792 break;
00793 case 'xmn':
00794 if ( !$hijri ) $hijri = self::tsToHijri ( $ts );
00795 $num = $hijri[1];
00796 break;
00797 case 'xjn':
00798 if ( !$hebrew ) $hebrew = self::tsToHebrew( $ts );
00799 $num = $hebrew[1];
00800 break;
00801 case 't':
00802 if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
00803 $num = gmdate( 't', $unix );
00804 break;
00805 case 'xjt':
00806 if ( !$hebrew ) $hebrew = self::tsToHebrew( $ts );
00807 $num = $hebrew[3];
00808 break;
00809 case 'L':
00810 if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
00811 $num = gmdate( 'L', $unix );
00812 break;
00813 # 'o' is supported since PHP 5.1.0
00814 # return literal if not supported
00815 # TODO: emulation for pre 5.1.0 versions
00816 case 'o':
00817 if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
00818 if ( version_compare(PHP_VERSION, '5.1.0') === 1 )
00819 $num = date( 'o', $unix );
00820 else
00821 $s .= 'o';
00822 break;
00823 case 'Y':
00824 $num = substr( $ts, 0, 4 );
00825 break;
00826 case 'xiY':
00827 if ( !$iranian ) $iranian = self::tsToIranian( $ts );
00828 $num = $iranian[0];
00829 break;
00830 case 'xmY':
00831 if ( !$hijri ) $hijri = self::tsToHijri( $ts );
00832 $num = $hijri[0];
00833 break;
00834 case 'xjY':
00835 if ( !$hebrew ) $hebrew = self::tsToHebrew( $ts );
00836 $num = $hebrew[0];
00837 break;
00838 case 'xkY':
00839 if ( !$thai ) $thai = self::tsToYear( $ts, 'thai' );
00840 $num = $thai[0];
00841 break;
00842 case 'xoY':
00843 if ( !$minguo ) $minguo = self::tsToYear( $ts, 'minguo' );
00844 $num = $minguo[0];
00845 break;
00846 case 'xtY':
00847 if ( !$tenno ) $tenno = self::tsToYear( $ts, 'tenno' );
00848 $num = $tenno[0];
00849 break;
00850 case 'y':
00851 $num = substr( $ts, 2, 2 );
00852 break;
00853 case 'a':
00854 $s .= intval( substr( $ts, 8, 2 ) ) < 12 ? 'am' : 'pm';
00855 break;
00856 case 'A':
00857 $s .= intval( substr( $ts, 8, 2 ) ) < 12 ? 'AM' : 'PM';
00858 break;
00859 case 'g':
00860 $h = substr( $ts, 8, 2 );
00861 $num = $h % 12 ? $h % 12 : 12;
00862 break;
00863 case 'G':
00864 $num = intval( substr( $ts, 8, 2 ) );
00865 break;
00866 case 'h':
00867 $h = substr( $ts, 8, 2 );
00868 $num = sprintf( '%02d', $h % 12 ? $h % 12 : 12 );
00869 break;
00870 case 'H':
00871 $num = substr( $ts, 8, 2 );
00872 break;
00873 case 'i':
00874 $num = substr( $ts, 10, 2 );
00875 break;
00876 case 's':
00877 $num = substr( $ts, 12, 2 );
00878 break;
00879 case 'c':
00880 if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
00881 $s .= gmdate( 'c', $unix );
00882 break;
00883 case 'r':
00884 if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
00885 $s .= gmdate( 'r', $unix );
00886 break;
00887 case 'U':
00888 if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
00889 $num = $unix;
00890 break;
00891 case '\\':
00892 # Backslash escaping
00893 if ( $p < strlen( $format ) - 1 ) {
00894 $s .= $format[++$p];
00895 } else {
00896 $s .= '\\';
00897 }
00898 break;
00899 case '"':
00900 # Quoted literal
00901 if ( $p < strlen( $format ) - 1 ) {
00902 $endQuote = strpos( $format, '"', $p + 1 );
00903 if ( $endQuote === false ) {
00904 # No terminating quote, assume literal "
00905 $s .= '"';
00906 } else {
00907 $s .= substr( $format, $p + 1, $endQuote - $p - 1 );
00908 $p = $endQuote;
00909 }
00910 } else {
00911 # Quote at end of string, assume literal "
00912 $s .= '"';
00913 }
00914 break;
00915 default:
00916 $s .= $format[$p];
00917 }
00918 if ( $num !== false ) {
00919 if ( $rawToggle || $raw ) {
00920 $s .= $num;
00921 $raw = false;
00922 } elseif ( $roman ) {
00923 $s .= self::romanNumeral( $num );
00924 $roman = false;
00925 } elseif( $hebrewNum ) {
00926 $s .= self::hebrewNumeral( $num );
00927 $hebrewNum = false;
00928 } else {
00929 $s .= $this->formatNum( $num, true );
00930 }
00931 $num = false;
00932 }
00933 }
00934 return $s;
00935 }
00936
00937 private static $GREG_DAYS = array( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
00938 private static $IRANIAN_DAYS = array( 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 );
00947 private static function tsToIranian( $ts ) {
00948 $gy = substr( $ts, 0, 4 ) -1600;
00949 $gm = substr( $ts, 4, 2 ) -1;
00950 $gd = substr( $ts, 6, 2 ) -1;
00951
00952 # Days passed from the beginning (including leap years)
00953 $gDayNo = 365*$gy
00954 + floor(($gy+3) / 4)
00955 - floor(($gy+99) / 100)
00956 + floor(($gy+399) / 400);
00957
00958
00959
00960 for( $i = 0; $i < $gm; $i++ ) {
00961 $gDayNo += self::$GREG_DAYS[$i];
00962 }
00963
00964
00965 if ( $gm > 1 && (($gy%4===0 && $gy%100!==0 || ($gy%400==0)))) {
00966 $gDayNo++;
00967 }
00968
00969
00970 $gDayNo += $gd;
00971
00972 $jDayNo = $gDayNo - 79;
00973
00974 $jNp = floor($jDayNo / 12053);
00975 $jDayNo %= 12053;
00976
00977 $jy = 979 + 33*$jNp + 4*floor($jDayNo/1461);
00978 $jDayNo %= 1461;
00979
00980 if ( $jDayNo >= 366 ) {
00981 $jy += floor(($jDayNo-1)/365);
00982 $jDayNo = floor(($jDayNo-1)%365);
00983 }
00984
00985 for ( $i = 0; $i < 11 && $jDayNo >= self::$IRANIAN_DAYS[$i]; $i++ ) {
00986 $jDayNo -= self::$IRANIAN_DAYS[$i];
00987 }
00988
00989 $jm= $i+1;
00990 $jd= $jDayNo+1;
00991
00992 return array($jy, $jm, $jd);
00993 }
01001 private static function tsToHijri ( $ts ) {
01002 $year = substr( $ts, 0, 4 );
01003 $month = substr( $ts, 4, 2 );
01004 $day = substr( $ts, 6, 2 );
01005
01006 $zyr = $year;
01007 $zd=$day;
01008 $zm=$month;
01009 $zy=$zyr;
01010
01011
01012
01013 if (($zy>1582)||(($zy==1582)&&($zm>10))||(($zy==1582)&&($zm==10)&&($zd>14)))
01014 {
01015
01016
01017 $zjd=(int)((1461*($zy + 4800 + (int)( ($zm-14) /12) ))/4) + (int)((367*($zm-2-12*((int)(($zm-14)/12))))/12)-(int)((3*(int)(( ($zy+4900+(int)(($zm-14)/12))/100)))/4)+$zd-32075;
01018 }
01019 else
01020 {
01021 $zjd = 367*$zy-(int)((7*($zy+5001+(int)(($zm-9)/7)))/4)+(int)((275*$zm)/9)+$zd+1729777;
01022 }
01023
01024 $zl=$zjd-1948440+10632;
01025 $zn=(int)(($zl-1)/10631);
01026 $zl=$zl-10631*$zn+354;
01027 $zj=((int)((10985-$zl)/5316))*((int)((50*$zl)/17719))+((int)($zl/5670))*((int)((43*$zl)/15238));
01028 $zl=$zl-((int)((30-$zj)/15))*((int)((17719*$zj)/50))-((int)($zj/16))*((int)((15238*$zj)/43))+29;
01029 $zm=(int)((24*$zl)/709);
01030 $zd=$zl-(int)((709*$zm)/24);
01031 $zy=30*$zn+$zj-30;
01032
01033 return array ($zy, $zm, $zd);
01034 }
01035
01047 private static function tsToHebrew( $ts ) {
01048 # Parse date
01049 $year = substr( $ts, 0, 4 );
01050 $month = substr( $ts, 4, 2 );
01051 $day = substr( $ts, 6, 2 );
01052
01053 # Calculate Hebrew year
01054 $hebrewYear = $year + 3760;
01055
01056 # Month number when September = 1, August = 12
01057 $month += 4;
01058 if( $month > 12 ) {
01059 # Next year
01060 $month -= 12;
01061 $year++;
01062 $hebrewYear++;
01063 }
01064
01065 # Calculate day of year from 1 September
01066 $dayOfYear = $day;
01067 for( $i = 1; $i < $month; $i++ ) {
01068 if( $i == 6 ) {
01069 # February
01070 $dayOfYear += 28;
01071 # Check if the year is leap
01072 if( $year % 400 == 0 || ( $year % 4 == 0 && $year % 100 > 0 ) ) {
01073 $dayOfYear++;
01074 }
01075 } elseif( $i == 8 || $i == 10 || $i == 1 || $i == 3 ) {
01076 $dayOfYear += 30;
01077 } else {
01078 $dayOfYear += 31;
01079 }
01080 }
01081
01082 # Calculate the start of the Hebrew year
01083 $start = self::hebrewYearStart( $hebrewYear );
01084
01085 # Calculate next year's start
01086 if( $dayOfYear <= $start ) {
01087 # Day is before the start of the year - it is the previous year
01088 # Next year's start
01089 $nextStart = $start;
01090 # Previous year
01091 $year--;
01092 $hebrewYear--;
01093 # Add days since previous year's 1 September
01094 $dayOfYear += 365;
01095 if( ( $year % 400 == 0 ) || ( $year % 100 != 0 && $year % 4 == 0 ) ) {
01096 # Leap year
01097 $dayOfYear++;
01098 }
01099 # Start of the new (previous) year
01100 $start = self::hebrewYearStart( $hebrewYear );
01101 } else {
01102 # Next year's start
01103 $nextStart = self::hebrewYearStart( $hebrewYear + 1 );
01104 }
01105
01106 # Calculate Hebrew day of year
01107 $hebrewDayOfYear = $dayOfYear - $start;
01108
01109 # Difference between year's days
01110 $diff = $nextStart - $start;
01111 # Add 12 (or 13 for leap years) days to ignore the difference between
01112 # Hebrew and Gregorian year (353 at least vs. 365/6) - now the
01113 # difference is only about the year type
01114 if( ( $year % 400 == 0 ) || ( $year % 100 != 0 && $year % 4 == 0 ) ) {
01115 $diff += 13;
01116 } else {
01117 $diff += 12;
01118 }
01119
01120 # Check the year pattern, and is leap year
01121 # 0 means an incomplete year, 1 means a regular year, 2 means a complete year
01122 # This is mod 30, to work on both leap years (which add 30 days of Adar I)
01123 # and non-leap years
01124 $yearPattern = $diff % 30;
01125 # Check if leap year
01126 $isLeap = $diff >= 30;
01127
01128 # Calculate day in the month from number of day in the Hebrew year
01129 # Don't check Adar - if the day is not in Adar, we will stop before;
01130 # if it is in Adar, we will use it to check if it is Adar I or Adar II
01131 $hebrewDay = $hebrewDayOfYear;
01132 $hebrewMonth = 1;
01133 $days = 0;
01134 while( $hebrewMonth <= 12 ) {
01135 # Calculate days in this month
01136 if( $isLeap && $hebrewMonth == 6 ) {
01137 # Adar in a leap year
01138 if( $isLeap ) {
01139 # Leap year - has Adar I, with 30 days, and Adar II, with 29 days
01140 $days = 30;
01141 if( $hebrewDay <= $days ) {
01142 # Day in Adar I
01143 $hebrewMonth = 13;
01144 } else {
01145 # Subtract the days of Adar I
01146 $hebrewDay -= $days;
01147 # Try Adar II
01148 $days = 29;
01149 if( $hebrewDay <= $days ) {
01150 # Day in Adar II
01151 $hebrewMonth = 14;
01152 }
01153 }
01154 }
01155 } elseif( $hebrewMonth == 2 && $yearPattern == 2 ) {
01156 # Cheshvan in a complete year (otherwise as the rule below)
01157 $days = 30;
01158 } elseif( $hebrewMonth == 3 && $yearPattern == 0 ) {
01159 # Kislev in an incomplete year (otherwise as the rule below)
01160 $days = 29;
01161 } else {
01162 # Odd months have 30 days, even have 29
01163 $days = 30 - ( $hebrewMonth - 1 ) % 2;
01164 }
01165 if( $hebrewDay <= $days ) {
01166 # In the current month
01167 break;
01168 } else {
01169 # Subtract the days of the current month
01170 $hebrewDay -= $days;
01171 # Try in the next month
01172 $hebrewMonth++;
01173 }
01174 }
01175
01176 return array( $hebrewYear, $hebrewMonth, $hebrewDay, $days );
01177 }
01178
01184 private static function hebrewYearStart( $year ) {
01185 $a = intval( ( 12 * ( $year - 1 ) + 17 ) % 19 );
01186 $b = intval( ( $year - 1 ) % 4 );
01187 $m = 32.044093161144 + 1.5542417966212 * $a + $b / 4.0 - 0.0031777940220923 * ( $year - 1 );
01188 if( $m < 0 ) {
01189 $m--;
01190 }
01191 $Mar = intval( $m );
01192 if( $m < 0 ) {
01193 $m++;
01194 }
01195 $m -= $Mar;
01196
01197 $c = intval( ( $Mar + 3 * ( $year - 1 ) + 5 * $b + 5 ) % 7);
01198 if( $c == 0 && $a > 11 && $m >= 0.89772376543210 ) {
01199 $Mar++;
01200 } else if( $c == 1 && $a > 6 && $m >= 0.63287037037037 ) {
01201 $Mar += 2;
01202 } else if( $c == 2 || $c == 4 || $c == 6 ) {
01203 $Mar++;
01204 }
01205
01206 $Mar += intval( ( $year - 3761 ) / 100 ) - intval( ( $year - 3761 ) / 400 ) - 24;
01207 return $Mar;
01208 }
01209
01221 private static function tsToYear( $ts, $cName ) {
01222 $gy = substr( $ts, 0, 4 );
01223 $gm = substr( $ts, 4, 2 );
01224 $gd = substr( $ts, 6, 2 );
01225
01226 if (!strcmp($cName,'thai')) {
01227 # Thai solar dates
01228 # Add 543 years to the Gregorian calendar
01229 # Months and days are identical
01230 $gy_offset = $gy + 543;
01231 } else if ((!strcmp($cName,'minguo')) || !strcmp($cName,'juche')) {
01232 # Minguo dates
01233 # Deduct 1911 years from the Gregorian calendar
01234 # Months and days are identical
01235 $gy_offset = $gy - 1911;
01236 } else if (!strcmp($cName,'tenno')) {
01237 # Nengō dates up to Meiji period
01238 # Deduct years from the Gregorian calendar
01239 # depending on the nengo periods
01240 # Months and days are identical
01241 if (($gy < 1912) || (($gy == 1912) && ($gm < 7)) || (($gy == 1912) && ($gm == 7) && ($gd < 31))) {
01242 # Meiji period
01243 $gy_gannen = $gy - 1868 + 1;
01244 $gy_offset = $gy_gannen;
01245 if ($gy_gannen == 1)
01246 $gy_offset = '元';
01247 $gy_offset = '明治'.$gy_offset;
01248 } else if ((($gy == 1912) && ($gm == 7) && ($gd == 31)) || (($gy == 1912) && ($gm >= 8)) || (($gy > 1912) && ($gy < 1926)) || (($gy == 1926) && ($gm < 12)) || (($gy == 1926) && ($gm == 12) && ($gd < 26))) {
01249 # Taishō period
01250 $gy_gannen = $gy - 1912 + 1;
01251 $gy_offset = $gy_gannen;
01252 if ($gy_gannen == 1)
01253 $gy_offset = '元';
01254 $gy_offset = '大正'.$gy_offset;
01255 } else if ((($gy == 1926) && ($gm == 12) && ($gd >= 26)) || (($gy > 1926) && ($gy < 1989)) || (($gy == 1989) && ($gm == 1) && ($gd < 8))) {
01256 # Shōwa period
01257 $gy_gannen = $gy - 1926 + 1;
01258 $gy_offset = $gy_gannen;
01259 if ($gy_gannen == 1)
01260 $gy_offset = '元';
01261 $gy_offset = '昭和'.$gy_offset;
01262 } else {
01263 # Heisei period
01264 $gy_gannen = $gy - 1989 + 1;
01265 $gy_offset = $gy_gannen;
01266 if ($gy_gannen == 1)
01267 $gy_offset = '元';
01268 $gy_offset = '平成'.$gy_offset;
01269 }
01270 } else {
01271 $gy_offset = $gy;
01272 }
01273
01274 return array( $gy_offset, $gm, $gd );
01275 }
01276
01280 static function romanNumeral( $num ) {
01281 static $table = array(
01282 array( '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X' ),
01283 array( '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC', 'C' ),
01284 array( '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM', 'M' ),
01285 array( '', 'M', 'MM', 'MMM' )
01286 );
01287
01288 $num = intval( $num );
01289 if ( $num > 3000 || $num <= 0 ) {
01290 return $num;
01291 }
01292
01293 $s = '';
01294 for ( $pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i-- ) {
01295 if ( $num >= $pow10 ) {
01296 $s .= $table[$i][floor($num / $pow10)];
01297 }
01298 $num = $num % $pow10;
01299 }
01300 return $s;
01301 }
01302
01306 static function hebrewNumeral( $num ) {
01307 static $table = array(
01308 array( '', 'א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י' ),
01309 array( '', 'י', 'כ', 'ל', 'מ', 'נ', 'ס', 'ע', 'פ', 'צ', 'ק' ),
01310 array( '', 'ק', 'ר', 'ש', 'ת', 'תק', 'תר', 'תש', 'תת', 'תתק', 'תתר' ),
01311 array( '', 'א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י' )
01312 );
01313
01314 $num = intval( $num );
01315 if ( $num > 9999 || $num <= 0 ) {
01316 return $num;
01317 }
01318
01319 $s = '';
01320 for ( $pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i-- ) {
01321 if ( $num >= $pow10 ) {
01322 if ( $num == 15 || $num == 16 ) {
01323 $s .= $table[0][9] . $table[0][$num - 9];
01324 $num = 0;
01325 } else {
01326 $s .= $table[$i][intval( ( $num / $pow10 ) )];
01327 if( $pow10 == 1000 ) {
01328 $s .= "'";
01329 }
01330 }
01331 }
01332 $num = $num % $pow10;
01333 }
01334 if( strlen( $s ) == 2 ) {
01335 $str = $s . "'";
01336 } else {
01337 $str = substr( $s, 0, strlen( $s ) - 2 ) . '"';
01338 $str .= substr( $s, strlen( $s ) - 2, 2 );
01339 }
01340 $start = substr( $str, 0, strlen( $str ) - 2 );
01341 $end = substr( $str, strlen( $str ) - 2 );
01342 switch( $end ) {
01343 case 'כ':
01344 $str = $start . 'ך';
01345 break;
01346 case 'מ':
01347 $str = $start . 'ם';
01348 break;
01349 case 'נ':
01350 $str = $start . 'ן';
01351 break;
01352 case 'פ':
01353 $str = $start . 'ף';
01354 break;
01355 case 'צ':
01356 $str = $start . 'ץ';
01357 break;
01358 }
01359 return $str;
01360 }
01361
01379 function dateFormat( $usePrefs = true ) {
01380 global $wgUser;
01381
01382 if( is_bool( $usePrefs ) ) {
01383 if( $usePrefs ) {
01384 $datePreference = $wgUser->getDatePreference();
01385 } else {
01386 $options = User::getDefaultOptions();
01387 $datePreference = (string)$options['date'];
01388 }
01389 } else {
01390 $datePreference = (string)$usePrefs;
01391 }
01392
01393
01394 if( $datePreference == '' ) {
01395 return 'default';
01396 }
01397
01398 return $datePreference;
01399 }
01400
01406 function getDateFormatString( $type, $pref ) {
01407 if ( !isset( $this->dateFormatStrings[$type][$pref] ) ) {
01408 if ( $pref == 'default' ) {
01409 $pref = $this->getDefaultDateFormat();
01410 $df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
01411 } else {
01412 $df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
01413 if ( is_null( $df ) ) {
01414 $pref = $this->getDefaultDateFormat();
01415 $df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
01416 }
01417 }
01418 $this->dateFormatStrings[$type][$pref] = $df;
01419 }
01420 return $this->dateFormatStrings[$type][$pref];
01421 }
01422
01433 function date( $ts, $adj = false, $format = true, $timecorrection = false ) {
01434 if ( $adj ) {
01435 $ts = $this->userAdjust( $ts, $timecorrection );
01436 }
01437 $df = $this->getDateFormatString( 'date', $this->dateFormat( $format ) );
01438 return $this->sprintfDate( $df, $ts );
01439 }
01440
01451 function time( $ts, $adj = false, $format = true, $timecorrection = false ) {
01452 if ( $adj ) {
01453 $ts = $this->userAdjust( $ts, $timecorrection );
01454 }
01455 $df = $this->getDateFormatString( 'time', $this->dateFormat( $format ) );
01456 return $this->sprintfDate( $df, $ts );
01457 }
01458
01470 function timeanddate( $ts, $adj = false, $format = true, $timecorrection = false) {
01471 $ts = wfTimestamp( TS_MW, $ts );
01472 if ( $adj ) {
01473 $ts = $this->userAdjust( $ts, $timecorrection );
01474 }
01475 $df = $this->getDateFormatString( 'both', $this->dateFormat( $format ) );
01476 return $this->sprintfDate( $df, $ts );
01477 }
01478
01479 function getMessage( $key ) {
01480 return self::$dataCache->getSubitem( $this->mCode, 'messages', $key );
01481 }
01482
01483 function getAllMessages() {
01484 return self::$dataCache->getItem( $this->mCode, 'messages' );
01485 }
01486
01487 function iconv( $in, $out, $string ) {
01488 # This is a wrapper for iconv in all languages except esperanto,
01489 # which does some nasty x-conversions beforehand
01490
01491 # Even with //IGNORE iconv can whine about illegal characters in
01492 # *input* string. We just ignore those too.
01493 # REF: http://bugs.php.net/bug.php?id=37166
01494 # REF: https://bugzilla.wikimedia.org/show_bug.cgi?id=16885
01495 wfSuppressWarnings();
01496 $text = iconv( $in, $out . '//IGNORE', $string );
01497 wfRestoreWarnings();
01498 return $text;
01499 }
01500
01501
01502 function ucwordbreaksCallbackAscii($matches){
01503 return $this->ucfirst($matches[1]);
01504 }
01505
01506 function ucwordbreaksCallbackMB($matches){
01507 return mb_strtoupper($matches[0]);
01508 }
01509
01510 function ucCallback($matches){
01511 list( $wikiUpperChars ) = self::getCaseMaps();
01512 return strtr( $matches[1], $wikiUpperChars );
01513 }
01514
01515 function lcCallback($matches){
01516 list( , $wikiLowerChars ) = self::getCaseMaps();
01517 return strtr( $matches[1], $wikiLowerChars );
01518 }
01519
01520 function ucwordsCallbackMB($matches){
01521 return mb_strtoupper($matches[0]);
01522 }
01523
01524 function ucwordsCallbackWiki($matches){
01525 list( $wikiUpperChars ) = self::getCaseMaps();
01526 return strtr( $matches[0], $wikiUpperChars );
01527 }
01528
01529 function ucfirst( $str ) {
01530 $o = ord( $str );
01531 if ( $o < 96 ) {
01532 return $str;
01533 } elseif ( $o < 128 ) {
01534 return ucfirst($str);
01535 } else {
01536
01537 return self::uc($str,true);
01538 }
01539 }
01540
01541 function uc( $str, $first = false ) {
01542 if ( function_exists( 'mb_strtoupper' ) ) {
01543 if ( $first ) {
01544 if ( self::isMultibyte( $str ) ) {
01545 return mb_strtoupper( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 );
01546 } else {
01547 return ucfirst( $str );
01548 }
01549 } else {
01550 return self::isMultibyte( $str ) ? mb_strtoupper( $str ) : strtoupper( $str );
01551 }
01552 } else {
01553 if ( self::isMultibyte( $str ) ) {
01554 list( $wikiUpperChars ) = $this->getCaseMaps();
01555 $x = $first ? '^' : '';
01556 return preg_replace_callback(
01557 "/$x([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/",
01558 array($this,"ucCallback"),
01559 $str
01560 );
01561 } else {
01562 return $first ? ucfirst( $str ) : strtoupper( $str );
01563 }
01564 }
01565 }
01566
01567 function lcfirst( $str ) {
01568 $o = ord( $str );
01569 if ( !$o ) {
01570 return strval( $str );
01571 } elseif ( $o >= 128 ) {
01572 return self::lc( $str, true );
01573 } elseif ( $o > 96 ) {
01574 return $str;
01575 } else {
01576 $str[0] = strtolower( $str[0] );
01577 return $str;
01578 }
01579 }
01580
01581 function lc( $str, $first = false ) {
01582 if ( function_exists( 'mb_strtolower' ) )
01583 if ( $first )
01584 if ( self::isMultibyte( $str ) )
01585 return mb_strtolower( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 );
01586 else
01587 return strtolower( substr( $str, 0, 1 ) ) . substr( $str, 1 );
01588 else
01589 return self::isMultibyte( $str ) ? mb_strtolower( $str ) : strtolower( $str );
01590 else
01591 if ( self::isMultibyte( $str ) ) {
01592 list( , $wikiLowerChars ) = self::getCaseMaps();
01593 $x = $first ? '^' : '';
01594 return preg_replace_callback(
01595 "/$x([A-Z]|[\\xc0-\\xff][\\x80-\\xbf]*)/",
01596 array($this,"lcCallback"),
01597 $str
01598 );
01599 } else
01600 return $first ? strtolower( substr( $str, 0, 1 ) ) . substr( $str, 1 ) : strtolower( $str );
01601 }
01602
01603 function isMultibyte( $str ) {
01604 return (bool)preg_match( '/[\x80-\xff]/', $str );
01605 }
01606
01607 function ucwords($str) {
01608 if ( self::isMultibyte( $str ) ) {
01609 $str = self::lc($str);
01610
01611
01612 $replaceRegexp = "/^([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)| ([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/";
01613
01614
01615 if ( function_exists( 'mb_strtoupper' ) )
01616 return preg_replace_callback(
01617 $replaceRegexp,
01618 array($this,"ucwordsCallbackMB"),
01619 $str
01620 );
01621 else
01622 return preg_replace_callback(
01623 $replaceRegexp,
01624 array($this,"ucwordsCallbackWiki"),
01625 $str
01626 );
01627 }
01628 else
01629 return ucwords( strtolower( $str ) );
01630 }
01631
01632 # capitalize words at word breaks
01633 function ucwordbreaks($str){
01634 if (self::isMultibyte( $str ) ) {
01635 $str = self::lc($str);
01636
01637
01638 $breaks= "[ \-\(\)\}\{\.,\?!]";
01639
01640
01641 $replaceRegexp = "/^([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)|$breaks([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/";
01642
01643 if ( function_exists( 'mb_strtoupper' ) )
01644 return preg_replace_callback(
01645 $replaceRegexp,
01646 array($this,"ucwordbreaksCallbackMB"),
01647 $str
01648 );
01649 else
01650 return preg_replace_callback(
01651 $replaceRegexp,
01652 array($this,"ucwordsCallbackWiki"),
01653 $str
01654 );
01655 }
01656 else
01657 return preg_replace_callback(
01658 '/\b([\w\x80-\xff]+)\b/',
01659 array($this,"ucwordbreaksCallbackAscii"),
01660 $str );
01661 }
01662
01674 function caseFold( $s ) {
01675 return $this->uc( $s );
01676 }
01677
01678 function checkTitleEncoding( $s ) {
01679 if( is_array( $s ) ) {
01680 wfDebugDieBacktrace( 'Given array to checkTitleEncoding.' );
01681 }
01682 # Check for non-UTF-8 URLs
01683 $ishigh = preg_match( '/[\x80-\xff]/', $s);
01684 if(!$ishigh) return $s;
01685
01686 $isutf8 = preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
01687 '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s );
01688 if( $isutf8 ) return $s;
01689
01690 return $this->iconv( $this->fallback8bitEncoding(), "utf-8", $s );
01691 }
01692
01693 function fallback8bitEncoding() {
01694 return self::$dataCache->getItem( $this->mCode, 'fallback8bitEncoding' );
01695 }
01696
01703 function hasWordBreaks() {
01704 return true;
01705 }
01706
01714 function wordSegmentation( $string ) {
01715 return $string;
01716 }
01717
01725 function normalizeForSearch( $string ) {
01726 return $string;
01727 }
01728
01733 protected static function convertDoubleWidth( $string ) {
01734 $string = preg_replace( '/\xef\xbc([\x80-\xbf])/e', 'chr((ord("$1") & 0x3f) + 0x20)', $string );
01735 $string = preg_replace( '/\xef\xbd([\x80-\x99])/e', 'chr((ord("$1") & 0x3f) + 0x60)', $string );
01736 return $string;
01737 }
01738
01739 protected static function insertSpace( $string, $pattern ) {
01740 $string = preg_replace( $pattern, " $1 ", $string );
01741 $string = preg_replace( '/ +/', ' ', $string );
01742 return $string;
01743 }
01744
01745 function convertForSearchResult( $termsArray ) {
01746 # some languages, e.g. Chinese, need to do a conversion
01747 # in order for search results to be displayed correctly
01748 return $termsArray;
01749 }
01750
01757 function firstChar( $s ) {
01758 $matches = array();
01759 preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
01760 '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})/', $s, $matches);
01761
01762 if ( isset( $matches[1] ) ) {
01763 if ( strlen( $matches[1] ) != 3 ) {
01764 return $matches[1];
01765 }
01766
01767
01768 $code = utf8ToCodepoint( $matches[1] );
01769 if ( $code < 0xac00 || 0xd7a4 <= $code) {
01770 return $matches[1];
01771 } elseif ( $code < 0xb098 ) {
01772 return "\xe3\x84\xb1";
01773 } elseif ( $code < 0xb2e4 ) {
01774 return "\xe3\x84\xb4";
01775 } elseif ( $code < 0xb77c ) {
01776 return "\xe3\x84\xb7";
01777 } elseif ( $code < 0xb9c8 ) {
01778 return "\xe3\x84\xb9";
01779 } elseif ( $code < 0xbc14 ) {
01780 return "\xe3\x85\x81";
01781 } elseif ( $code < 0xc0ac ) {
01782 return "\xe3\x85\x82";
01783 } elseif ( $code < 0xc544 ) {
01784 return "\xe3\x85\x85";
01785 } elseif ( $code < 0xc790 ) {
01786 return "\xe3\x85\x87";
01787 } elseif ( $code < 0xcc28 ) {
01788 return "\xe3\x85\x88";
01789 } elseif ( $code < 0xce74 ) {
01790 return "\xe3\x85\x8a";
01791 } elseif ( $code < 0xd0c0 ) {
01792 return "\xe3\x85\x8b";
01793 } elseif ( $code < 0xd30c ) {
01794 return "\xe3\x85\x8c";
01795 } elseif ( $code < 0xd558 ) {
01796 return "\xe3\x85\x8d";
01797 } else {
01798 return "\xe3\x85\x8e";
01799 }
01800 } else {
01801 return "";
01802 }
01803 }
01804
01805 function initEncoding() {
01806 # Some languages may have an alternate char encoding option
01807 # (Esperanto X-coding, Japanese furigana conversion, etc)
01808 # If this language is used as the primary content language,
01809 # an override to the defaults can be set here on startup.
01810 }
01811
01812 function recodeForEdit( $s ) {
01813 # For some languages we'll want to explicitly specify
01814 # which characters make it into the edit box raw
01815 # or are converted in some way or another.
01816 # Note that if wgOutputEncoding is different from
01817 # wgInputEncoding, this text will be further converted
01818 # to wgOutputEncoding.
01819 global $wgEditEncoding;
01820 if( $wgEditEncoding == '' or
01821 $wgEditEncoding == 'UTF-8' ) {
01822 return $s;
01823 } else {
01824 return $this->iconv( 'UTF-8', $wgEditEncoding, $s );
01825 }
01826 }
01827
01828 function recodeInput( $s ) {
01829 # Take the previous into account.
01830 global $wgEditEncoding;
01831 if($wgEditEncoding != "") {
01832 $enc = $wgEditEncoding;
01833 } else {
01834 $enc = 'UTF-8';
01835 }
01836 if( $enc == 'UTF-8' ) {
01837 return $s;
01838 } else {
01839 return $this->iconv( $enc, 'UTF-8', $s );
01840 }
01841 }
01842
01850 function normalize( $s ) {
01851 return UtfNormal::cleanUp( $s );
01852 }
01853
01862 function transformUsingPairFile( $file, $string ) {
01863 if ( !isset( $this->transformData[$file] ) ) {
01864 $data = wfGetPrecompiledData( $file );
01865 if ( $data === false ) {
01866 throw new MWException( __METHOD__.": The transformation file $file is missing" );
01867 }
01868 $this->transformData[$file] = new ReplacementArray( $data );
01869 }
01870 return $this->transformData[$file]->replace( $string );
01871 }
01872
01878 function isRTL() {
01879 return self::$dataCache->getItem( $this->mCode, 'rtl' );
01880 }
01881
01886 function getDir() {
01887 return $this->isRTL() ? 'rtl' : 'ltr';
01888 }
01889
01898 function alignStart() {
01899 return $this->isRTL() ? 'right' : 'left';
01900 }
01901
01910 function alignEnd() {
01911 return $this->isRTL() ? 'left' : 'right';
01912 }
01913
01919 function getDirMark() {
01920 return $this->isRTL() ? "\xE2\x80\x8F" : "\xE2\x80\x8E";
01921 }
01922
01923 function capitalizeAllNouns() {
01924 return self::$dataCache->getItem( $this->mCode, 'capitalizeAllNouns' );
01925 }
01926
01932 function getArrow() {
01933 return $this->isRTL() ? '←' : '→';
01934 }
01935
01941 function linkPrefixExtension() {
01942 return self::$dataCache->getItem( $this->mCode, 'linkPrefixExtension' );
01943 }
01944
01945 function getMagicWords() {
01946 return self::$dataCache->getItem( $this->mCode, 'magicWords' );
01947 }
01948
01949 # Fill a MagicWord object with data from here
01950 function getMagic( $mw ) {
01951 if ( !$this->mMagicHookDone ) {
01952 $this->mMagicHookDone = true;
01953 wfProfileIn( 'LanguageGetMagic' );
01954 wfRunHooks( 'LanguageGetMagic', array( &$this->mMagicExtensions, $this->getCode() ) );
01955 wfProfileOut( 'LanguageGetMagic' );
01956 }
01957 if ( isset( $this->mMagicExtensions[$mw->mId] ) ) {
01958 $rawEntry = $this->mMagicExtensions[$mw->mId];
01959 } else {
01960 $magicWords = $this->getMagicWords();
01961 if ( isset( $magicWords[$mw->mId] ) ) {
01962 $rawEntry = $magicWords[$mw->mId];
01963 } else {
01964 $rawEntry = false;
01965 }
01966 }
01967
01968 if( !is_array( $rawEntry ) ) {
01969 error_log( "\"$rawEntry\" is not a valid magic thingie for \"$mw->mId\"" );
01970 } else {
01971 $mw->mCaseSensitive = $rawEntry[0];
01972 $mw->mSynonyms = array_slice( $rawEntry, 1 );
01973 }
01974 }
01975
01979 function addMagicWordsByLang( $newWords ) {
01980 $code = $this->getCode();
01981 $fallbackChain = array();
01982 while ( $code && !in_array( $code, $fallbackChain ) ) {
01983 $fallbackChain[] = $code;
01984 $code = self::getFallbackFor( $code );
01985 }
01986 if ( !in_array( 'en', $fallbackChain ) ) {
01987 $fallbackChain[] = 'en';
01988 }
01989 $fallbackChain = array_reverse( $fallbackChain );
01990 foreach ( $fallbackChain as $code ) {
01991 if ( isset( $newWords[$code] ) ) {
01992 $this->mMagicExtensions = $newWords[$code] + $this->mMagicExtensions;
01993 }
01994 }
01995 }
01996
02001 function getSpecialPageAliases() {
02002
02003 if ( is_null( $this->mExtendedSpecialPageAliases ) ) {
02004
02005 $this->mExtendedSpecialPageAliases =
02006 self::$dataCache->getItem( $this->mCode, 'specialPageAliases' );
02007 wfRunHooks( 'LanguageGetSpecialPageAliases',
02008 array( &$this->mExtendedSpecialPageAliases, $this->getCode() ) );
02009 }
02010
02011 return $this->mExtendedSpecialPageAliases;
02012 }
02013
02020 function emphasize( $text ) {
02021 return "<em>$text</em>";
02022 }
02023
02048 function formatNum( $number, $nocommafy = false ) {
02049 global $wgTranslateNumerals;
02050 if (!$nocommafy) {
02051 $number = $this->commafy($number);
02052 $s = $this->separatorTransformTable();
02053 if ($s) { $number = strtr($number, $s); }
02054 }
02055
02056 if ($wgTranslateNumerals) {
02057 $s = $this->digitTransformTable();
02058 if ($s) { $number = strtr($number, $s); }
02059 }
02060
02061 return $number;
02062 }
02063
02064 function parseFormattedNumber( $number ) {
02065 $s = $this->digitTransformTable();
02066 if ($s) { $number = strtr($number, array_flip($s)); }
02067
02068 $s = $this->separatorTransformTable();
02069 if ($s) { $number = strtr($number, array_flip($s)); }
02070
02071 $number = strtr( $number, array (',' => '') );
02072 return $number;
02073 }
02074
02081 function commafy($_) {
02082 return strrev((string)preg_replace('/(\d{3})(?=\d)(?!\d*\.)/','$1,',strrev($_)));
02083 }
02084
02085 function digitTransformTable() {
02086 return self::$dataCache->getItem( $this->mCode, 'digitTransformTable' );
02087 }
02088
02089 function separatorTransformTable() {
02090 return self::$dataCache->getItem( $this->mCode, 'separatorTransformTable' );
02091 }
02092
02093
02102 function listToText( $l ) {
02103 $s = '';
02104 $m = count( $l ) - 1;
02105 if( $m == 1 ) {
02106 return $l[0] . $this->getMessageFromDB( 'and' ) . $this->getMessageFromDB( 'word-separator' ) . $l[1];
02107 }
02108 else {
02109 for ( $i = $m; $i >= 0; $i-- ) {
02110 if ( $i == $m ) {
02111 $s = $l[$i];
02112 } else if( $i == $m - 1 ) {
02113 $s = $l[$i] . $this->getMessageFromDB( 'and' ) . $this->getMessageFromDB( 'word-separator' ) . $s;
02114 } else {
02115 $s = $l[$i] . $this->getMessageFromDB( 'comma-separator' ) . $s;
02116 }
02117 }
02118 return $s;
02119 }
02120 }
02121
02128 function commaList( $list ) {
02129 return implode(
02130 $list,
02131 wfMsgExt( 'comma-separator', array( 'parsemag', 'escapenoentities', 'language' => $this ) ) );
02132 }
02133
02140 function semicolonList( $list ) {
02141 return implode(
02142 $list,
02143 wfMsgExt( 'semicolon-separator', array( 'parsemag', 'escapenoentities', 'language' => $this ) ) );
02144 }
02145
02151 function pipeList( $list ) {
02152 return implode(
02153 $list,
02154 wfMsgExt( 'pipe-separator', array( 'escapenoentities', 'language' => $this ) ) );
02155 }
02156
02172 function truncate( $string, $length, $ellipsis = '...' ) {
02173 # Use the localized ellipsis character
02174 if( $ellipsis == '...' ) {
02175 $ellipsis = wfMsgExt( 'ellipsis', array( 'escapenoentities', 'language' => $this ) );
02176 }
02177
02178 if( $length == 0 ) {
02179 return $ellipsis;
02180 }
02181 if ( strlen( $string ) <= abs( $length ) ) {
02182 return $string;
02183 }
02184 $stringOriginal = $string;
02185 if( $length > 0 ) {
02186 $string = substr( $string, 0, $length );
02187 $char = ord( $string[strlen( $string ) - 1] );
02188 $m = array();
02189 if ($char >= 0xc0) {
02190 # We got the first byte only of a multibyte char; remove it.
02191 $string = substr( $string, 0, -1 );
02192 } elseif( $char >= 0x80 &&
02193 preg_match( '/^(.*)(?:[\xe0-\xef][\x80-\xbf]|' .
02194 '[\xf0-\xf7][\x80-\xbf]{1,2})$/', $string, $m ) ) {
02195 # We chopped in the middle of a character; remove it
02196 $string = $m[1];
02197 }
02198 $string = $string . $ellipsis;
02199
02200 } else {
02201 $string = substr( $string, $length );
02202 $char = ord( $string[0] );
02203 if( $char >= 0x80 && $char < 0xc0 ) {
02204 # We chopped in the middle of a character; remove the whole thing
02205 $string = preg_replace( '/^[\x80-\xbf]+/', '', $string );
02206 }
02207 $string = $ellipsis . $string;
02208 }
02209 # Do not truncate if the ellipsis actually make the string longer. Bug 22181
02210 if ( strlen( $string ) < strlen( $stringOriginal ) ) {
02211 return $string;
02212 } else {
02213 return $stringOriginal;
02214 }
02215 }
02216
02225 function convertGrammar( $word, $case ) {
02226 global $wgGrammarForms;
02227 if ( isset($wgGrammarForms[$this->getCode()][$case][$word]) ) {
02228 return $wgGrammarForms[$this->getCode()][$case][$word];
02229 }
02230 return $word;
02231 }
02232
02241 function gender( $gender, $forms ) {
02242 if ( !count($forms) ) { return ''; }
02243 $forms = $this->preConvertPlural( $forms, 2 );
02244 if ( $gender === 'male' ) return $forms[0];
02245 if ( $gender === 'female' ) return $forms[1];
02246 return isset($forms[2]) ? $forms[2] : $forms[0];
02247 }
02248
02264 function convertPlural( $count, $forms ) {
02265 if ( !count($forms) ) { return ''; }
02266 $forms = $this->preConvertPlural( $forms, 2 );
02267
02268 return ( $count == 1 ) ? $forms[0] : $forms[1];
02269 }
02270
02279 protected function preConvertPlural( $forms, $count ) {
02280 while ( count($forms) < $count ) {
02281 $forms[] = $forms[count($forms)-1];
02282 }
02283 return $forms;
02284 }
02285
02292 function translateBlockExpiry( $str ) {
02293
02294 $scBlockExpiryOptions = $this->getMessageFromDB( 'ipboptions' );
02295
02296 if ( $scBlockExpiryOptions == '-') {
02297 return $str;
02298 }
02299
02300 foreach (explode(',', $scBlockExpiryOptions) as $option) {
02301 if ( strpos($option, ":") === false )
02302 continue;
02303 list($show, $value) = explode(":", $option);
02304 if ( strcmp ( $str, $value) == 0 ) {
02305 return htmlspecialchars( trim( $show ) );
02306 }
02307 }
02308
02309 return $str;
02310 }
02311
02319 function segmentForDiff( $text ) {
02320 return $text;
02321 }
02322
02329 function unsegmentForDiff( $text ) {
02330 return $text;
02331 }
02332
02333 # convert text to all supported variants
02334 function autoConvertToAllVariants($text) {
02335 return $this->mConverter->autoConvertToAllVariants($text);
02336 }
02337
02338 # convert text to different variants of a language.
02339 function convert( $text ) {
02340 return $this->mConverter->convert( $text );
02341 }
02342
02343 # Convert a Title object to a string in the preferred variant
02344 function convertTitle( $title ) {
02345 return $this->mConverter->convertTitle( $title );
02346 }
02347
02348 # Check if this is a language with variants
02349 function hasVariants(){
02350 return sizeof($this->getVariants())>1;
02351 }
02352
02353 # Put custom tags (e.g. -{ }-) around math to prevent conversion
02354 function armourMath($text){
02355 return $this->mConverter->armourMath($text);
02356 }
02357
02358
02366 function convertHtml( $text, $isTitle = false ) {
02367 return htmlspecialchars( $this->convert( $text, $isTitle ) );
02368 }
02369
02370 function convertCategoryKey( $key ) {
02371 return $this->mConverter->convertCategoryKey( $key );
02372 }
02373
02380 function getVariants() {
02381 return $this->mConverter->getVariants();
02382 }
02383
02384
02385 function getPreferredVariant( $fromUser = true, $fromHeader = false ) {
02386 return $this->mConverter->getPreferredVariant( $fromUser, $fromHeader );
02387 }
02388
02401 function findVariantLink( &$link, &$nt, $ignoreOtherCond = false ) {
02402 $this->mConverter->findVariantLink( $link, $nt, $ignoreOtherCond );
02403 }
02404
02410 function convertLinkToAllVariants($text){
02411 return $this->mConverter->convertLinkToAllVariants($text);
02412 }
02413
02414
02421 function getExtraHashOptions() {
02422 return $this->mConverter->getExtraHashOptions();
02423 }
02424
02432 function getParsedTitle() {
02433 return $this->mConverter->getParsedTitle();
02434 }
02435
02444 function markNoConversion( $text, $noParse=false ) {
02445 return $this->mConverter->markNoConversion( $text, $noParse );
02446 }
02447
02454 function linkTrail() {
02455 return self::$dataCache->getItem( $this->mCode, 'linkTrail' );
02456 }
02457
02458 function getLangObj() {
02459 return $this;
02460 }
02461
02465 function getCode() {
02466 return $this->mCode;
02467 }
02468
02469 function setCode( $code ) {
02470 $this->mCode = $code;
02471 }
02472
02480 static function getFileName( $prefix = 'Language', $code, $suffix = '.php' ) {
02481
02482 if ( !Language::isValidCode( $code )
02483 || strcspn( $code, "/\\\000" ) !== strlen( $code ) )
02484 {
02485 throw new MWException( "Invalid language code \"$code\"" );
02486 }
02487
02488 return $prefix . str_replace( '-', '_', ucfirst( $code ) ) . $suffix;
02489 }
02490
02498 static function getCodeFromFileName( $filename, $prefix = 'Language', $suffix = '.php' ) {
02499 $m = null;
02500 preg_match( '/' . preg_quote( $prefix, '/' ) . '([A-Z][a-z_]+)' .
02501 preg_quote( $suffix, '/' ) . '/', $filename, $m );
02502 if ( !count( $m ) ) {
02503 return false;
02504 }
02505 return str_replace( '_', '-', strtolower( $m[1] ) );
02506 }
02507
02508 static function getMessagesFileName( $code ) {
02509 global $IP;
02510 return self::getFileName( "$IP/languages/messages/Messages", $code, '.php' );
02511 }
02512
02513 static function getClassFileName( $code ) {
02514 global $IP;
02515 return self::getFileName( "$IP/languages/classes/Language", $code, '.php' );
02516 }
02517
02521 static function getFallbackFor( $code ) {
02522 if ( $code === 'en' ) {
02523
02524 return false;
02525 } else {
02526 return self::getLocalisationCache()->getItem( $code, 'fallback' );
02527 }
02528 }
02529
02534 static function getMessagesFor( $code ) {
02535 return self::getLocalisationCache()->getItem( $code, 'messages' );
02536 }
02537
02541 static function getMessageFor( $key, $code ) {
02542 return self::getLocalisationCache()->getSubitem( $code, 'messages', $key );
02543 }
02544
02545 function fixVariableInNamespace( $talk ) {
02546 if ( strpos( $talk, '$1' ) === false ) return $talk;
02547
02548 global $wgMetaNamespace;
02549 $talk = str_replace( '$1', $wgMetaNamespace, $talk );
02550
02551 # Allow grammar transformations
02552 # Allowing full message-style parsing would make simple requests
02553 # such as action=raw much more expensive than they need to be.
02554 # This will hopefully cover most cases.
02555 $talk = preg_replace_callback( '/{{grammar:(.*?)\|(.*?)}}/i',
02556 array( &$this, 'replaceGrammarInNamespace' ), $talk );
02557 return str_replace( ' ', '_', $talk );
02558 }
02559
02560 function replaceGrammarInNamespace( $m ) {
02561 return $this->convertGrammar( trim( $m[2] ), trim( $m[1] ) );
02562 }
02563
02564 static function getCaseMaps() {
02565 static $wikiUpperChars, $wikiLowerChars;
02566 if ( isset( $wikiUpperChars ) ) {
02567 return array( $wikiUpperChars, $wikiLowerChars );
02568 }
02569
02570 wfProfileIn( __METHOD__ );
02571 $arr = wfGetPrecompiledData( 'Utf8Case.ser' );
02572 if ( $arr === false ) {
02573 throw new MWException(
02574 "Utf8Case.ser is missing, please run \"make\" in the serialized directory\n" );
02575 }
02576 extract( $arr );
02577 wfProfileOut( __METHOD__ );
02578 return array( $wikiUpperChars, $wikiLowerChars );
02579 }
02580
02581 function formatTimePeriod( $seconds ) {
02582 if ( $seconds < 10 ) {
02583 return $this->formatNum( sprintf( "%.1f", $seconds ) ) . wfMsg( 'seconds-abbrev' );
02584 } elseif ( $seconds < 60 ) {
02585 return $this->formatNum( round( $seconds ) ) . wfMsg( 'seconds-abbrev' );
02586 } elseif ( $seconds < 3600 ) {
02587 return $this->formatNum( floor( $seconds / 60 ) ) . wfMsg( 'minutes-abbrev' ) .
02588 $this->formatNum( round( fmod( $seconds, 60 ) ) ) . wfMsg( 'seconds-abbrev' );
02589 } else {
02590 $hours = floor( $seconds / 3600 );
02591 $minutes = floor( ( $seconds - $hours * 3600 ) / 60 );
02592 $secondsPart = round( $seconds - $hours * 3600 - $minutes * 60 );
02593 return $this->formatNum( $hours ) . wfMsg( 'hours-abbrev' ) .
02594 $this->formatNum( $minutes ) . wfMsg( 'minutes-abbrev' ) .
02595 $this->formatNum( $secondsPart ) . wfMsg( 'seconds-abbrev' );
02596 }
02597 }
02598
02599 function formatBitrate( $bps ) {
02600 $units = array( 'bps', 'kbps', 'Mbps', 'Gbps' );
02601 if ( $bps <= 0 ) {
02602 return $this->formatNum( $bps ) . $units[0];
02603 }
02604 $unitIndex = floor( log10( $bps ) / 3 );
02605 $mantissa = $bps / pow( 1000, $unitIndex );
02606 if ( $mantissa < 10 ) {
02607 $mantissa = round( $mantissa, 1 );
02608 } else {
02609 $mantissa = round( $mantissa );
02610 }
02611 return $this->formatNum( $mantissa ) . $units[$unitIndex];
02612 }
02613
02621 function formatSize( $size ) {
02622
02623 $round = 0;
02624 if( $size > 1024 ) {
02625 $size = $size / 1024;
02626 if( $size > 1024 ) {
02627 $size = $size / 1024;
02628
02629 $round = 2;
02630 if( $size > 1024 ) {
02631 $size = $size / 1024;
02632 $msg = 'size-gigabytes';
02633 } else {
02634 $msg = 'size-megabytes';
02635 }
02636 } else {
02637 $msg = 'size-kilobytes';
02638 }
02639 } else {
02640 $msg = 'size-bytes';
02641 }
02642 $size = round( $size, $round );
02643 $text = $this->getMessageFromDB( $msg );
02644 return str_replace( '$1', $this->formatNum( $size ), $text );
02645 }
02646
02650 function getConvRuleTitle() {
02651 return $this->mConverter->getConvRuleTitle();
02652 }
02653 }