MediaWiki
REL1_23
|
00001 <?php 00027 class Languages { 00029 protected $mLanguages; # 00030 00032 protected $mRawMessages; 00033 00035 protected $mMessages; 00036 00038 protected $mFallback; 00039 00041 protected $mGeneralMessages; 00042 00044 protected $mIgnoredMessages; 00045 00047 protected $mOptionalMessages; 00048 00050 protected $mNamespaceNames; 00051 00053 protected $mNamespaceAliases; 00054 00056 protected $mMagicWords; 00057 00059 protected $mSpecialPageAliases; 00060 00067 function __construct( $exif = true ) { 00068 require __DIR__ . '/messageTypes.inc'; 00069 $this->mIgnoredMessages = $wgIgnoredMessages; 00070 if ( $exif ) { 00071 $this->mOptionalMessages = array_merge( $wgOptionalMessages ); 00072 } else { 00073 $this->mOptionalMessages = array_merge( $wgOptionalMessages, $wgEXIFMessages ); 00074 } 00075 00076 $this->mLanguages = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) ); 00077 sort( $this->mLanguages ); 00078 } 00079 00085 public function getLanguages() { 00086 return $this->mLanguages; 00087 } 00088 00094 public function getIgnoredMessages() { 00095 return $this->mIgnoredMessages; 00096 } 00097 00103 public function getOptionalMessages() { 00104 return $this->mOptionalMessages; 00105 } 00106 00112 protected function loadFile( $code ) { 00113 if ( isset( $this->mRawMessages[$code] ) && 00114 isset( $this->mFallback[$code] ) && 00115 isset( $this->mNamespaceNames[$code] ) && 00116 isset( $this->mNamespaceAliases[$code] ) && 00117 isset( $this->mMagicWords[$code] ) && 00118 isset( $this->mSpecialPageAliases[$code] ) 00119 ) { 00120 return; 00121 } 00122 $this->mRawMessages[$code] = array(); 00123 $this->mFallback[$code] = ''; 00124 $this->mNamespaceNames[$code] = array(); 00125 $this->mNamespaceAliases[$code] = array(); 00126 $this->mMagicWords[$code] = array(); 00127 $this->mSpecialPageAliases[$code] = array(); 00128 00129 $jsonfilename = Language::getJsonMessagesFileName( $code ); 00130 if ( file_exists( $jsonfilename ) ) { 00131 $json = Language::getLocalisationCache()->readJSONFile( $jsonfilename ); 00132 $this->mRawMessages[$code] = $json['messages']; 00133 } 00134 00135 $filename = Language::getMessagesFileName( $code ); 00136 if ( file_exists( $filename ) ) { 00137 require $filename; 00138 if ( isset( $fallback ) ) { 00139 $this->mFallback[$code] = $fallback; 00140 } 00141 if ( isset( $namespaceNames ) ) { 00142 $this->mNamespaceNames[$code] = $namespaceNames; 00143 } 00144 if ( isset( $namespaceAliases ) ) { 00145 $this->mNamespaceAliases[$code] = $namespaceAliases; 00146 } 00147 if ( isset( $magicWords ) ) { 00148 $this->mMagicWords[$code] = $magicWords; 00149 } 00150 if ( isset( $specialPageAliases ) ) { 00151 $this->mSpecialPageAliases[$code] = $specialPageAliases; 00152 } 00153 } 00154 } 00155 00170 private function loadMessages( $code ) { 00171 if ( isset( $this->mMessages[$code] ) ) { 00172 return; 00173 } 00174 $this->loadFile( $code ); 00175 $this->loadGeneralMessages(); 00176 $this->mMessages[$code]['all'] = $this->mRawMessages[$code]; 00177 $this->mMessages[$code]['required'] = array(); 00178 $this->mMessages[$code]['optional'] = array(); 00179 $this->mMessages[$code]['obsolete'] = array(); 00180 $this->mMessages[$code]['translated'] = array(); 00181 foreach ( $this->mMessages[$code]['all'] as $key => $value ) { 00182 if ( isset( $this->mGeneralMessages['required'][$key] ) ) { 00183 $this->mMessages[$code]['required'][$key] = $value; 00184 $this->mMessages[$code]['translated'][$key] = $value; 00185 } elseif ( isset( $this->mGeneralMessages['optional'][$key] ) ) { 00186 $this->mMessages[$code]['optional'][$key] = $value; 00187 $this->mMessages[$code]['translated'][$key] = $value; 00188 } else { 00189 $this->mMessages[$code]['obsolete'][$key] = $value; 00190 } 00191 } 00192 } 00193 00205 private function loadGeneralMessages() { 00206 if ( isset( $this->mGeneralMessages ) ) { 00207 return; 00208 } 00209 $this->loadFile( 'en' ); 00210 $this->mGeneralMessages['all'] = $this->mRawMessages['en']; 00211 $this->mGeneralMessages['required'] = array(); 00212 $this->mGeneralMessages['optional'] = array(); 00213 $this->mGeneralMessages['ignored'] = array(); 00214 $this->mGeneralMessages['translatable'] = array(); 00215 foreach ( $this->mGeneralMessages['all'] as $key => $value ) { 00216 if ( in_array( $key, $this->mIgnoredMessages ) ) { 00217 $this->mGeneralMessages['ignored'][$key] = $value; 00218 } elseif ( in_array( $key, $this->mOptionalMessages ) ) { 00219 $this->mGeneralMessages['optional'][$key] = $value; 00220 $this->mGeneralMessages['translatable'][$key] = $value; 00221 } else { 00222 $this->mGeneralMessages['required'][$key] = $value; 00223 $this->mGeneralMessages['translatable'][$key] = $value; 00224 } 00225 } 00226 } 00227 00244 public function getMessages( $code ) { 00245 $this->loadMessages( $code ); 00246 00247 return $this->mMessages[$code]; 00248 } 00249 00263 public function getGeneralMessages() { 00264 $this->loadGeneralMessages(); 00265 00266 return $this->mGeneralMessages; 00267 } 00268 00276 public function getFallback( $code ) { 00277 $this->loadFile( $code ); 00278 00279 return $this->mFallback[$code]; 00280 } 00281 00289 public function getNamespaceNames( $code ) { 00290 $this->loadFile( $code ); 00291 00292 return $this->mNamespaceNames[$code]; 00293 } 00294 00302 public function getNamespaceAliases( $code ) { 00303 $this->loadFile( $code ); 00304 00305 return $this->mNamespaceAliases[$code]; 00306 } 00307 00315 public function getMagicWords( $code ) { 00316 $this->loadFile( $code ); 00317 00318 return $this->mMagicWords[$code]; 00319 } 00320 00328 public function getSpecialPageAliases( $code ) { 00329 $this->loadFile( $code ); 00330 00331 return $this->mSpecialPageAliases[$code]; 00332 } 00333 00341 public function getUntranslatedMessages( $code ) { 00342 $this->loadGeneralMessages(); 00343 $this->loadMessages( $code ); 00344 00345 return array_diff_key( $this->mGeneralMessages['required'], $this->mMessages[$code]['required'] ); 00346 } 00347 00355 public function getDuplicateMessages( $code ) { 00356 $this->loadGeneralMessages(); 00357 $this->loadMessages( $code ); 00358 $duplicateMessages = array(); 00359 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00360 if ( $this->mGeneralMessages['translatable'][$key] == $value ) { 00361 $duplicateMessages[$key] = $value; 00362 } 00363 } 00364 00365 return $duplicateMessages; 00366 } 00367 00375 public function getObsoleteMessages( $code ) { 00376 $this->loadGeneralMessages(); 00377 $this->loadMessages( $code ); 00378 00379 return $this->mMessages[$code]['obsolete']; 00380 } 00381 00389 public function getMessagesWithMismatchVariables( $code ) { 00390 $this->loadGeneralMessages(); 00391 $this->loadMessages( $code ); 00392 $variables = array( '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' ); 00393 $mismatchMessages = array(); 00394 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00395 $missing = false; 00396 foreach ( $variables as $var ) { 00397 if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) && 00398 !preg_match( "/$var/sU", $value ) 00399 ) { 00400 $missing = true; 00401 } 00402 if ( !preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) && 00403 preg_match( "/$var/sU", $value ) 00404 ) { 00405 $missing = true; 00406 } 00407 } 00408 if ( $missing ) { 00409 $mismatchMessages[$key] = $value; 00410 } 00411 } 00412 00413 return $mismatchMessages; 00414 } 00415 00423 public function getMessagesWithoutPlural( $code ) { 00424 $this->loadGeneralMessages(); 00425 $this->loadMessages( $code ); 00426 $messagesWithoutPlural = array(); 00427 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00428 if ( stripos( $this->mGeneralMessages['translatable'][$key], '{{plural:' ) !== false && 00429 stripos( $value, '{{plural:' ) === false 00430 ) { 00431 $messagesWithoutPlural[$key] = $value; 00432 } 00433 } 00434 00435 return $messagesWithoutPlural; 00436 } 00437 00445 public function getEmptyMessages( $code ) { 00446 $this->loadGeneralMessages(); 00447 $this->loadMessages( $code ); 00448 $emptyMessages = array(); 00449 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00450 if ( $value === '' || $value === '-' ) { 00451 $emptyMessages[$key] = $value; 00452 } 00453 } 00454 00455 return $emptyMessages; 00456 } 00457 00465 public function getMessagesWithWhitespace( $code ) { 00466 $this->loadGeneralMessages(); 00467 $this->loadMessages( $code ); 00468 $messagesWithWhitespace = array(); 00469 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00470 if ( $this->mGeneralMessages['translatable'][$key] !== '' && $value !== rtrim( $value ) ) { 00471 $messagesWithWhitespace[$key] = $value; 00472 } 00473 } 00474 00475 return $messagesWithWhitespace; 00476 } 00477 00485 public function getNonXHTMLMessages( $code ) { 00486 $this->loadGeneralMessages(); 00487 $this->loadMessages( $code ); 00488 $wrongPhrases = array( 00489 '<hr *\\?>', 00490 '<br *\\?>', 00491 '<hr/>', 00492 '<br/>', 00493 '<hr>', 00494 '<br>', 00495 ); 00496 $wrongPhrases = '~(' . implode( '|', $wrongPhrases ) . ')~sDu'; 00497 $nonXHTMLMessages = array(); 00498 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00499 if ( preg_match( $wrongPhrases, $value ) ) { 00500 $nonXHTMLMessages[$key] = $value; 00501 } 00502 } 00503 00504 return $nonXHTMLMessages; 00505 } 00506 00514 public function getMessagesWithWrongChars( $code ) { 00515 $this->loadGeneralMessages(); 00516 $this->loadMessages( $code ); 00517 $wrongChars = array( 00518 '[LRM]' => "\xE2\x80\x8E", 00519 '[RLM]' => "\xE2\x80\x8F", 00520 '[LRE]' => "\xE2\x80\xAA", 00521 '[RLE]' => "\xE2\x80\xAB", 00522 '[POP]' => "\xE2\x80\xAC", 00523 '[LRO]' => "\xE2\x80\xAD", 00524 '[RLO]' => "\xE2\x80\xAB", 00525 '[ZWSP]' => "\xE2\x80\x8B", 00526 '[NBSP]' => "\xC2\xA0", 00527 '[WJ]' => "\xE2\x81\xA0", 00528 '[BOM]' => "\xEF\xBB\xBF", 00529 '[FFFD]' => "\xEF\xBF\xBD", 00530 ); 00531 $wrongRegExp = '/(' . implode( '|', array_values( $wrongChars ) ) . ')/sDu'; 00532 $wrongCharsMessages = array(); 00533 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00534 if ( preg_match( $wrongRegExp, $value ) ) { 00535 foreach ( $wrongChars as $viewableChar => $hiddenChar ) { 00536 $value = str_replace( $hiddenChar, $viewableChar, $value ); 00537 } 00538 $wrongCharsMessages[$key] = $value; 00539 } 00540 } 00541 00542 return $wrongCharsMessages; 00543 } 00544 00552 public function getMessagesWithDubiousLinks( $code ) { 00553 $this->loadGeneralMessages(); 00554 $this->loadMessages( $code ); 00555 $tc = Title::legalChars() . '#%{}'; 00556 $messages = array(); 00557 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00558 $matches = array(); 00559 preg_match_all( "/\[\[([{$tc}]+)(?:\\|(.+?))?]]/sDu", $value, $matches ); 00560 $numMatches = count( $matches[0] ); 00561 for ( $i = 0; $i < $numMatches; $i++ ) { 00562 if ( preg_match( "/.*project.*/isDu", $matches[1][$i] ) ) { 00563 $messages[$key][] = $matches[0][$i]; 00564 } 00565 } 00566 00567 if ( isset( $messages[$key] ) ) { 00568 $messages[$key] = implode( $messages[$key], ", " ); 00569 } 00570 } 00571 00572 return $messages; 00573 } 00574 00582 public function getMessagesWithUnbalanced( $code ) { 00583 $this->loadGeneralMessages(); 00584 $this->loadMessages( $code ); 00585 $messages = array(); 00586 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00587 $a = $b = $c = $d = 0; 00588 foreach ( preg_split( '//', $value ) as $char ) { 00589 switch ( $char ) { 00590 case '[': 00591 $a++; 00592 break; 00593 case ']': 00594 $b++; 00595 break; 00596 case '{': 00597 $c++; 00598 break; 00599 case '}': 00600 $d++; 00601 break; 00602 } 00603 } 00604 00605 if ( $a !== $b || $c !== $d ) { 00606 $messages[$key] = "$a, $b, $c, $d"; 00607 } 00608 } 00609 00610 return $messages; 00611 } 00612 00620 public function getUntranslatedNamespaces( $code ) { 00621 $this->loadFile( 'en' ); 00622 $this->loadFile( $code ); 00623 $namespacesDiff = array_diff_key( $this->mNamespaceNames['en'], $this->mNamespaceNames[$code] ); 00624 if ( isset( $namespacesDiff[NS_MAIN] ) ) { 00625 unset( $namespacesDiff[NS_MAIN] ); 00626 } 00627 00628 return $namespacesDiff; 00629 } 00630 00638 public function getProblematicProjectTalks( $code ) { 00639 $this->loadFile( $code ); 00640 $namespaces = array(); 00641 00642 # Check default namespace name 00643 if ( isset( $this->mNamespaceNames[$code][NS_PROJECT_TALK] ) ) { 00644 $default = $this->mNamespaceNames[$code][NS_PROJECT_TALK]; 00645 if ( strpos( $default, '$1' ) === false ) { 00646 $namespaces[$default] = 'default'; 00647 } 00648 } 00649 00650 # Check namespace aliases 00651 foreach ( $this->mNamespaceAliases[$code] as $key => $value ) { 00652 if ( $value == NS_PROJECT_TALK && strpos( $key, '$1' ) === false ) { 00653 $namespaces[$key] = ''; 00654 } 00655 } 00656 00657 return $namespaces; 00658 } 00659 00667 public function getUntranslatedMagicWords( $code ) { 00668 $this->loadFile( 'en' ); 00669 $this->loadFile( $code ); 00670 $magicWords = array(); 00671 foreach ( $this->mMagicWords['en'] as $key => $value ) { 00672 if ( !isset( $this->mMagicWords[$code][$key] ) ) { 00673 $magicWords[$key] = $value[1]; 00674 } 00675 } 00676 00677 return $magicWords; 00678 } 00679 00687 public function getObsoleteMagicWords( $code ) { 00688 $this->loadFile( 'en' ); 00689 $this->loadFile( $code ); 00690 $magicWords = array(); 00691 foreach ( $this->mMagicWords[$code] as $key => $value ) { 00692 if ( !isset( $this->mMagicWords['en'][$key] ) ) { 00693 $magicWords[$key] = $value[1]; 00694 } 00695 } 00696 00697 return $magicWords; 00698 } 00699 00707 public function getOverridingMagicWords( $code ) { 00708 $this->loadFile( 'en' ); 00709 $this->loadFile( $code ); 00710 $magicWords = array(); 00711 foreach ( $this->mMagicWords[$code] as $key => $local ) { 00712 if ( !isset( $this->mMagicWords['en'][$key] ) ) { 00713 # Unrecognized magic word 00714 continue; 00715 } 00716 $en = $this->mMagicWords['en'][$key]; 00717 array_shift( $local ); 00718 array_shift( $en ); 00719 foreach ( $en as $word ) { 00720 if ( !in_array( $word, $local ) ) { 00721 $magicWords[$key] = $word; 00722 break; 00723 } 00724 } 00725 } 00726 00727 return $magicWords; 00728 } 00729 00737 public function getCaseMismatchMagicWords( $code ) { 00738 $this->loadFile( 'en' ); 00739 $this->loadFile( $code ); 00740 $magicWords = array(); 00741 foreach ( $this->mMagicWords[$code] as $key => $local ) { 00742 if ( !isset( $this->mMagicWords['en'][$key] ) ) { 00743 # Unrecognized magic word 00744 continue; 00745 } 00746 if ( $local[0] != $this->mMagicWords['en'][$key][0] ) { 00747 $magicWords[$key] = $local[0]; 00748 } 00749 } 00750 00751 return $magicWords; 00752 } 00753 00761 public function getUntraslatedSpecialPages( $code ) { 00762 $this->loadFile( 'en' ); 00763 $this->loadFile( $code ); 00764 $specialPageAliases = array(); 00765 foreach ( $this->mSpecialPageAliases['en'] as $key => $value ) { 00766 if ( !isset( $this->mSpecialPageAliases[$code][$key] ) ) { 00767 $specialPageAliases[$key] = $value[0]; 00768 } 00769 } 00770 00771 return $specialPageAliases; 00772 } 00773 00781 public function getObsoleteSpecialPages( $code ) { 00782 $this->loadFile( 'en' ); 00783 $this->loadFile( $code ); 00784 $specialPageAliases = array(); 00785 foreach ( $this->mSpecialPageAliases[$code] as $key => $value ) { 00786 if ( !isset( $this->mSpecialPageAliases['en'][$key] ) ) { 00787 $specialPageAliases[$key] = $value[0]; 00788 } 00789 } 00790 00791 return $specialPageAliases; 00792 } 00793 } 00794 00795 class ExtensionLanguages extends Languages { 00799 private $mMessageGroup; 00800 00805 function __construct( MessageGroup $group ) { 00806 $this->mMessageGroup = $group; 00807 00808 $this->mIgnoredMessages = $this->mMessageGroup->getIgnored(); 00809 $this->mOptionalMessages = $this->mMessageGroup->getOptional(); 00810 } 00811 00817 public function name() { 00818 return $this->mMessageGroup->getLabel(); 00819 } 00820 00826 protected function loadFile( $code ) { 00827 if ( !isset( $this->mRawMessages[$code] ) ) { 00828 $this->mRawMessages[$code] = $this->mMessageGroup->load( $code ); 00829 if ( empty( $this->mRawMessages[$code] ) ) { 00830 $this->mRawMessages[$code] = array(); 00831 } 00832 } 00833 } 00834 }