/**
* Cache for language names
- * @var MapCacheLRU|null
+ * @var HashBagOStuff|null
*/
static private $languageNameCache;
* @return Language
*/
protected static function newFromCode( $code ) {
- // Protect against path traversal below
- if ( !Language::isValidCode( $code )
- || strcspn( $code, ":/\\\000" ) !== strlen( $code )
- ) {
+ if ( !Language::isValidCode( $code ) ) {
throw new MWException( "Invalid language code \"$code\"" );
}
// Check if there is a language class for the code
$class = self::classFromCode( $code );
- self::preloadLanguageClass( $class );
if ( class_exists( $class ) ) {
$lang = new $class;
return $lang;
}
$class = self::classFromCode( $fallbackCode );
- self::preloadLanguageClass( $class );
if ( class_exists( $class ) ) {
- $lang = Language::newFromCode( $fallbackCode );
+ $lang = new $class;
$lang->setCode( $code );
return $lang;
}
*/
public static function isValidCode( $code ) {
static $cache = array();
- if ( isset( $cache[$code] ) ) {
- return $cache[$code];
+ if ( !isset( $cache[$code] ) ) {
+ // People think language codes are html safe, so enforce it.
+ // Ideally we should only allow a-zA-Z0-9-
+ // but, .+ and other chars are often used for {{int:}} hacks
+ // see bugs 37564, 37587, 36938
+ $cache[$code] =
+ // Protect against path traversal
+ strcspn( $code, ":/\\\000&<>'\"" ) === strlen( $code )
+ && !preg_match( MediaWikiTitleCodec::getTitleInvalidRegex(), $code );
}
- // People think language codes are html safe, so enforce it.
- // Ideally we should only allow a-zA-Z0-9-
- // but, .+ and other chars are often used for {{int:}} hacks
- // see bugs 37564, 37587, 36938
- $cache[$code] =
- strcspn( $code, ":/\\\000&<>'\"" ) === strlen( $code )
- && !preg_match( MediaWikiTitleCodec::getTitleInvalidRegex(), $code );
-
return $cache[$code];
}
return false;
}
- /**
- * @param string $code
- * @return string Name of the language class
- */
- public static function classFromCode( $code ) {
- if ( $code == 'en' ) {
- return 'Language';
- } else {
- return 'Language' . str_replace( '-', '_', ucfirst( $code ) );
- }
- }
-
- /**
- * Includes language class files
- *
- * @param string $class Name of the language class
- */
- public static function preloadLanguageClass( $class ) {
- global $IP;
-
- if ( $class === 'Language' ) {
- return;
- }
-
- if ( file_exists( "$IP/languages/classes/$class.php" ) ) {
- include_once "$IP/languages/classes/$class.php";
- }
- }
-
/**
* Get the LocalisationCache instance
*
$cacheKey = $inLanguage === null ? 'null' : $inLanguage;
$cacheKey .= ":$include";
if ( self::$languageNameCache === null ) {
- self::$languageNameCache = new MapCacheLRU( 20 );
+ self::$languageNameCache = new HashBagOStuff( array( 'maxKeys' => 20 ) );
}
- if ( self::$languageNameCache->has( $cacheKey ) ) {
- $ret = self::$languageNameCache->get( $cacheKey );
- } else {
+
+ $ret = self::$languageNameCache->get( $cacheKey );
+ if ( !$ret ) {
$ret = self::fetchLanguageNamesUncached( $inLanguage, $include );
self::$languageNameCache->set( $cacheKey, $ret );
}
*
* @param MWTimestamp $time
* @param MWTimestamp|null $relativeTo The base timestamp to compare to (defaults to now)
- * @param User|null $user User the timestamp is being generated for (or null to use main context's user)
+ * @param User|null $user User the timestamp is being generated for
+ * (or null to use main context's user)
* @return string Formatted timestamp
*/
- public function getHumanTimestamp( MWTimestamp $time, MWTimestamp $relativeTo = null, User $user = null ) {
+ public function getHumanTimestamp(
+ MWTimestamp $time, MWTimestamp $relativeTo = null, User $user = null
+ ) {
if ( $relativeTo === null ) {
$relativeTo = new MWTimestamp();
}
* @return string Human timestamp
* @since 1.26
*/
- private function getHumanTimestampInternal( MWTimestamp $ts, MWTimestamp $relativeTo, User $user ) {
+ private function getHumanTimestampInternal(
+ MWTimestamp $ts, MWTimestamp $relativeTo, User $user
+ ) {
$diff = $ts->diff( $relativeTo );
$diffDay = (bool)( (int)$ts->timestamp->format( 'w' ) -
(int)$relativeTo->timestamp->format( 'w' ) );
# We got the first byte only of a multibyte char; remove it.
$string = substr( $string, 0, -1 );
} elseif ( $char >= 0x80 &&
+ // Use the /s modifier (PCRE_DOTALL) so (.*) also matches newlines
preg_match( '/^(.*)(?:[\xe0-\xef][\x80-\xbf]|' .
- '[\xf0-\xf7][\x80-\xbf]{1,2})$/', $string, $m )
+ '[\xf0-\xf7][\x80-\xbf]{1,2})$/s', $string, $m )
) {
# We chopped in the middle of a character; remove it
$string = $m[1];
$this->mParentLanguage = false;
}
- /**
- * Get the name of a file for a certain language code
- * @param string $prefix Prepend this to the filename
- * @param string $code Language code
- * @param string $suffix Append this to the filename
- * @throws MWException
- * @return string $prefix . $mangledCode . $suffix
- */
- public static function getFileName( $prefix = 'Language', $code, $suffix = '.php' ) {
- if ( !self::isValidBuiltInCode( $code ) ) {
- throw new MWException( "Invalid language code \"$code\"" );
- }
-
- return $prefix . str_replace( '-', '_', ucfirst( $code ) ) . $suffix;
- }
-
/**
* Get the language code from a file name. Inverse of getFileName()
* @param string $filename $prefix . $languageCode . $suffix
return str_replace( '_', '-', strtolower( $m[1] ) );
}
+ /**
+ * @param string $code
+ * @return string Name of the language class
+ */
+ public static function classFromCode( $code ) {
+ if ( $code == 'en' ) {
+ return 'Language';
+ } else {
+ return 'Language' . str_replace( '-', '_', ucfirst( $code ) );
+ }
+ }
+
+ /**
+ * Get the name of a file for a certain language code
+ * @param string $prefix Prepend this to the filename
+ * @param string $code Language code
+ * @param string $suffix Append this to the filename
+ * @throws MWException
+ * @return string $prefix . $mangledCode . $suffix
+ */
+ public static function getFileName( $prefix = 'Language', $code, $suffix = '.php' ) {
+ if ( !self::isValidBuiltInCode( $code ) ) {
+ throw new MWException( "Invalid language code \"$code\"" );
+ }
+
+ return $prefix . str_replace( '-', '_', ucfirst( $code ) ) . $suffix;
+ }
+
/**
* @param string $code
* @return string
return "$IP/languages/i18n/$code.json";
}
- /**
- * @param string $code
- * @return string
- */
- public static function getClassFileName( $code ) {
- global $IP;
- return self::getFileName( "$IP/languages/classes/Language", $code, '.php' );
- }
-
/**
* Get the first fallback for a given language.
*