* @return array
*/
function getDefaultUserOptions() {
+ trigger_error( 'Use of ' . __METHOD__ . ' is deprecated', E_USER_NOTICE );
return User::getDefaultOptions();
}
* If $customisedOnly is true, only returns codes with a messages file
*/
public static function getLanguageNames( $customisedOnly = false ) {
- global $wgLanguageNames;
+ global $wgLanguageNames, $wgExtraLanguageNames;
+ $allNames = $wgExtraLanguageNames + $wgLanguageNames;
if ( !$customisedOnly ) {
- return $wgLanguageNames;
+ return $allNames;
}
global $IP;
$m = array();
if( preg_match( '/Messages([A-Z][a-z_]+)\.php$/', $file, $m ) ) {
$code = str_replace( '_', '-', strtolower( $m[1] ) );
- if ( isset( $wgLanguageNames[$code] ) ) {
- $names[$code] = $wgLanguageNames[$code];
+ if ( isset( $allNames[$code] ) ) {
+ $names[$code] = $allNames[$code];
}
}
}
}
function getLanguageName( $code ) {
- global $wgLanguageNames;
- if ( ! array_key_exists( $code, $wgLanguageNames ) ) {
+ $names = self::getLanguageNames();
+ if ( !array_key_exists( $code, $names ) ) {
return '';
}
- return $wgLanguageNames[$code];
+ return $names[$code];
}
function getMonthName( $key ) {
*
* xjj j (day number) in Hebrew calendar
* xjF F (month name) in Hebrew calendar
+ * xjt t (days in month) in Hebrew calendar
* xjx xg (genitive month name) in Hebrew calendar
* xjn n (month number) in Hebrew calendar
* xjY Y (full year) in Hebrew calendar
*
+ * xkY Y (full year) in Thai solar calendar. Months and days are
+ * identical to the Gregorian calendar
+ *
* Characters enclosed in double quotes will be considered literal (with
* the quotes themselves removed). Unmatched quotes will be considered
* literal quotes. Example:
$rawToggle = false;
$iranian = false;
$hebrew = false;
+ $thai = false;
for ( $p = 0; $p < strlen( $format ); $p++ ) {
$num = false;
$code = $format[$p];
$code .= $format[++$p];
}
- if ( ( $code === 'xi' || $code == 'xj' ) && $p < strlen( $format ) - 1 ) {
+ if ( ( $code === 'xi' || $code == 'xj' || $code == 'xk' ) && $p < strlen( $format ) - 1 ) {
$code .= $format[++$p];
}
if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
$num = gmdate( 't', $unix );
break;
+ case 'xjt':
+ if ( !$hebrew ) $hebrew = self::tsToHebrew( $ts );
+ $num = $hebrew[3];
+ break;
case 'L':
if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
$num = gmdate( 'L', $unix );
if ( !$hebrew ) $hebrew = self::tsToHebrew( $ts );
$num = $hebrew[0];
break;
+ case 'xkY':
+ if ( !$thai ) $thai = self::tsToThai( $ts );
+ $num = $thai[0];
+ break;
case 'y':
$num = substr( $ts, 2, 2 );
break;
$month = substr( $ts, 4, 2 );
$day = substr( $ts, 6, 2 );
- # Month number when March = 1, February = 12
- $month -= 2;
- if( $month <= 0 ) {
- # January of February
- $month += 12;
- $year--;
+ # Calculate Hebrew year
+ $hebrewYear = $year + 3760;
+
+ # Month number when September = 1, August = 12
+ $month += 4;
+ if( $month > 12 ) {
+ # Next year
+ $month -= 12;
+ $year++;
+ $hebrewYear++;
}
- # Days since 1 March - calculating 30 days a month,
- # and then adding the missing number of days
- $day += (int)( 7 * $month / 12 + 30 * ( $month - 1 ) );
- # Calculate Hebrew year for days after 1 Nisan
- $hebrewYear = $year + 3760;
- # Passover date for this year (as days since 1 March)
- $passover = self::passoverDate( $hebrewYear );
- if( $day <= $passover - 15 ) {
- # Day is before 1 Nisan (passover is 15 Nisan) - it is the previous year
- # Next year's passover (as days since 1 March)
- $anchor = $passover;
- # Add days since previous year's 1 March
- $day += 365;
- if( ( $year % 400 == 0 ) || ( $year % 100 != 0 && $year % 4 == 0 ) ) {
- # Leap year
- $day++;
+ # Calculate day of year from 1 September
+ $dayOfYear = $day;
+ for( $i = 1; $i < $month; $i++ ) {
+ if( $i == 6 ) {
+ # February
+ $dayOfYear += 28;
+ # Check if the year is leap
+ if( $year % 400 == 0 || ( $year % 4 == 0 && $year % 100 > 0 ) ) {
+ $dayOfYear++;
+ }
+ } elseif( $i == 8 || $i == 10 || $i == 1 || $i == 3 ) {
+ $dayOfYear += 30;
+ } else {
+ $dayOfYear += 31;
}
+ }
+
+ # Calculate the start of the Hebrew year
+ $start = self::hebrewYearStart( $hebrewYear );
+
+ # Calculate next year's start
+ if( $dayOfYear <= $start ) {
+ # Day is before the start of the year - it is the previous year
+ # Next year's start
+ $nextStart = $start;
# Previous year
$year--;
$hebrewYear--;
- # Passover date for the new year (as days since 1 March)
- $passover = self::passoverDate( $hebrewYear );
+ # Add days since previous year's 1 September
+ $dayOfYear += 365;
+ if( ( $year % 400 == 0 ) || ( $year % 100 != 0 && $year % 4 == 0 ) ) {
+ # Leap year
+ $dayOfYear++;
+ }
+ # Start of the new (previous) year
+ $start = self::hebrewYearStart( $hebrewYear );
} else {
- # Next year's passover (as days since 1 March)
- $anchor = self::passoverDate( $hebrewYear + 1 );
- }
-
- # Days since 1 Nisan
- $day -= $passover - 15;
- # Difference between this year's passover date by gregorian calendar,
- # and the next year's one + 12 days. This should be 1 days for a regular year,
- # but 0 for incomplete one, 2 for complete, and those + 30 days of Adar I
- # for a leap year.
- $anchor -= $passover - 12;
- $nextYear = $year + 1;
- if( ( $nextYear % 400 == 0 ) || ( $nextYear % 100 != 0 && $nextYear % 4 == 0 ) ) {
- # Next year is a leap year - difference is growing
- $anchor++;
- }
-
- # Calculate day in the month from number of days sine 1 Nisan
- # Don't check Adar - if the day is not in adar, we will stop before;
- # if it is in adar, we will use it to check if it is Adar I or Adar II
- for( $month = 0; $month < 11; $month++ ) {
+ # Next year's start
+ $nextStart = self::hebrewYearStart( $hebrewYear + 1 );
+ }
+
+ # Calculate Hebrew day of year
+ $hebrewDayOfYear = $dayOfYear - $start;
+
+ # Difference between year's days
+ $diff = $nextStart - $start;
+ # Add 12 (or 13 for leap years) days to ignore the difference between
+ # Hebrew and Gregorian year (353 at least vs. 365/6) - now the
+ # difference is only about the year type
+ if( ( $year % 400 == 0 ) || ( $year % 100 != 0 && $year % 4 == 0 ) ) {
+ $diff += 13;
+ } else {
+ $diff += 12;
+ }
+
+ # Check the year pattern, and is leap year
+ # 0 means an incomplete year, 1 means a regular year, 2 means a complete year
+ # This is mod 30, to work on both leap years (which add 30 days of Adar I)
+ # and non-leap years
+ $yearPattern = $diff % 30;
+ # Check if leap year
+ $isLeap = $diff >= 30;
+
+ # Calculate day in the month from number of day in the Hebrew year
+ # Don't check Adar - if the day is not in Adar, we will stop before;
+ # if it is in Adar, we will use it to check if it is Adar I or Adar II
+ $hebrewDay = $hebrewDayOfYear;
+ $hebrewMonth = 1;
+ $days = 0;
+ while( $hebrewMonth <= 12 ) {
# Calculate days in this month
- if( $month == 7 && $anchor % 30 == 2 ) {
+ if( $isLeap && $hebrewMonth == 6 ) {
+ # Adar in a leap year
+ if( $isLeap ) {
+ # Leap year - has Adar I, with 30 days, and Adar II, with 29 days
+ $days = 30;
+ if( $hebrewDay <= $days ) {
+ # Day in Adar I
+ $hebrewMonth = 13;
+ } else {
+ # Subtract the days of Adar I
+ $hebrewDay -= $days;
+ # Try Adar II
+ $days = 29;
+ if( $hebrewDay <= $days ) {
+ # Day in Adar II
+ $hebrewMonth = 14;
+ }
+ }
+ }
+ } elseif( $hebrewMonth == 2 && $yearPattern == 2 ) {
# Cheshvan in a complete year (otherwise as the rule below)
$days = 30;
- } else if( $month == 8 && $anchor % 30 == 0 ) {
+ } elseif( $hebrewMonth == 3 && $yearPattern == 0 ) {
# Kislev in an incomplete year (otherwise as the rule below)
$days = 29;
} else {
- # Even months have 30 days, odd have 29
- $days = 30 - $month % 2;
+ # Odd months have 30 days, even have 29
+ $days = 30 - ( $hebrewMonth - 1 ) % 2;
}
- if( $day <= $days ) {
- # In this month
+ if( $hebrewDay <= $days ) {
+ # In the current month
break;
- }
- # Try in next months
- $day -= $days;
- }
-
- # Now we move to a year from Tishrei
- if( $month >= 6 ) {
- # After Tishrei, use next year
- $hebrewYear++;
- }
- # Recalculate month number so that we start from Tishrei
- $month = ( $month + 6 ) % 12 + 1;
-
- # Fix Adar
- if( $month == 6 && $anchor >= 30 ) {
- # This *is* adar, and this year is leap
- if( $day > 30 ) {
- # Adar II
- $month = 14;
- $day -= 30;
} else {
- # Adar I
- $month = 13;
+ # Subtract the days of the current month
+ $hebrewDay -= $days;
+ # Try in the next month
+ $hebrewMonth++;
}
}
- return array( $hebrewYear, $month, $day );
+ return array( $hebrewYear, $hebrewMonth, $hebrewDay, $days );
}
/**
+ * This calculates the Hebrew year start, as days since 1 September.
* Based on Carl Friedrich Gauss algorithm for finding Easter date.
* Used for Hebrew date.
*/
- private static function passoverDate( $year ) {
- $a = (int)( ( 12 * $year + 17 ) % 19 );
- $b = (int)( $year % 4 );
- $m = 32.044093161144 + 1.5542417966212 * $a + $b / 4.0 - 0.0031777940220923 * $year;
+ private static function hebrewYearStart( $year ) {
+ $a = intval( ( 12 * ( $year - 1 ) + 17 ) % 19 );
+ $b = intval( ( $year - 1 ) % 4 );
+ $m = 32.044093161144 + 1.5542417966212 * $a + $b / 4.0 - 0.0031777940220923 * ( $year - 1 );
if( $m < 0 ) {
$m--;
}
- $Mar = (int)$m;
+ $Mar = intval( $m );
if( $m < 0 ) {
$m++;
}
$m -= $Mar;
- $c = (int)( ( $Mar + 3 * $year + 5 * $b + 5 ) % 7);
+ $c = intval( ( $Mar + 3 * ( $year - 1 ) + 5 * $b + 5 ) % 7);
if( $c == 0 && $a > 11 && $m >= 0.89772376543210 ) {
$Mar++;
} else if( $c == 1 && $a > 6 && $m >= 0.63287037037037 ) {
$Mar++;
}
- $Mar += (int)( ( $year - 3760 ) / 100 ) - (int)( ( $year - 3760 ) / 400 ) - 2;
+ $Mar += intval( ( $year - 3761 ) / 100 ) - intval( ( $year - 3761 ) / 400 ) - 24;
return $Mar;
}
+ /**
+ * Algorithm to convert Gregorian dates to Thai solar dates.
+ *
+ * Link: http://en.wikipedia.org/wiki/Thai_solar_calendar
+ *
+ * @param string $ts 14-character timestamp
+ * @return array converted year, month, day
+ */
+ private static function tsToThai( $ts ) {
+ $gy = substr( $ts, 0, 4 );
+ $gm = substr( $ts, 4, 2 );
+ $gd = substr( $ts, 6, 2 );
+
+ # Add 543 years to the Gregorian calendar
+ # Months and days are identical
+ $gy_thai = $gy + 543;
+
+ return array( $gy_thai, $gm, $gd );
+ }
+
+
/**
* Roman number formatting up to 3000
*/
for ( $pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i-- ) {
if ( $num >= $pow10 ) {
if ( $num == 15 || $num == 16 ) {
- $s .= $table[0][9] . $table[0][$num - 10];
+ $s .= $table[0][9] . $table[0][$num - 9];
$num = 0;
} else {
- $s .= $table[$i][(int)( $num / $pow10 )];
+ $s .= $table[$i][intval( ( $num / $pow10 ) )];
if( $pow10 == 1000 ) {
$s .= "'";
}
$str = substr( $s, 0, strlen( $s ) - 2 ) . '"';
$str .= substr( $s, strlen( $s ) - 2, 2 );
}
+ $start = substr( $str, 0, strlen( $str ) - 2 );
+ $end = substr( $str, strlen( $str ) - 2 );
+ switch( $end ) {
+ case 'כ':
+ $str = $start . 'ך';
+ break;
+ case 'מ':
+ $str = $start . 'ם';
+ break;
+ case 'נ':
+ $str = $start . 'ן';
+ break;
+ case 'פ':
+ $str = $start . 'ף';
+ break;
+ case 'צ':
+ $str = $start . 'ץ';
+ break;
+ }
return $str;
}
function lcfirst( $str ) {
if ( empty($str) ) return $str;
- if ( ord($str[0]) < 128 ) {
+ if ( is_string( $str ) && ord($str[0]) < 128 ) {
// editing string in place = cool
$str[0]=strtolower($str[0]);
return $str;
if( !is_array( $rawEntry ) ) {
error_log( "\"$rawEntry\" is not a valid magic thingie for \"$mw->mId\"" );
+ } else {
+ $mw->mCaseSensitive = $rawEntry[0];
+ $mw->mSynonyms = array_slice( $rawEntry, 1 );
}
- $mw->mCaseSensitive = $rawEntry[0];
- $mw->mSynonyms = array_slice( $rawEntry, 1 );
}
/**
*/
function convertGrammar( $word, $case ) {
global $wgGrammarForms;
- if ( isset($wgGrammarForms['en'][$case][$word]) ) {
- return $wgGrammarForms['en'][$case][$word];
+ if ( isset($wgGrammarForms[$this->getCode()][$case][$word]) ) {
+ return $wgGrammarForms[$this->getCode()][$case][$word];
}
return $word;
}
*
* Example: {{plural:{{NUMBEROFARTICLES}}|article|articles}}
*
- * @param integer $count
- * @param string $wordform1
- * @param string $wordform2
- * @param string $wordform3 (optional)
- * @param string $wordform4 (optional)
- * @param string $wordform5 (optional)
- * @return string
+ * @param integer $count Non-localized number
+ * @param array $forms Different plural forms
+ * @return string Correct form of plural for $count in this language
*/
- function convertPlural( $count, $w1, $w2, $w3, $w4, $w5) {
- return ( $count == '1' || $count == '-1' ) ? $w1 : $w2;
+ function convertPlural( $count, $forms ) {
+ if ( !count($forms) ) { return ''; }
+ $forms = $this->preConvertPlural( $forms, 2 );
+
+ return ( abs($count) == 1 ) ? $forms[0] : $forms[1];
+ }
+
+ /**
+ * Checks that convertPlural was given an array and pads it to requested
+ * amound of forms by copying the last one.
+ *
+ * @param integer $count How many forms should there be at least
+ * @param array $forms Array of forms given to convertPlural
+ * @return array Padded array of forms or an exception if not an array
+ */
+ protected function preConvertPlural( /* Array */ $forms, $count ) {
+ while ( count($forms) < $count ) {
+ $forms[] = $forms[count($forms)-1];
+ }
+ return $forms;
}
/**
*/
static function loadLocalisation( $code, $disableCache = false ) {
static $recursionGuard = array();
- global $wgMemc;
+ global $wgMemc, $wgCheckSerialized;
if ( !$code ) {
throw new MWException( "Invalid language code requested" );
# Try the serialized directory
$cache = wfGetPrecompiledData( self::getFileName( "Messages", $code, '.ser' ) );
if ( $cache ) {
- self::$mLocalisationCache[$code] = $cache;
- wfDebug( "Language::loadLocalisation(): got localisation for $code from precompiled data file\n" );
- wfProfileOut( __METHOD__ );
- return self::$mLocalisationCache[$code]['deps'];
+ if ( $wgCheckSerialized && self::isLocalisationOutOfDate( $cache ) ) {
+ $cache = false;
+ wfDebug( "Language::loadLocalisation(): precompiled data file for $code is out of date\n" );
+ } else {
+ self::$mLocalisationCache[$code] = $cache;
+ wfDebug( "Language::loadLocalisation(): got localisation for $code from precompiled data file\n" );
+ wfProfileOut( __METHOD__ );
+ return self::$mLocalisationCache[$code]['deps'];
+ }
}
# Try the global cache
$memcKey = wfMemcKey('localisation', $code );
$cache = $wgMemc->get( $memcKey );
if ( $cache ) {
- # Check file modification times
- foreach ( $cache['deps'] as $file => $mtime ) {
- if ( !file_exists( $file ) || filemtime( $file ) > $mtime ) {
- break;
- }
- }
if ( self::isLocalisationOutOfDate( $cache ) ) {
$wgMemc->delete( $memcKey );
$cache = false;
- wfDebug( "Language::loadLocalisation(): localisation cache for $code had expired due to update of $file\n" );
+ wfDebug( "Language::loadLocalisation(): localisation cache for $code had expired\n" );
} else {
self::$mLocalisationCache[$code] = $cache;
wfDebug( "Language::loadLocalisation(): got localisation for $code from cache\n" );
# Replace spaces with underscores in namespace names
$cache['namespaceNames'] = str_replace( ' ', '_', $cache['namespaceNames'] );
+
+ # And do the same for specialpage aliases. $page is an array.
+ foreach ( $cache['specialPageAliases'] as &$page ) {
+ $page = str_replace( ' ', '_', $page );
+ }
+ # Decouple the reference to prevent accidental damage
+ unset($page);
# Save to both caches
self::$mLocalisationCache[$code] = $cache;