From b56b84c5b8651ae19849d023995e00221f039a8e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Niklas=20Laxstr=C3=B6m?= Date: Thu, 18 Aug 2011 16:41:07 +0000 Subject: [PATCH] Attempt to fix Bug 30216 - Improve language fallback loop detection. Made fallbacks a list per language, instead of scanning them recursively through the languages. --- includes/api/ApiQuerySiteinfo.php | 10 +- languages/Language.php | 129 +++++++++++++++--------- languages/messages/MessagesAls.php | 2 +- languages/messages/MessagesBat_smg.php | 2 +- languages/messages/MessagesFiu_vro.php | 2 +- languages/messages/MessagesGan.php | 3 +- languages/messages/MessagesGan_hant.php | 2 +- languages/messages/MessagesIi.php | 4 +- languages/messages/MessagesKaa.php | 2 +- languages/messages/MessagesKk_cn.php | 2 +- languages/messages/MessagesKk_tr.php | 2 +- languages/messages/MessagesMap_bms.php | 2 +- languages/messages/MessagesQug.php | 2 +- languages/messages/MessagesRue.php | 2 +- languages/messages/MessagesRuq.php | 2 +- languages/messages/MessagesTt.php | 2 +- languages/messages/MessagesZh_hk.php | 2 +- languages/messages/MessagesZh_mo.php | 2 +- languages/messages/MessagesZh_my.php | 2 +- languages/messages/MessagesZh_tw.php | 4 +- 20 files changed, 107 insertions(+), 73 deletions(-) diff --git a/includes/api/ApiQuerySiteinfo.php b/includes/api/ApiQuerySiteinfo.php index 6859604aa5..3c618244fd 100644 --- a/includes/api/ApiQuerySiteinfo.php +++ b/includes/api/ApiQuerySiteinfo.php @@ -140,13 +140,11 @@ class ApiQuerySiteinfo extends ApiQueryBase { $data['rights'] = $GLOBALS['wgRightsText']; $data['lang'] = $GLOBALS['wgLanguageCode']; - $fallbackLang = $wgContLang->getFallbackLanguageCode(); - $fallbackLangArray = array(); - while( $fallbackLang ) { - $fallbackLangArray[] = array( 'code' => $fallbackLang ); - $fallbackLang = Language::getFallbackFor( $fallbackLang ); + $fallbacks = array(); + foreach( $wgContLang->getFallbackLanguages() as $code ) { + $fallbacks[] = array( 'code' => $code ); } - $data['fallback'] = $fallbackLangArray; + $data['fallback'] = $fallbacks; $this->getResult()->setIndexedTagName( $data['fallback'], 'lang' ); if ( $wgContLang->isRTL() ) { diff --git a/languages/Language.php b/languages/Language.php index 46de0cdaf8..474fde02cd 100644 --- a/languages/Language.php +++ b/languages/Language.php @@ -148,9 +148,6 @@ class Language { * @return Language */ protected static function newFromCode( $code ) { - global $IP; - static $recursionLevel = 0; - // Protect against path traversal below if ( !Language::isValidCode( $code ) || strcspn( $code, ":/\\\000" ) !== strlen( $code ) ) @@ -166,35 +163,31 @@ class Language { return $lang; } - if ( $code == 'en' ) { - $class = 'Language'; - } else { - $class = 'Language' . str_replace( '-', '_', ucfirst( $code ) ); - if ( !defined( 'MW_COMPILED' ) ) { - // Preload base classes to work around APC/PHP5 bug - if ( file_exists( "$IP/languages/classes/$class.deps.php" ) ) { - include_once( "$IP/languages/classes/$class.deps.php" ); - } - if ( file_exists( "$IP/languages/classes/$class.php" ) ) { - include_once( "$IP/languages/classes/$class.php" ); - } - } + // Check if there is a language class for the code + $class = self::classFromCode( $code ); + self::preloadLanguageClass( $class ); + if ( MWInit::classExists( $class ) ) { + $lang = new $class; + return $lang; } - if ( $recursionLevel > 5 ) { - throw new MWException( "Language fallback loop detected when creating class $class\n" ); - } + // Keep trying the fallback list until we find an existing class + $fallbacks = Language::getFallbacksFor( $code ); + foreach ( $fallbacks as $fallbackCode ) { + if ( !Language::isValidBuiltInCode( $fallbackCode ) ) { + throw new MWException( "Invalid fallback '$fallbackCode' in fallback sequence for '$code'" ); + } - if ( !MWInit::classExists( $class ) ) { - $fallback = Language::getFallbackFor( $code ); - ++$recursionLevel; - $lang = Language::newFromCode( $fallback ); - --$recursionLevel; - $lang->setCode( $code ); - } else { - $lang = new $class; + $class = self::classFromCode( $fallbackCode ); + self::preloadLanguageClass( $class ); + if ( MWInit::classExists( $class ) ) { + $lang = Language::newFromCode( $fallbackCode ); + $lang->setCode( $code ); + return $lang; + } } - return $lang; + + throw new MWException( "Invalid fallback sequence for language '$code'" ); } /** @@ -225,6 +218,32 @@ class Language { return preg_match( '/^[a-z0-9-]*$/i', $code ); } + public static function classFromCode( $code ) { + if ( $code == 'en' ) { + return 'Language'; + } else { + return 'Language' . str_replace( '-', '_', ucfirst( $code ) ); + } + } + + public static function preloadLanguageClass( $class ) { + global $IP; + + if ( $class === 'Language' ) { + return; + } + + if ( !defined( 'MW_COMPILED' ) ) { + // Preload base classes to work around APC/PHP5 bug + if ( file_exists( "$IP/languages/classes/$class.deps.php" ) ) { + include_once( "$IP/languages/classes/$class.deps.php" ); + } + if ( file_exists( "$IP/languages/classes/$class.php" ) ) { + include_once( "$IP/languages/classes/$class.php" ); + } + } + } + /** * Get the LocalisationCache instance * @@ -266,14 +285,21 @@ class Language { function initContLang() { } /** + * Same as getFallbacksFor for current language. * @return array|bool + * @deprecated in 1.19 */ function getFallbackLanguageCode() { - if ( $this->mCode === 'en' ) { - return false; - } else { - return self::$dataCache->getItem( $this->mCode, 'fallback' ); - } + wfDeprecated( __METHOD__ ); + return self::getFallbackFor( $this->mCode ); + } + + /** + * @return array + * @since 1.19 + */ + function getFallbackLanguages() { + return self::getFallbacksFor( $this->mCode ); } /** @@ -2437,15 +2463,7 @@ class Language { * @param $newWords array */ function addMagicWordsByLang( $newWords ) { - $code = $this->getCode(); - $fallbackChain = array(); - while ( $code && !in_array( $code, $fallbackChain ) ) { - $fallbackChain[] = $code; - $code = self::getFallbackFor( $code ); - } - if ( !in_array( 'en', $fallbackChain ) ) { - $fallbackChain[] = 'en'; - } + $fallbackChain = $this->getFallbackLanguages(); $fallbackChain = array_reverse( $fallbackChain ); foreach ( $fallbackChain as $code ) { if ( isset( $newWords[$code] ) ) { @@ -3294,7 +3312,7 @@ class Language { } /** - * Get the fallback for a given language + * Get the first fallback for a given language * * @param $code string * @@ -3302,10 +3320,31 @@ class Language { */ static function getFallbackFor( $code ) { if ( $code === 'en' ) { - // Shortcut return false; } else { - return self::getLocalisationCache()->getItem( $code, 'fallback' ); + $fallbacks = self::getFallbacksFor( $code ); + $first = array_shift( $fallbacks ); + return $first; + } + } + + /** + * Get the ordered list of fallback languages. + * + * @since 1.19 + * @param $code string Language code + * @return array + */ + static function getFallbacksFor( $code ) { + if ( $code === 'en' ) { + return array(); + } else { + $v = self::getLocalisationCache()->getItem( $code, 'fallback' ); + $v = array_map( 'trim', explode( ',', $v ) ); + if ( $v[count( $v ) - 1] !== 'en' ) { + $v[] = 'en'; + } + return $v; } } diff --git a/languages/messages/MessagesAls.php b/languages/messages/MessagesAls.php index 604f49fcf0..867d2a88a7 100644 --- a/languages/messages/MessagesAls.php +++ b/languages/messages/MessagesAls.php @@ -9,4 +9,4 @@ * @comment Deprecated code. Falls back to 'gsw'. */ -$fallback = 'gsw'; +$fallback = 'gsw, de'; diff --git a/languages/messages/MessagesBat_smg.php b/languages/messages/MessagesBat_smg.php index d32e58ac43..44041f0e9a 100644 --- a/languages/messages/MessagesBat_smg.php +++ b/languages/messages/MessagesBat_smg.php @@ -12,4 +12,4 @@ * */ -$fallback = 'sgs'; +$fallback = 'sgs, lt'; diff --git a/languages/messages/MessagesFiu_vro.php b/languages/messages/MessagesFiu_vro.php index 85c3fd7a9f..9407647f1c 100644 --- a/languages/messages/MessagesFiu_vro.php +++ b/languages/messages/MessagesFiu_vro.php @@ -9,4 +9,4 @@ * @comment Deprecated language code. Falls back to 'vro'. */ -$fallback = 'vro'; +$fallback = 'vro, et'; diff --git a/languages/messages/MessagesGan.php b/languages/messages/MessagesGan.php index 41117356ac..3850261ed0 100644 --- a/languages/messages/MessagesGan.php +++ b/languages/messages/MessagesGan.php @@ -12,7 +12,7 @@ * @author Vipuser */ -$fallback = 'gan-hant'; +$fallback = 'gan-hant, zh-hant, zh-hans'; $namespaceNames = array( NS_MEDIA => 'Media', @@ -38,5 +38,4 @@ $messages = array( 'variantname-gan-hans' => '简体', 'variantname-gan-hant' => '繁體', 'variantname-gan' => '贛語原文', - ); diff --git a/languages/messages/MessagesGan_hant.php b/languages/messages/MessagesGan_hant.php index edd1fdb8ba..39acc2cb32 100644 --- a/languages/messages/MessagesGan_hant.php +++ b/languages/messages/MessagesGan_hant.php @@ -14,7 +14,7 @@ * @author Vipuser */ -$fallback = 'zh-hant'; +$fallback = 'zh-hant, zh-hans'; $namespaceNames = array( NS_TALK => '談詑', diff --git a/languages/messages/MessagesIi.php b/languages/messages/MessagesIi.php index 1dc08fea4f..a827db8fa1 100644 --- a/languages/messages/MessagesIi.php +++ b/languages/messages/MessagesIi.php @@ -10,10 +10,8 @@ * @author Biŋhai */ -$fallback = 'zh-cn'; +$fallback = 'zh-cn, zh-hans'; $messages = array( -# All link text and link target definitions of links into project namespace that get used by other message strings, with the exception of user group pages (see grouppage) and the disambiguation template definition (see disambiguations). 'mainpage' => 'ꀨꏾꌠ', - ); diff --git a/languages/messages/MessagesKaa.php b/languages/messages/MessagesKaa.php index 7b812e2846..b645de69b4 100644 --- a/languages/messages/MessagesKaa.php +++ b/languages/messages/MessagesKaa.php @@ -14,7 +14,7 @@ * @author Urhixidur */ -$fallback = 'kk-latn'; +$fallback = 'kk-latn, kk-cyrl'; $separatorTransformTable = array( ',' => "\xc2\xa0", diff --git a/languages/messages/MessagesKk_cn.php b/languages/messages/MessagesKk_cn.php index e96d890f25..fba4e9ffdf 100644 --- a/languages/messages/MessagesKk_cn.php +++ b/languages/messages/MessagesKk_cn.php @@ -10,4 +10,4 @@ */ # Inherit everything for now -$fallback = 'kk-arab'; +$fallback = 'kk-arab, kk-cyrl'; diff --git a/languages/messages/MessagesKk_tr.php b/languages/messages/MessagesKk_tr.php index 41d530a385..05627f901d 100644 --- a/languages/messages/MessagesKk_tr.php +++ b/languages/messages/MessagesKk_tr.php @@ -10,4 +10,4 @@ */ # Inherit everything for now -$fallback = 'kk-latn'; +$fallback = 'kk-latn, kk-cyrl'; diff --git a/languages/messages/MessagesMap_bms.php b/languages/messages/MessagesMap_bms.php index 4276ae7c6c..92befb8c0e 100644 --- a/languages/messages/MessagesMap_bms.php +++ b/languages/messages/MessagesMap_bms.php @@ -10,7 +10,7 @@ * @author לערי ריינהארט */ -$fallback = 'jv'; +$fallback = 'jv, id'; $messages = array( 'article' => 'Isi tulisan', diff --git a/languages/messages/MessagesQug.php b/languages/messages/MessagesQug.php index 6f419dab20..2032bf4099 100644 --- a/languages/messages/MessagesQug.php +++ b/languages/messages/MessagesQug.php @@ -11,7 +11,7 @@ * @author Sylvain2803 */ -$fallback = 'qu'; +$fallback = 'qu, es'; $messages = array( # Dates diff --git a/languages/messages/MessagesRue.php b/languages/messages/MessagesRue.php index d0d6cff5b9..2545cb09bb 100644 --- a/languages/messages/MessagesRue.php +++ b/languages/messages/MessagesRue.php @@ -13,7 +13,7 @@ * @author Tkalyn */ -$fallback = 'uk'; +$fallback = 'uk, ru'; $namespaceNames = array( NS_MEDIA => 'Медіа', diff --git a/languages/messages/MessagesRuq.php b/languages/messages/MessagesRuq.php index d3d5283e9c..ce2d0cefc1 100644 --- a/languages/messages/MessagesRuq.php +++ b/languages/messages/MessagesRuq.php @@ -10,4 +10,4 @@ * */ -$fallback = 'ruq-latn'; +$fallback = 'ruq-latn, ro'; diff --git a/languages/messages/MessagesTt.php b/languages/messages/MessagesTt.php index 6cfb6788cf..1cc1166da0 100644 --- a/languages/messages/MessagesTt.php +++ b/languages/messages/MessagesTt.php @@ -10,4 +10,4 @@ * @comment Placeholder for Tatar. Falls back to Tatar in Latin script. */ -$fallback = 'tt-cyrl'; +$fallback = 'tt-cyrl, ru'; diff --git a/languages/messages/MessagesZh_hk.php b/languages/messages/MessagesZh_hk.php index dc8892593e..70a36125a7 100644 --- a/languages/messages/MessagesZh_hk.php +++ b/languages/messages/MessagesZh_hk.php @@ -17,7 +17,7 @@ * @author Yuyu */ -$fallback = 'zh-hant'; +$fallback = 'zh-hant, zh-hans'; $fallback8bitEncoding = 'Big5-HKSCS'; diff --git a/languages/messages/MessagesZh_mo.php b/languages/messages/MessagesZh_mo.php index 6772ef0a74..37be152b3f 100644 --- a/languages/messages/MessagesZh_mo.php +++ b/languages/messages/MessagesZh_mo.php @@ -10,4 +10,4 @@ */ # Inherit everything for now -$fallback = 'zh-hk'; +$fallback = 'zh-hk, zh-hant, zh-hans'; diff --git a/languages/messages/MessagesZh_my.php b/languages/messages/MessagesZh_my.php index a27ed45fbd..01b5524a12 100644 --- a/languages/messages/MessagesZh_my.php +++ b/languages/messages/MessagesZh_my.php @@ -10,4 +10,4 @@ */ # Inherit everything for now -$fallback = 'zh-sg'; +$fallback = 'zh-sg, zh-hans'; diff --git a/languages/messages/MessagesZh_tw.php b/languages/messages/MessagesZh_tw.php index 5ecd229702..55f6777145 100644 --- a/languages/messages/MessagesZh_tw.php +++ b/languages/messages/MessagesZh_tw.php @@ -22,6 +22,8 @@ * @author לערי ריינהארט */ +$fallback = 'zh-hant, zh-hans'; + $specialPageAliases = array( 'Ancientpages' => array( '最舊頁面' ), 'Block' => array( '查封用戶' ), @@ -43,8 +45,6 @@ $specialPageAliases = array( 'Withoutinterwiki' => array( '沒有跨語言鏈接的頁面' ), ); -$fallback = 'zh-hant'; - $namespaceNames = array( NS_USER => '使用者', NS_USER_TALK => '使用者討論', -- 2.20.1