r94907 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r94906‎ | r94907 | r94908 >
Date:16:41, 18 August 2011
Author:nikerabbit
Status:resolved (Comments)
Tags:
Comment:
Attempt to fix Bug 30216 - Improve language fallback loop detection.
Made fallbacks a list per language, instead of scanning them recursively through the languages.
Modified paths:
  • /trunk/extensions/Translate/groups/ComplexMessages.php (modified) (history)
  • /trunk/extensions/Translate/utils/TranslationHelpers.php (modified) (history)
  • /trunk/extensions/cldr/LanguageNames.body.php (modified) (history)
  • /trunk/phase3/includes/api/ApiQuerySiteinfo.php (modified) (history)
  • /trunk/phase3/languages/Language.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesAls.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesBat_smg.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesFiu_vro.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesGan.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesGan_hant.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesIi.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesKaa.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesKk_cn.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesKk_tr.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesMap_bms.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesQug.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesRue.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesRuq.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesTt.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesZh_hk.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesZh_mo.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesZh_my.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesZh_tw.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/api/ApiQuerySiteinfo.php
@@ -140,13 +140,11 @@
141141 $data['rights'] = $GLOBALS['wgRightsText'];
142142 $data['lang'] = $GLOBALS['wgLanguageCode'];
143143
144 - $fallbackLang = $wgContLang->getFallbackLanguageCode();
145 - $fallbackLangArray = array();
146 - while( $fallbackLang ) {
147 - $fallbackLangArray[] = array( 'code' => $fallbackLang );
148 - $fallbackLang = Language::getFallbackFor( $fallbackLang );
 144+ $fallbacks = array();
 145+ foreach( $wgContLang->getFallbackLanguages() as $code ) {
 146+ $fallbacks[] = array( 'code' => $code );
149147 }
150 - $data['fallback'] = $fallbackLangArray;
 148+ $data['fallback'] = $fallbacks;
151149 $this->getResult()->setIndexedTagName( $data['fallback'], 'lang' );
152150
153151 if ( $wgContLang->isRTL() ) {
Index: trunk/phase3/languages/messages/MessagesAls.php
@@ -9,4 +9,4 @@
1010 * @comment Deprecated code. Falls back to 'gsw'.
1111 */
1212
13 -$fallback = 'gsw';
 13+$fallback = 'gsw, de';
Index: trunk/phase3/languages/messages/MessagesZh_my.php
@@ -10,4 +10,4 @@
1111 */
1212
1313 # Inherit everything for now
14 -$fallback = 'zh-sg';
 14+$fallback = 'zh-sg, zh-hans';
Index: trunk/phase3/languages/messages/MessagesKk_tr.php
@@ -10,4 +10,4 @@
1111 */
1212
1313 # Inherit everything for now
14 -$fallback = 'kk-latn';
 14+$fallback = 'kk-latn, kk-cyrl';
Index: trunk/phase3/languages/messages/MessagesBat_smg.php
@@ -12,4 +12,4 @@
1313 *
1414 */
1515
16 -$fallback = 'sgs';
 16+$fallback = 'sgs, lt';
Index: trunk/phase3/languages/messages/MessagesIi.php
@@ -10,10 +10,8 @@
1111 * @author Biŋhai
1212 */
1313
14 -$fallback = 'zh-cn';
 14+$fallback = 'zh-cn, zh-hans';
1515
1616 $messages = array(
17 -# 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).
1817 'mainpage' => 'ꀨꏾꌠ',
19 -
2018 );
Index: trunk/phase3/languages/messages/MessagesFiu_vro.php
@@ -9,4 +9,4 @@
1010 * @comment Deprecated language code. Falls back to 'vro'.
1111 */
1212
13 -$fallback = 'vro';
 13+$fallback = 'vro, et';
Index: trunk/phase3/languages/messages/MessagesZh_mo.php
@@ -10,4 +10,4 @@
1111 */
1212
1313 # Inherit everything for now
14 -$fallback = 'zh-hk';
 14+$fallback = 'zh-hk, zh-hant, zh-hans';
Index: trunk/phase3/languages/messages/MessagesGan.php
@@ -12,7 +12,7 @@
1313 * @author Vipuser
1414 */
1515
16 -$fallback = 'gan-hant';
 16+$fallback = 'gan-hant, zh-hant, zh-hans';
1717
1818 $namespaceNames = array(
1919 NS_MEDIA => 'Media',
@@ -38,5 +38,4 @@
3939 'variantname-gan-hans' => '简体',
4040 'variantname-gan-hant' => '繁體',
4141 'variantname-gan' => '贛語原文',
42 -
4342 );
Index: trunk/phase3/languages/messages/MessagesGan_hant.php
@@ -14,7 +14,7 @@
1515 * @author Vipuser
1616 */
1717
18 -$fallback = 'zh-hant';
 18+$fallback = 'zh-hant, zh-hans';
1919
2020 $namespaceNames = array(
2121 NS_TALK => '談詑',
Index: trunk/phase3/languages/messages/MessagesTt.php
@@ -10,4 +10,4 @@
1111 * @comment Placeholder for Tatar. Falls back to Tatar in Latin script.
1212 */
1313
14 -$fallback = 'tt-cyrl';
 14+$fallback = 'tt-cyrl, ru';
Index: trunk/phase3/languages/messages/MessagesRue.php
@@ -13,7 +13,7 @@
1414 * @author Tkalyn
1515 */
1616
17 -$fallback = 'uk';
 17+$fallback = 'uk, ru';
1818
1919 $namespaceNames = array(
2020 NS_MEDIA => 'Медіа',
Index: trunk/phase3/languages/messages/MessagesZh_tw.php
@@ -22,6 +22,8 @@
2323 * @author לערי ריינהארט
2424 */
2525
 26+$fallback = 'zh-hant, zh-hans';
 27+
2628 $specialPageAliases = array(
2729 'Ancientpages' => array( '最舊頁面' ),
2830 'Block' => array( '查封用戶' ),
@@ -43,8 +45,6 @@
4446 'Withoutinterwiki' => array( '沒有跨語言鏈接的頁面' ),
4547 );
4648
47 -$fallback = 'zh-hant';
48 -
4949 $namespaceNames = array(
5050 NS_USER => '使用者',
5151 NS_USER_TALK => '使用者討論',
Index: trunk/phase3/languages/messages/MessagesRuq.php
@@ -10,4 +10,4 @@
1111 *
1212 */
1313
14 -$fallback = 'ruq-latn';
 14+$fallback = 'ruq-latn, ro';
Index: trunk/phase3/languages/messages/MessagesMap_bms.php
@@ -10,7 +10,7 @@
1111 * @author לערי ריינהארט
1212 */
1313
14 -$fallback = 'jv';
 14+$fallback = 'jv, id';
1515
1616 $messages = array(
1717 'article' => 'Isi tulisan',
Index: trunk/phase3/languages/messages/MessagesKaa.php
@@ -14,7 +14,7 @@
1515 * @author Urhixidur
1616 */
1717
18 -$fallback = 'kk-latn';
 18+$fallback = 'kk-latn, kk-cyrl';
1919
2020 $separatorTransformTable = array(
2121 ',' => "\xc2\xa0",
Index: trunk/phase3/languages/messages/MessagesQug.php
@@ -11,7 +11,7 @@
1212 * @author Sylvain2803
1313 */
1414
15 -$fallback = 'qu';
 15+$fallback = 'qu, es';
1616
1717 $messages = array(
1818 # Dates
Index: trunk/phase3/languages/messages/MessagesKk_cn.php
@@ -10,4 +10,4 @@
1111 */
1212
1313 # Inherit everything for now
14 -$fallback = 'kk-arab';
 14+$fallback = 'kk-arab, kk-cyrl';
Index: trunk/phase3/languages/messages/MessagesZh_hk.php
@@ -17,7 +17,7 @@
1818 * @author Yuyu
1919 */
2020
21 -$fallback = 'zh-hant';
 21+$fallback = 'zh-hant, zh-hans';
2222
2323 $fallback8bitEncoding = 'Big5-HKSCS';
2424
Index: trunk/phase3/languages/Language.php
@@ -148,9 +148,6 @@
149149 * @return Language
150150 */
151151 protected static function newFromCode( $code ) {
152 - global $IP;
153 - static $recursionLevel = 0;
154 -
155152 // Protect against path traversal below
156153 if ( !Language::isValidCode( $code )
157154 || strcspn( $code, ":/\\\000" ) !== strlen( $code ) )
@@ -166,35 +163,31 @@
167164 return $lang;
168165 }
169166
170 - if ( $code == 'en' ) {
171 - $class = 'Language';
172 - } else {
173 - $class = 'Language' . str_replace( '-', '_', ucfirst( $code ) );
174 - if ( !defined( 'MW_COMPILED' ) ) {
175 - // Preload base classes to work around APC/PHP5 bug
176 - if ( file_exists( "$IP/languages/classes/$class.deps.php" ) ) {
177 - include_once( "$IP/languages/classes/$class.deps.php" );
178 - }
179 - if ( file_exists( "$IP/languages/classes/$class.php" ) ) {
180 - include_once( "$IP/languages/classes/$class.php" );
181 - }
182 - }
 167+ // Check if there is a language class for the code
 168+ $class = self::classFromCode( $code );
 169+ self::preloadLanguageClass( $class );
 170+ if ( MWInit::classExists( $class ) ) {
 171+ $lang = new $class;
 172+ return $lang;
183173 }
184174
185 - if ( $recursionLevel > 5 ) {
186 - throw new MWException( "Language fallback loop detected when creating class $class\n" );
 175+ // Keep trying the fallback list until we find an existing class
 176+ $fallbacks = Language::getFallbacksFor( $code );
 177+ foreach ( $fallbacks as $fallbackCode ) {
 178+ if ( !Language::isValidBuiltInCode( $fallbackCode ) ) {
 179+ throw new MWException( "Invalid fallback '$fallbackCode' in fallback sequence for '$code'" );
 180+ }
 181+
 182+ $class = self::classFromCode( $fallbackCode );
 183+ self::preloadLanguageClass( $class );
 184+ if ( MWInit::classExists( $class ) ) {
 185+ $lang = Language::newFromCode( $fallbackCode );
 186+ $lang->setCode( $code );
 187+ return $lang;
 188+ }
187189 }
188190
189 - if ( !MWInit::classExists( $class ) ) {
190 - $fallback = Language::getFallbackFor( $code );
191 - ++$recursionLevel;
192 - $lang = Language::newFromCode( $fallback );
193 - --$recursionLevel;
194 - $lang->setCode( $code );
195 - } else {
196 - $lang = new $class;
197 - }
198 - return $lang;
 191+ throw new MWException( "Invalid fallback sequence for language '$code'" );
199192 }
200193
201194 /**
@@ -225,6 +218,32 @@
226219 return preg_match( '/^[a-z0-9-]*$/i', $code );
227220 }
228221
 222+ public static function classFromCode( $code ) {
 223+ if ( $code == 'en' ) {
 224+ return 'Language';
 225+ } else {
 226+ return 'Language' . str_replace( '-', '_', ucfirst( $code ) );
 227+ }
 228+ }
 229+
 230+ public static function preloadLanguageClass( $class ) {
 231+ global $IP;
 232+
 233+ if ( $class === 'Language' ) {
 234+ return;
 235+ }
 236+
 237+ if ( !defined( 'MW_COMPILED' ) ) {
 238+ // Preload base classes to work around APC/PHP5 bug
 239+ if ( file_exists( "$IP/languages/classes/$class.deps.php" ) ) {
 240+ include_once( "$IP/languages/classes/$class.deps.php" );
 241+ }
 242+ if ( file_exists( "$IP/languages/classes/$class.php" ) ) {
 243+ include_once( "$IP/languages/classes/$class.php" );
 244+ }
 245+ }
 246+ }
 247+
229248 /**
230249 * Get the LocalisationCache instance
231250 *
@@ -266,17 +285,24 @@
267286 function initContLang() { }
268287
269288 /**
 289+ * Same as getFallbacksFor for current language.
270290 * @return array|bool
 291+ * @deprecated in 1.19
271292 */
272293 function getFallbackLanguageCode() {
273 - if ( $this->mCode === 'en' ) {
274 - return false;
275 - } else {
276 - return self::$dataCache->getItem( $this->mCode, 'fallback' );
277 - }
 294+ wfDeprecated( __METHOD__ );
 295+ return self::getFallbackFor( $this->mCode );
278296 }
279297
280298 /**
 299+ * @return array
 300+ * @since 1.19
 301+ */
 302+ function getFallbackLanguages() {
 303+ return self::getFallbacksFor( $this->mCode );
 304+ }
 305+
 306+ /**
281307 * Exports $wgBookstoreListEn
282308 * @return array
283309 */
@@ -2437,15 +2463,7 @@
24382464 * @param $newWords array
24392465 */
24402466 function addMagicWordsByLang( $newWords ) {
2441 - $code = $this->getCode();
2442 - $fallbackChain = array();
2443 - while ( $code && !in_array( $code, $fallbackChain ) ) {
2444 - $fallbackChain[] = $code;
2445 - $code = self::getFallbackFor( $code );
2446 - }
2447 - if ( !in_array( 'en', $fallbackChain ) ) {
2448 - $fallbackChain[] = 'en';
2449 - }
 2467+ $fallbackChain = $this->getFallbackLanguages();
24502468 $fallbackChain = array_reverse( $fallbackChain );
24512469 foreach ( $fallbackChain as $code ) {
24522470 if ( isset( $newWords[$code] ) ) {
@@ -3294,7 +3312,7 @@
32953313 }
32963314
32973315 /**
3298 - * Get the fallback for a given language
 3316+ * Get the first fallback for a given language
32993317 *
33003318 * @param $code string
33013319 *
@@ -3302,14 +3320,35 @@
33033321 */
33043322 static function getFallbackFor( $code ) {
33053323 if ( $code === 'en' ) {
3306 - // Shortcut
33073324 return false;
33083325 } else {
3309 - return self::getLocalisationCache()->getItem( $code, 'fallback' );
 3326+ $fallbacks = self::getFallbacksFor( $code );
 3327+ $first = array_shift( $fallbacks );
 3328+ return $first;
33103329 }
33113330 }
33123331
33133332 /**
 3333+ * Get the ordered list of fallback languages.
 3334+ *
 3335+ * @since 1.19
 3336+ * @param $code string Language code
 3337+ * @return array
 3338+ */
 3339+ static function getFallbacksFor( $code ) {
 3340+ if ( $code === 'en' ) {
 3341+ return array();
 3342+ } else {
 3343+ $v = self::getLocalisationCache()->getItem( $code, 'fallback' );
 3344+ $v = array_map( 'trim', explode( ',', $v ) );
 3345+ if ( $v[count( $v ) - 1] !== 'en' ) {
 3346+ $v[] = 'en';
 3347+ }
 3348+ return $v;
 3349+ }
 3350+ }
 3351+
 3352+ /**
33143353 * Get all messages for a given language
33153354 * WARNING: this may take a long time
33163355 *
Index: trunk/extensions/Translate/groups/ComplexMessages.php
@@ -102,13 +102,15 @@
103103 $current = $this->cleanData( $defs, $current );
104104
105105 $chain = $current;
106 - while ( $this->chainable && $code = Language::getFallbackFor( $code ) ) {
107 - $fbdata = $this->readVariable( $group, $code );
108 - if ( $this->firstMagic ) {
109 - $fbdata = $this->cleanData( $defs, $fbdata );
 106+ if ( $this->chainable } {
 107+ foreach ( Language::getFallbackFors( $code ) as $code ) {
 108+ $fbdata = $this->readVariable( $group, $code );
 109+ if ( $this->firstMagic ) {
 110+ $fbdata = $this->cleanData( $defs, $fbdata );
 111+ }
 112+
 113+ $chain = array_merge_recursive( $chain, $fbdata );
110114 }
111 -
112 - $chain = array_merge_recursive( $chain, $fbdata );
113115 }
114116
115117 if ( $this->firstMagic ) {
Index: trunk/extensions/Translate/utils/TranslationHelpers.php
@@ -995,11 +995,16 @@
996996 $fallbacks = (array) $wgTranslateLanguageFallbacks[$code];
997997 }
998998
999 - // And the real fallback
1000 - // TODO: why only one?
1001 - $realFallback = $code ? Language::getFallbackFor( $code ) : false;
1002 - if ( $realFallback && $realFallback !== 'en' ) {
1003 - $fallbacks = array_merge( array( $realFallback ), $fallbacks );
 999+ // BC <1.19
 1000+ if ( method_exists( 'Language', 'getFallbacksFor' ) ) {
 1001+ $list = Language::getFallbacskFor( $code );
 1002+ array_pop( $list ); // Get 'en' away from the end
 1003+ $fallbacks = array_merge( $list , $fallbacks );
 1004+ } else {
 1005+ $realFallback = $code ? Language::getFallbackFor( $code ) : false;
 1006+ if ( $realFallback && $realFallback !== 'en' ) {
 1007+ $fallbacks = array_merge( array( $realFallback ), $fallbacks );
 1008+ }
10041009 }
10051010
10061011 return $fallbacks;
Index: trunk/extensions/cldr/LanguageNames.body.php
@@ -25,9 +25,9 @@
2626 if ( $fbMethod === self::FALLBACK_NATIVE ) {
2727 $names = array_merge( $native, $xx );
2828 } elseif ( $fbMethod === self::FALLBACK_NORMAL ) {
29 - $fallback = $code;
 29+ $fallbacks = Language::getFallbacksFor( $code );
3030 $fb = $xx;
31 - while ( $fallback = Language::getFallbackFor( $fallback ) ) {
 31+ foreach ( $fallbacks as $fallback ) {
3232 /* Over write the things in fallback with what we have already */
3333 $fb = array_merge( self::loadLanguage( $fallback ), $fb );
3434 }

Follow-up revisions

RevisionCommit summaryAuthorDate
r94908* (bug 30217) Make pt-br a fallback of pt...nikerabbit16:43, 18 August 2011
r94939Fix Language::getFallbacskFor typoreedy20:40, 18 August 2011
r94988fu r94907: Fix PHP Parse error: syntax error, unexpected '}' in /www/w/exten...raymond07:04, 19 August 2011
r94991Fu r94907 - also update localisation cache, which accesses the fallback varia...nikerabbit09:02, 19 August 2011
r95012Fu r94907 - stupid typonikerabbit16:28, 19 August 2011
r95025Followup r95012...reedy18:38, 19 August 2011
r95192Make the language recaching non-recursive and load the data directly....nikerabbit08:12, 22 August 2011
r112300Fixes for r94907/r94908: change in fallback behaviour allowing infinite loops...tstarling05:14, 24 February 2012

Comments

#Comment by Reedy (talk | contribs)   18:21, 18 August 2011

I wonder why this didn't appear as an inline diff.

$wgCodeReviewMaxDiffPaths is set to 30, and $wgCodeReviewMaxDiffSize to 500,000

#Comment by Siebrand (talk | contribs)   14:07, 30 August 2011

Create a bug report for CodeReview? This doesn't appear to be the right place to discuss this...

#Comment by Platonides (talk | contribs)   16:20, 14 November 2011

Why a comma-separated list instead of an array?

#Comment by Nikerabbit (talk | contribs)   16:33, 14 November 2011

No particular reason.

#Comment by 😂 (talk | contribs)   16:28, 14 November 2011

Not sure why this was deferred, unmarking.

Status & tagging log