Index: trunk/phase3/includes/api/ApiQuerySiteinfo.php |
— | — | @@ -140,13 +140,11 @@ |
141 | 141 | $data['rights'] = $GLOBALS['wgRightsText']; |
142 | 142 | $data['lang'] = $GLOBALS['wgLanguageCode']; |
143 | 143 | |
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 ); |
149 | 147 | } |
150 | | - $data['fallback'] = $fallbackLangArray; |
| 148 | + $data['fallback'] = $fallbacks; |
151 | 149 | $this->getResult()->setIndexedTagName( $data['fallback'], 'lang' ); |
152 | 150 | |
153 | 151 | if ( $wgContLang->isRTL() ) { |
Index: trunk/phase3/languages/messages/MessagesAls.php |
— | — | @@ -9,4 +9,4 @@ |
10 | 10 | * @comment Deprecated code. Falls back to 'gsw'. |
11 | 11 | */ |
12 | 12 | |
13 | | -$fallback = 'gsw'; |
| 13 | +$fallback = 'gsw, de'; |
Index: trunk/phase3/languages/messages/MessagesZh_my.php |
— | — | @@ -10,4 +10,4 @@ |
11 | 11 | */ |
12 | 12 | |
13 | 13 | # 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 @@ |
11 | 11 | */ |
12 | 12 | |
13 | 13 | # 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 @@ |
13 | 13 | * |
14 | 14 | */ |
15 | 15 | |
16 | | -$fallback = 'sgs'; |
| 16 | +$fallback = 'sgs, lt'; |
Index: trunk/phase3/languages/messages/MessagesIi.php |
— | — | @@ -10,10 +10,8 @@ |
11 | 11 | * @author Biŋhai |
12 | 12 | */ |
13 | 13 | |
14 | | -$fallback = 'zh-cn'; |
| 14 | +$fallback = 'zh-cn, zh-hans'; |
15 | 15 | |
16 | 16 | $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). |
18 | 17 | 'mainpage' => 'ꀨꏾꌠ', |
19 | | - |
20 | 18 | ); |
Index: trunk/phase3/languages/messages/MessagesFiu_vro.php |
— | — | @@ -9,4 +9,4 @@ |
10 | 10 | * @comment Deprecated language code. Falls back to 'vro'. |
11 | 11 | */ |
12 | 12 | |
13 | | -$fallback = 'vro'; |
| 13 | +$fallback = 'vro, et'; |
Index: trunk/phase3/languages/messages/MessagesZh_mo.php |
— | — | @@ -10,4 +10,4 @@ |
11 | 11 | */ |
12 | 12 | |
13 | 13 | # 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 @@ |
13 | 13 | * @author Vipuser |
14 | 14 | */ |
15 | 15 | |
16 | | -$fallback = 'gan-hant'; |
| 16 | +$fallback = 'gan-hant, zh-hant, zh-hans'; |
17 | 17 | |
18 | 18 | $namespaceNames = array( |
19 | 19 | NS_MEDIA => 'Media', |
— | — | @@ -38,5 +38,4 @@ |
39 | 39 | 'variantname-gan-hans' => '简体', |
40 | 40 | 'variantname-gan-hant' => '繁體', |
41 | 41 | 'variantname-gan' => '贛語原文', |
42 | | - |
43 | 42 | ); |
Index: trunk/phase3/languages/messages/MessagesGan_hant.php |
— | — | @@ -14,7 +14,7 @@ |
15 | 15 | * @author Vipuser |
16 | 16 | */ |
17 | 17 | |
18 | | -$fallback = 'zh-hant'; |
| 18 | +$fallback = 'zh-hant, zh-hans'; |
19 | 19 | |
20 | 20 | $namespaceNames = array( |
21 | 21 | NS_TALK => '談詑', |
Index: trunk/phase3/languages/messages/MessagesTt.php |
— | — | @@ -10,4 +10,4 @@ |
11 | 11 | * @comment Placeholder for Tatar. Falls back to Tatar in Latin script. |
12 | 12 | */ |
13 | 13 | |
14 | | -$fallback = 'tt-cyrl'; |
| 14 | +$fallback = 'tt-cyrl, ru'; |
Index: trunk/phase3/languages/messages/MessagesRue.php |
— | — | @@ -13,7 +13,7 @@ |
14 | 14 | * @author Tkalyn |
15 | 15 | */ |
16 | 16 | |
17 | | -$fallback = 'uk'; |
| 17 | +$fallback = 'uk, ru'; |
18 | 18 | |
19 | 19 | $namespaceNames = array( |
20 | 20 | NS_MEDIA => 'Медіа', |
Index: trunk/phase3/languages/messages/MessagesZh_tw.php |
— | — | @@ -22,6 +22,8 @@ |
23 | 23 | * @author לערי ריינהארט |
24 | 24 | */ |
25 | 25 | |
| 26 | +$fallback = 'zh-hant, zh-hans'; |
| 27 | + |
26 | 28 | $specialPageAliases = array( |
27 | 29 | 'Ancientpages' => array( '最舊頁面' ), |
28 | 30 | 'Block' => array( '查封用戶' ), |
— | — | @@ -43,8 +45,6 @@ |
44 | 46 | 'Withoutinterwiki' => array( '沒有跨語言鏈接的頁面' ), |
45 | 47 | ); |
46 | 48 | |
47 | | -$fallback = 'zh-hant'; |
48 | | - |
49 | 49 | $namespaceNames = array( |
50 | 50 | NS_USER => '使用者', |
51 | 51 | NS_USER_TALK => '使用者討論', |
Index: trunk/phase3/languages/messages/MessagesRuq.php |
— | — | @@ -10,4 +10,4 @@ |
11 | 11 | * |
12 | 12 | */ |
13 | 13 | |
14 | | -$fallback = 'ruq-latn'; |
| 14 | +$fallback = 'ruq-latn, ro'; |
Index: trunk/phase3/languages/messages/MessagesMap_bms.php |
— | — | @@ -10,7 +10,7 @@ |
11 | 11 | * @author לערי ריינהארט |
12 | 12 | */ |
13 | 13 | |
14 | | -$fallback = 'jv'; |
| 14 | +$fallback = 'jv, id'; |
15 | 15 | |
16 | 16 | $messages = array( |
17 | 17 | 'article' => 'Isi tulisan', |
Index: trunk/phase3/languages/messages/MessagesKaa.php |
— | — | @@ -14,7 +14,7 @@ |
15 | 15 | * @author Urhixidur |
16 | 16 | */ |
17 | 17 | |
18 | | -$fallback = 'kk-latn'; |
| 18 | +$fallback = 'kk-latn, kk-cyrl'; |
19 | 19 | |
20 | 20 | $separatorTransformTable = array( |
21 | 21 | ',' => "\xc2\xa0", |
Index: trunk/phase3/languages/messages/MessagesQug.php |
— | — | @@ -11,7 +11,7 @@ |
12 | 12 | * @author Sylvain2803 |
13 | 13 | */ |
14 | 14 | |
15 | | -$fallback = 'qu'; |
| 15 | +$fallback = 'qu, es'; |
16 | 16 | |
17 | 17 | $messages = array( |
18 | 18 | # Dates |
Index: trunk/phase3/languages/messages/MessagesKk_cn.php |
— | — | @@ -10,4 +10,4 @@ |
11 | 11 | */ |
12 | 12 | |
13 | 13 | # 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 @@ |
18 | 18 | * @author Yuyu |
19 | 19 | */ |
20 | 20 | |
21 | | -$fallback = 'zh-hant'; |
| 21 | +$fallback = 'zh-hant, zh-hans'; |
22 | 22 | |
23 | 23 | $fallback8bitEncoding = 'Big5-HKSCS'; |
24 | 24 | |
Index: trunk/phase3/languages/Language.php |
— | — | @@ -148,9 +148,6 @@ |
149 | 149 | * @return Language |
150 | 150 | */ |
151 | 151 | protected static function newFromCode( $code ) { |
152 | | - global $IP; |
153 | | - static $recursionLevel = 0; |
154 | | - |
155 | 152 | // Protect against path traversal below |
156 | 153 | if ( !Language::isValidCode( $code ) |
157 | 154 | || strcspn( $code, ":/\\\000" ) !== strlen( $code ) ) |
— | — | @@ -166,35 +163,31 @@ |
167 | 164 | return $lang; |
168 | 165 | } |
169 | 166 | |
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; |
183 | 173 | } |
184 | 174 | |
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 | + } |
187 | 189 | } |
188 | 190 | |
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'" ); |
199 | 192 | } |
200 | 193 | |
201 | 194 | /** |
— | — | @@ -225,6 +218,32 @@ |
226 | 219 | return preg_match( '/^[a-z0-9-]*$/i', $code ); |
227 | 220 | } |
228 | 221 | |
| 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 | + |
229 | 248 | /** |
230 | 249 | * Get the LocalisationCache instance |
231 | 250 | * |
— | — | @@ -266,17 +285,24 @@ |
267 | 286 | function initContLang() { } |
268 | 287 | |
269 | 288 | /** |
| 289 | + * Same as getFallbacksFor for current language. |
270 | 290 | * @return array|bool |
| 291 | + * @deprecated in 1.19 |
271 | 292 | */ |
272 | 293 | 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 ); |
278 | 296 | } |
279 | 297 | |
280 | 298 | /** |
| 299 | + * @return array |
| 300 | + * @since 1.19 |
| 301 | + */ |
| 302 | + function getFallbackLanguages() { |
| 303 | + return self::getFallbacksFor( $this->mCode ); |
| 304 | + } |
| 305 | + |
| 306 | + /** |
281 | 307 | * Exports $wgBookstoreListEn |
282 | 308 | * @return array |
283 | 309 | */ |
— | — | @@ -2437,15 +2463,7 @@ |
2438 | 2464 | * @param $newWords array |
2439 | 2465 | */ |
2440 | 2466 | 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(); |
2450 | 2468 | $fallbackChain = array_reverse( $fallbackChain ); |
2451 | 2469 | foreach ( $fallbackChain as $code ) { |
2452 | 2470 | if ( isset( $newWords[$code] ) ) { |
— | — | @@ -3294,7 +3312,7 @@ |
3295 | 3313 | } |
3296 | 3314 | |
3297 | 3315 | /** |
3298 | | - * Get the fallback for a given language |
| 3316 | + * Get the first fallback for a given language |
3299 | 3317 | * |
3300 | 3318 | * @param $code string |
3301 | 3319 | * |
— | — | @@ -3302,14 +3320,35 @@ |
3303 | 3321 | */ |
3304 | 3322 | static function getFallbackFor( $code ) { |
3305 | 3323 | if ( $code === 'en' ) { |
3306 | | - // Shortcut |
3307 | 3324 | return false; |
3308 | 3325 | } else { |
3309 | | - return self::getLocalisationCache()->getItem( $code, 'fallback' ); |
| 3326 | + $fallbacks = self::getFallbacksFor( $code ); |
| 3327 | + $first = array_shift( $fallbacks ); |
| 3328 | + return $first; |
3310 | 3329 | } |
3311 | 3330 | } |
3312 | 3331 | |
3313 | 3332 | /** |
| 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 | + /** |
3314 | 3353 | * Get all messages for a given language |
3315 | 3354 | * WARNING: this may take a long time |
3316 | 3355 | * |
Index: trunk/extensions/Translate/groups/ComplexMessages.php |
— | — | @@ -102,13 +102,15 @@ |
103 | 103 | $current = $this->cleanData( $defs, $current ); |
104 | 104 | |
105 | 105 | $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 ); |
110 | 114 | } |
111 | | - |
112 | | - $chain = array_merge_recursive( $chain, $fbdata ); |
113 | 115 | } |
114 | 116 | |
115 | 117 | if ( $this->firstMagic ) { |
Index: trunk/extensions/Translate/utils/TranslationHelpers.php |
— | — | @@ -995,11 +995,16 @@ |
996 | 996 | $fallbacks = (array) $wgTranslateLanguageFallbacks[$code]; |
997 | 997 | } |
998 | 998 | |
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 | + } |
1004 | 1009 | } |
1005 | 1010 | |
1006 | 1011 | return $fallbacks; |
Index: trunk/extensions/cldr/LanguageNames.body.php |
— | — | @@ -25,9 +25,9 @@ |
26 | 26 | if ( $fbMethod === self::FALLBACK_NATIVE ) { |
27 | 27 | $names = array_merge( $native, $xx ); |
28 | 28 | } elseif ( $fbMethod === self::FALLBACK_NORMAL ) { |
29 | | - $fallback = $code; |
| 29 | + $fallbacks = Language::getFallbacksFor( $code ); |
30 | 30 | $fb = $xx; |
31 | | - while ( $fallback = Language::getFallbackFor( $fallback ) ) { |
| 31 | + foreach ( $fallbacks as $fallback ) { |
32 | 32 | /* Over write the things in fallback with what we have already */ |
33 | 33 | $fb = array_merge( self::loadLanguage( $fallback ), $fb ); |
34 | 34 | } |