* @ingroup Language
*/
class Language {
+ /**
+ * Return autonyms in fetchLanguageName(s).
+ * @since 1.32
+ */
+ const AS_AUTONYMS = null;
+
+ /**
+ * Return all known languages in fetchLanguageName(s).
+ * @since 1.32
+ */
+ const ALL = 'all';
+
+ /**
+ * Return in fetchLanguageName(s) only the languages for which we have at
+ * least some localisation.
+ * @since 1.32
+ */
+ const SUPPORTED = 'mwfile';
+
/**
* @var LanguageConverter
*/
public $mConverter;
public $mVariants, $mCode, $mLoaded = false;
- public $mMagicExtensions = [], $mMagicHookDone = false;
+ public $mMagicExtensions = [];
private $mHtmlCode = null, $mParentLanguage = false;
public $dateFormatStrings = [];
static public $mLangObjCache = [];
+ /**
+ * Return a fallback chain for messages in getFallbacksFor
+ * @since 1.32
+ */
+ const MESSAGES_FALLBACKS = 0;
+
+ /**
+ * Return a strict fallback chain in getFallbacksFor
+ * @since 1.32
+ */
+ const STRICT_FALLBACKS = 1;
+
static public $mWeekdayMsgs = [
'sunday', 'monday', 'tuesday', 'wednesday', 'thursday',
'friday', 'saturday'
}
$this->namespaceAliases = $aliases + $convertedNames;
+
+ # Filter out aliases to namespaces that don't exist, e.g. from extensions
+ # that aren't loaded here but are included in the l10n cache.
+ # (array_intersect preserves keys from its first argument)
+ $this->namespaceAliases = array_intersect(
+ $this->namespaceAliases,
+ array_keys( $this->getNamespaces() )
+ );
}
return $this->namespaceAliases;
return self::$dataCache->getItem( $this->mCode, 'datePreferenceMigrationMap' );
}
- /**
- * @param string $image
- * @return array|null
- */
- function getImageFile( $image ) {
- return self::$dataCache->getSubitem( $this->mCode, 'imageFiles', $image );
- }
-
- /**
- * @return array
- * @since 1.24
- */
- public function getImageFiles() {
- return self::$dataCache->getItem( $this->mCode, 'imageFiles' );
- }
-
/**
* @return array
*/
/**
* Get an array of language names, indexed by code.
* @param null|string $inLanguage Code of language in which to return the names
- * Use null for autonyms (native names)
+ * Use self::AS_AUTONYMS for autonyms (native names)
* @param string $include One of:
- * 'all' all available languages
+ * self::ALL all available languages
* 'mw' only if the language is defined in MediaWiki or wgExtraLanguageNames (default)
- * 'mwfile' only if the language is in 'mw' *and* has a message file
+ * self::SUPPORTED only if the language is in 'mw' *and* has a message file
* @return array Language code => language name (sorted by key)
* @since 1.20
*/
- public static function fetchLanguageNames( $inLanguage = null, $include = 'mw' ) {
- $cacheKey = $inLanguage === null ? 'null' : $inLanguage;
+ public static function fetchLanguageNames( $inLanguage = self::AS_AUTONYMS, $include = 'mw' ) {
+ $cacheKey = $inLanguage === self::AS_AUTONYMS ? 'null' : $inLanguage;
$cacheKey .= ":$include";
if ( self::$languageNameCache === null ) {
self::$languageNameCache = new HashBagOStuff( [ 'maxKeys' => 20 ] );
/**
* Uncached helper for fetchLanguageNames
* @param null|string $inLanguage Code of language in which to return the names
- * Use null for autonyms (native names)
+ * Use self::AS_AUTONYMS for autonyms (native names)
* @param string $include One of:
- * 'all' all available languages
+ * self::ALL all available languages
* 'mw' only if the language is defined in MediaWiki or wgExtraLanguageNames (default)
- * 'mwfile' only if the language is in 'mw' *and* has a message file
+ * self::SUPPORTED only if the language is in 'mw' *and* has a message file
* @return array Language code => language name (sorted by key)
*/
- private static function fetchLanguageNamesUncached( $inLanguage = null, $include = 'mw' ) {
+ private static function fetchLanguageNamesUncached(
+ $inLanguage = self::AS_AUTONYMS,
+ $include = 'mw'
+ ) {
global $wgExtraLanguageNames, $wgUsePigLatinVariant;
// If passed an invalid language code to use, fallback to en
- if ( $inLanguage !== null && !self::isValidCode( $inLanguage ) ) {
+ if ( $inLanguage !== self::AS_AUTONYMS && !self::isValidCode( $inLanguage ) ) {
$inLanguage = 'en';
}
}
}
- if ( $include === 'all' ) {
+ if ( $include === self::ALL ) {
ksort( $names );
return $names;
}
$returnMw[$coreCode] = $names[$coreCode];
}
- if ( $include === 'mwfile' ) {
+ if ( $include === self::SUPPORTED ) {
$namesMwFile = [];
# We do this using a foreach over the codes instead of a directory
# loop so that messages files in extensions will work correctly.
/**
* @param string $code The code of the language for which to get the name
- * @param null|string $inLanguage Code of language in which to return the name (null for autonyms)
- * @param string $include 'all', 'mw' or 'mwfile'; see fetchLanguageNames()
+ * @param null|string $inLanguage Code of language in which to return the name
+ * (SELF::AS_AUTONYMS for autonyms)
+ * @param string $include See fetchLanguageNames()
* @return string Language name or empty
* @since 1.20
*/
- public static function fetchLanguageName( $code, $inLanguage = null, $include = 'all' ) {
+ public static function fetchLanguageName(
+ $code,
+ $inLanguage = self::AS_AUTONYMS,
+ $include = self::ALL
+ ) {
$code = strtolower( $code );
$array = self::fetchLanguageNames( $inLanguage, $include );
return !array_key_exists( $code, $array ) ? '' : $array[$code];
while ( $hebrewMonth <= 12 ) {
# Calculate days in this month
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;
+ # 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 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;
- }
+ # Day in Adar II
+ $hebrewMonth = 14;
}
}
} elseif ( $hebrewMonth == 2 && $yearPattern == 2 ) {
return self::$dataCache->getItem( $this->mCode, 'magicWords' );
}
- /**
- * Run the LanguageGetMagic hook once.
- */
- protected function doMagicHook() {
- if ( $this->mMagicHookDone ) {
- return;
- }
- $this->mMagicHookDone = true;
- Hooks::run( 'LanguageGetMagic', [ &$this->mMagicExtensions, $this->getCode() ], '1.16' );
- }
-
/**
* Fill a MagicWord object with data from here
*
* @param MagicWord $mw
*/
function getMagic( $mw ) {
- // Saves a function call
- if ( !$this->mMagicHookDone ) {
- $this->doMagicHook();
- }
-
- if ( isset( $this->mMagicExtensions[$mw->mId] ) ) {
- $rawEntry = $this->mMagicExtensions[$mw->mId];
- } else {
- $rawEntry = self::$dataCache->getSubitem(
- $this->mCode, 'magicWords', $mw->mId );
- }
+ $rawEntry = $this->mMagicExtensions[$mw->mId] ??
+ self::$dataCache->getSubitem( $this->mCode, 'magicWords', $mw->mId );
if ( !is_array( $rawEntry ) ) {
wfWarn( "\"$rawEntry\" is not a valid magic word for \"$mw->mId\"" );
// Initialise array
$this->mExtendedSpecialPageAliases =
self::$dataCache->getItem( $this->mCode, 'specialPageAliases' );
- Hooks::run( 'LanguageGetSpecialPageAliases',
- [ &$this->mExtendedSpecialPageAliases, $this->getCode() ], '1.16' );
}
return $this->mExtendedSpecialPageAliases;
);
}
- /**
- * This method is deprecated since 1.31 and kept as alias for truncateForDatabase, which
- * has replaced it. This method provides truncation suitable for DB.
- *
- * The database offers limited byte lengths for some columns in the database;
- * multi-byte character sets mean we need to ensure that only whole characters
- * are included, otherwise broken characters can be passed to the user.
- *
- * @deprecated since 1.31, use truncateForDatabase or truncateForVisual as appropriate.
- *
- * @param string $string String to truncate
- * @param int $length Maximum length (including ellipsis)
- * @param string $ellipsis String to append to the truncated text
- * @param bool $adjustLength Subtract length of ellipsis from $length.
- * $adjustLength was introduced in 1.18, before that behaved as if false.
- * @return string
- */
- function truncate( $string, $length, $ellipsis = '...', $adjustLength = true ) {
- wfDeprecated( __METHOD__, '1.31' );
- return $this->truncateForDatabase( $string, $length, $ellipsis, $adjustLength );
- }
-
/**
* Truncate a string to a specified length in bytes, appending an optional
* string (e.g. for ellipsis)
}
/**
- * Check if the language has the specific variant
+ * Strict check if the language has the specific variant.
+ *
+ * Compare to LanguageConverter::validateVariant() which does a more
+ * lenient check and attempts to coerce the given code to a valid one.
*
* @since 1.19
* @param string $variant
* @return bool
*/
public function hasVariant( $variant ) {
- return (bool)$this->mConverter->validateVariant( $variant );
+ return $variant && ( $variant === $this->mConverter->validateVariant( $variant ) );
}
/**
* Perform output conversion on a string, and encode for safe HTML output.
* @param string $text Text to be converted
- * @param bool $isTitle Whether this conversion is for the article title
* @return string
* @todo this should get integrated somewhere sane
*/
- public function convertHtml( $text, $isTitle = false ) {
- return htmlspecialchars( $this->convert( $text, $isTitle ) );
+ public function convertHtml( $text ) {
+ return htmlspecialchars( $this->convert( $text ) );
}
/**
/**
* @param string $code
+ * @deprecated since 1.32, use Language::factory to create a new object instead.
*/
public function setCode( $code ) {
$this->mCode = $code;
*
* @since 1.19
* @param string $code Language code
- * @return array Non-empty array, ending in "en"
+ * @param int $mode Fallback mode, either MESSAGES_FALLBACKS (which always falls back to 'en'),
+ * or STRICT_FALLBACKS (whic honly falls back to 'en' when explicitly defined)
+ * @throws MWException
+ * @return array List of language codes
*/
- public static function getFallbacksFor( $code ) {
+ public static function getFallbacksFor( $code, $mode = self::MESSAGES_FALLBACKS ) {
if ( $code === 'en' || !self::isValidBuiltInCode( $code ) ) {
return [];
}
- // For unknown languages, fallbackSequence returns an empty array,
- // hardcode fallback to 'en' in that case.
- return self::getLocalisationCache()->getItem( $code, 'fallbackSequence' ) ?: [ 'en' ];
+ switch ( $mode ) {
+ case self::MESSAGES_FALLBACKS:
+ // For unknown languages, fallbackSequence returns an empty array,
+ // hardcode fallback to 'en' in that case as English messages are
+ // always defined.
+ return self::getLocalisationCache()->getItem( $code, 'fallbackSequence' ) ?: [ 'en' ];
+ case self::STRICT_FALLBACKS:
+ // Use this mode when you don't want to fallback to English unless
+ // explicitly defined, for example when you have language-variant icons
+ // and an international language-independent fallback.
+ return self::getLocalisationCache()->getItem( $code, 'originalFallbackSequence' );
+ default:
+ throw new MWException( "Invalid fallback mode \"$mode\"" );
+ }
}
/**
public function getPluralRuleType( $number ) {
$index = $this->getPluralRuleIndexNumber( $number );
$pluralRuleTypes = $this->getPluralRuleTypes();
- if ( isset( $pluralRuleTypes[$index] ) ) {
- return $pluralRuleTypes[$index];
- } else {
- return 'other';
- }
+ return $pluralRuleTypes[$index] ?? 'other';
}
}