MediaWiki
REL1_22
|
00001 <?php 00027 class languages { 00028 protected $mLanguages; # List of languages 00029 00030 protected $mRawMessages; # Raw list of the messages in each language 00031 protected $mMessages; # Messages in each language (except for English), divided to groups 00032 protected $mFallback; # Fallback language in each language 00033 protected $mGeneralMessages; # General messages in English, divided to groups 00034 protected $mIgnoredMessages; # All the messages which should be exist only in the English file 00035 protected $mOptionalMessages; # All the messages which may be translated or not, depending on the language 00036 00037 protected $mNamespaceNames; # Namespace names 00038 protected $mNamespaceAliases; # Namespace aliases 00039 protected $mMagicWords; # Magic words 00040 protected $mSpecialPageAliases; # Special page aliases 00041 00048 function __construct( $exif = true ) { 00049 require __DIR__ . '/messageTypes.inc'; 00050 $this->mIgnoredMessages = $wgIgnoredMessages; 00051 if ( $exif ) { 00052 $this->mOptionalMessages = array_merge( $wgOptionalMessages ); 00053 } else { 00054 $this->mOptionalMessages = array_merge( $wgOptionalMessages, $wgEXIFMessages ); 00055 } 00056 00057 $this->mLanguages = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) ); 00058 sort( $this->mLanguages ); 00059 } 00060 00066 public function getLanguages() { 00067 return $this->mLanguages; 00068 } 00069 00075 public function getIgnoredMessages() { 00076 return $this->mIgnoredMessages; 00077 } 00078 00084 public function getOptionalMessages() { 00085 return $this->mOptionalMessages; 00086 } 00087 00093 protected function loadFile( $code ) { 00094 if ( isset( $this->mRawMessages[$code] ) && 00095 isset( $this->mFallback[$code] ) && 00096 isset( $this->mNamespaceNames[$code] ) && 00097 isset( $this->mNamespaceAliases[$code] ) && 00098 isset( $this->mMagicWords[$code] ) && 00099 isset( $this->mSpecialPageAliases[$code] ) ) { 00100 return; 00101 } 00102 $this->mRawMessages[$code] = array(); 00103 $this->mFallback[$code] = ''; 00104 $this->mNamespaceNames[$code] = array(); 00105 $this->mNamespaceAliases[$code] = array(); 00106 $this->mMagicWords[$code] = array(); 00107 $this->mSpecialPageAliases[$code] = array(); 00108 $filename = Language::getMessagesFileName( $code ); 00109 if ( file_exists( $filename ) ) { 00110 require $filename; 00111 if ( isset( $messages ) ) { 00112 $this->mRawMessages[$code] = $messages; 00113 } 00114 if ( isset( $fallback ) ) { 00115 $this->mFallback[$code] = $fallback; 00116 } 00117 if ( isset( $namespaceNames ) ) { 00118 $this->mNamespaceNames[$code] = $namespaceNames; 00119 } 00120 if ( isset( $namespaceAliases ) ) { 00121 $this->mNamespaceAliases[$code] = $namespaceAliases; 00122 } 00123 if ( isset( $magicWords ) ) { 00124 $this->mMagicWords[$code] = $magicWords; 00125 } 00126 if ( isset( $specialPageAliases ) ) { 00127 $this->mSpecialPageAliases[$code] = $specialPageAliases; 00128 } 00129 } 00130 } 00131 00142 private function loadMessages( $code ) { 00143 if ( isset( $this->mMessages[$code] ) ) { 00144 return; 00145 } 00146 $this->loadFile( $code ); 00147 $this->loadGeneralMessages(); 00148 $this->mMessages[$code]['all'] = $this->mRawMessages[$code]; 00149 $this->mMessages[$code]['required'] = array(); 00150 $this->mMessages[$code]['optional'] = array(); 00151 $this->mMessages[$code]['obsolete'] = array(); 00152 $this->mMessages[$code]['translated'] = array(); 00153 foreach ( $this->mMessages[$code]['all'] as $key => $value ) { 00154 if ( isset( $this->mGeneralMessages['required'][$key] ) ) { 00155 $this->mMessages[$code]['required'][$key] = $value; 00156 $this->mMessages[$code]['translated'][$key] = $value; 00157 } elseif ( isset( $this->mGeneralMessages['optional'][$key] ) ) { 00158 $this->mMessages[$code]['optional'][$key] = $value; 00159 $this->mMessages[$code]['translated'][$key] = $value; 00160 } else { 00161 $this->mMessages[$code]['obsolete'][$key] = $value; 00162 } 00163 } 00164 } 00165 00174 private function loadGeneralMessages() { 00175 if ( isset( $this->mGeneralMessages ) ) { 00176 return; 00177 } 00178 $this->loadFile( 'en' ); 00179 $this->mGeneralMessages['all'] = $this->mRawMessages['en']; 00180 $this->mGeneralMessages['required'] = array(); 00181 $this->mGeneralMessages['optional'] = array(); 00182 $this->mGeneralMessages['ignored'] = array(); 00183 $this->mGeneralMessages['translatable'] = array(); 00184 foreach ( $this->mGeneralMessages['all'] as $key => $value ) { 00185 if ( in_array( $key, $this->mIgnoredMessages ) ) { 00186 $this->mGeneralMessages['ignored'][$key] = $value; 00187 } elseif ( in_array( $key, $this->mOptionalMessages ) ) { 00188 $this->mGeneralMessages['optional'][$key] = $value; 00189 $this->mGeneralMessages['translatable'][$key] = $value; 00190 } else { 00191 $this->mGeneralMessages['required'][$key] = $value; 00192 $this->mGeneralMessages['translatable'][$key] = $value; 00193 } 00194 } 00195 } 00196 00210 public function getMessages( $code ) { 00211 $this->loadMessages( $code ); 00212 return $this->mMessages[$code]; 00213 } 00214 00225 public function getGeneralMessages() { 00226 $this->loadGeneralMessages(); 00227 return $this->mGeneralMessages; 00228 } 00229 00237 public function getFallback( $code ) { 00238 $this->loadFile( $code ); 00239 return $this->mFallback[$code]; 00240 } 00241 00249 public function getNamespaceNames( $code ) { 00250 $this->loadFile( $code ); 00251 return $this->mNamespaceNames[$code]; 00252 } 00253 00261 public function getNamespaceAliases( $code ) { 00262 $this->loadFile( $code ); 00263 return $this->mNamespaceAliases[$code]; 00264 } 00265 00273 public function getMagicWords( $code ) { 00274 $this->loadFile( $code ); 00275 return $this->mMagicWords[$code]; 00276 } 00277 00285 public function getSpecialPageAliases( $code ) { 00286 $this->loadFile( $code ); 00287 return $this->mSpecialPageAliases[$code]; 00288 } 00289 00297 public function getUntranslatedMessages( $code ) { 00298 $this->loadGeneralMessages(); 00299 $this->loadMessages( $code ); 00300 return array_diff_key( $this->mGeneralMessages['required'], $this->mMessages[$code]['required'] ); 00301 } 00302 00310 public function getDuplicateMessages( $code ) { 00311 $this->loadGeneralMessages(); 00312 $this->loadMessages( $code ); 00313 $duplicateMessages = array(); 00314 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00315 if ( $this->mGeneralMessages['translatable'][$key] == $value ) { 00316 $duplicateMessages[$key] = $value; 00317 } 00318 } 00319 return $duplicateMessages; 00320 } 00321 00329 public function getObsoleteMessages( $code ) { 00330 $this->loadGeneralMessages(); 00331 $this->loadMessages( $code ); 00332 return $this->mMessages[$code]['obsolete']; 00333 } 00334 00342 public function getMessagesWithMismatchVariables( $code ) { 00343 $this->loadGeneralMessages(); 00344 $this->loadMessages( $code ); 00345 $variables = array( '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' ); 00346 $mismatchMessages = array(); 00347 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00348 $missing = false; 00349 foreach ( $variables as $var ) { 00350 if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) && 00351 !preg_match( "/$var/sU", $value ) ) { 00352 $missing = true; 00353 } 00354 if ( !preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) && 00355 preg_match( "/$var/sU", $value ) ) { 00356 $missing = true; 00357 } 00358 } 00359 if ( $missing ) { 00360 $mismatchMessages[$key] = $value; 00361 } 00362 } 00363 return $mismatchMessages; 00364 } 00365 00373 public function getMessagesWithoutPlural( $code ) { 00374 $this->loadGeneralMessages(); 00375 $this->loadMessages( $code ); 00376 $messagesWithoutPlural = array(); 00377 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00378 if ( stripos( $this->mGeneralMessages['translatable'][$key], '{{plural:' ) !== false && stripos( $value, '{{plural:' ) === false ) { 00379 $messagesWithoutPlural[$key] = $value; 00380 } 00381 } 00382 return $messagesWithoutPlural; 00383 } 00384 00392 public function getEmptyMessages( $code ) { 00393 $this->loadGeneralMessages(); 00394 $this->loadMessages( $code ); 00395 $emptyMessages = array(); 00396 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00397 if ( $value === '' || $value === '-' ) { 00398 $emptyMessages[$key] = $value; 00399 } 00400 } 00401 return $emptyMessages; 00402 } 00403 00411 public function getMessagesWithWhitespace( $code ) { 00412 $this->loadGeneralMessages(); 00413 $this->loadMessages( $code ); 00414 $messagesWithWhitespace = array(); 00415 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00416 if ( $this->mGeneralMessages['translatable'][$key] !== '' && $value !== rtrim( $value ) ) { 00417 $messagesWithWhitespace[$key] = $value; 00418 } 00419 } 00420 return $messagesWithWhitespace; 00421 } 00422 00430 public function getNonXHTMLMessages( $code ) { 00431 $this->loadGeneralMessages(); 00432 $this->loadMessages( $code ); 00433 $wrongPhrases = array( 00434 '<hr *\\?>', 00435 '<br *\\?>', 00436 '<hr/>', 00437 '<br/>', 00438 '<hr>', 00439 '<br>', 00440 ); 00441 $wrongPhrases = '~(' . implode( '|', $wrongPhrases ) . ')~sDu'; 00442 $nonXHTMLMessages = array(); 00443 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00444 if ( preg_match( $wrongPhrases, $value ) ) { 00445 $nonXHTMLMessages[$key] = $value; 00446 } 00447 } 00448 return $nonXHTMLMessages; 00449 } 00450 00458 public function getMessagesWithWrongChars( $code ) { 00459 $this->loadGeneralMessages(); 00460 $this->loadMessages( $code ); 00461 $wrongChars = array( 00462 '[LRM]' => "\xE2\x80\x8E", 00463 '[RLM]' => "\xE2\x80\x8F", 00464 '[LRE]' => "\xE2\x80\xAA", 00465 '[RLE]' => "\xE2\x80\xAB", 00466 '[POP]' => "\xE2\x80\xAC", 00467 '[LRO]' => "\xE2\x80\xAD", 00468 '[RLO]' => "\xE2\x80\xAB", 00469 '[ZWSP]' => "\xE2\x80\x8B", 00470 '[NBSP]' => "\xC2\xA0", 00471 '[WJ]' => "\xE2\x81\xA0", 00472 '[BOM]' => "\xEF\xBB\xBF", 00473 '[FFFD]' => "\xEF\xBF\xBD", 00474 ); 00475 $wrongRegExp = '/(' . implode( '|', array_values( $wrongChars ) ) . ')/sDu'; 00476 $wrongCharsMessages = array(); 00477 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00478 if ( preg_match( $wrongRegExp, $value ) ) { 00479 foreach ( $wrongChars as $viewableChar => $hiddenChar ) { 00480 $value = str_replace( $hiddenChar, $viewableChar, $value ); 00481 } 00482 $wrongCharsMessages[$key] = $value; 00483 } 00484 } 00485 return $wrongCharsMessages; 00486 } 00487 00495 public function getMessagesWithDubiousLinks( $code ) { 00496 $this->loadGeneralMessages(); 00497 $this->loadMessages( $code ); 00498 $tc = Title::legalChars() . '#%{}'; 00499 $messages = array(); 00500 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00501 $matches = array(); 00502 preg_match_all( "/\[\[([{$tc}]+)(?:\\|(.+?))?]]/sDu", $value, $matches ); 00503 for ( $i = 0; $i < count( $matches[0] ); $i++ ) { 00504 if ( preg_match( "/.*project.*/isDu", $matches[1][$i] ) ) { 00505 $messages[$key][] = $matches[0][$i]; 00506 } 00507 } 00508 00509 00510 if ( isset( $messages[$key] ) ) { 00511 $messages[$key] = implode( $messages[$key], ", " ); 00512 } 00513 } 00514 return $messages; 00515 } 00516 00524 public function getMessagesWithUnbalanced( $code ) { 00525 $this->loadGeneralMessages(); 00526 $this->loadMessages( $code ); 00527 $messages = array(); 00528 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00529 $a = $b = $c = $d = 0; 00530 foreach ( preg_split( '//', $value ) as $char ) { 00531 switch ( $char ) { 00532 case '[': 00533 $a++; 00534 break; 00535 case ']': 00536 $b++; 00537 break; 00538 case '{': 00539 $c++; 00540 break; 00541 case '}': 00542 $d++; 00543 break; 00544 } 00545 } 00546 00547 if ( $a !== $b || $c !== $d ) { 00548 $messages[$key] = "$a, $b, $c, $d"; 00549 } 00550 00551 } 00552 return $messages; 00553 } 00554 00562 public function getUntranslatedNamespaces( $code ) { 00563 $this->loadFile( 'en' ); 00564 $this->loadFile( $code ); 00565 $namespacesDiff = array_diff_key( $this->mNamespaceNames['en'], $this->mNamespaceNames[$code] ); 00566 if ( isset( $namespacesDiff[NS_MAIN] ) ) { 00567 unset( $namespacesDiff[NS_MAIN] ); 00568 } 00569 return $namespacesDiff; 00570 } 00571 00579 public function getProblematicProjectTalks( $code ) { 00580 $this->loadFile( $code ); 00581 $namespaces = array(); 00582 00583 # Check default namespace name 00584 if ( isset( $this->mNamespaceNames[$code][NS_PROJECT_TALK] ) ) { 00585 $default = $this->mNamespaceNames[$code][NS_PROJECT_TALK]; 00586 if ( strpos( $default, '$1' ) === false ) { 00587 $namespaces[$default] = 'default'; 00588 } 00589 } 00590 00591 # Check namespace aliases 00592 foreach ( $this->mNamespaceAliases[$code] as $key => $value ) { 00593 if ( $value == NS_PROJECT_TALK && strpos( $key, '$1' ) === false ) { 00594 $namespaces[$key] = ''; 00595 } 00596 } 00597 00598 return $namespaces; 00599 } 00600 00608 public function getUntranslatedMagicWords( $code ) { 00609 $this->loadFile( 'en' ); 00610 $this->loadFile( $code ); 00611 $magicWords = array(); 00612 foreach ( $this->mMagicWords['en'] as $key => $value ) { 00613 if ( !isset( $this->mMagicWords[$code][$key] ) ) { 00614 $magicWords[$key] = $value[1]; 00615 } 00616 } 00617 return $magicWords; 00618 } 00619 00627 public function getObsoleteMagicWords( $code ) { 00628 $this->loadFile( 'en' ); 00629 $this->loadFile( $code ); 00630 $magicWords = array(); 00631 foreach ( $this->mMagicWords[$code] as $key => $value ) { 00632 if ( !isset( $this->mMagicWords['en'][$key] ) ) { 00633 $magicWords[$key] = $value[1]; 00634 } 00635 } 00636 return $magicWords; 00637 } 00638 00646 public function getOverridingMagicWords( $code ) { 00647 $this->loadFile( 'en' ); 00648 $this->loadFile( $code ); 00649 $magicWords = array(); 00650 foreach ( $this->mMagicWords[$code] as $key => $local ) { 00651 if ( !isset( $this->mMagicWords['en'][$key] ) ) { 00652 # Unrecognized magic word 00653 continue; 00654 } 00655 $en = $this->mMagicWords['en'][$key]; 00656 array_shift( $local ); 00657 array_shift( $en ); 00658 foreach ( $en as $word ) { 00659 if ( !in_array( $word, $local ) ) { 00660 $magicWords[$key] = $word; 00661 break; 00662 } 00663 } 00664 } 00665 return $magicWords; 00666 } 00667 00675 public function getCaseMismatchMagicWords( $code ) { 00676 $this->loadFile( 'en' ); 00677 $this->loadFile( $code ); 00678 $magicWords = array(); 00679 foreach ( $this->mMagicWords[$code] as $key => $local ) { 00680 if ( !isset( $this->mMagicWords['en'][$key] ) ) { 00681 # Unrecognized magic word 00682 continue; 00683 } 00684 if ( $local[0] != $this->mMagicWords['en'][$key][0] ) { 00685 $magicWords[$key] = $local[0]; 00686 } 00687 } 00688 return $magicWords; 00689 } 00690 00698 public function getUntraslatedSpecialPages( $code ) { 00699 $this->loadFile( 'en' ); 00700 $this->loadFile( $code ); 00701 $specialPageAliases = array(); 00702 foreach ( $this->mSpecialPageAliases['en'] as $key => $value ) { 00703 if ( !isset( $this->mSpecialPageAliases[$code][$key] ) ) { 00704 $specialPageAliases[$key] = $value[0]; 00705 } 00706 } 00707 return $specialPageAliases; 00708 } 00709 00717 public function getObsoleteSpecialPages( $code ) { 00718 $this->loadFile( 'en' ); 00719 $this->loadFile( $code ); 00720 $specialPageAliases = array(); 00721 foreach ( $this->mSpecialPageAliases[$code] as $key => $value ) { 00722 if ( !isset( $this->mSpecialPageAliases['en'][$key] ) ) { 00723 $specialPageAliases[$key] = $value[0]; 00724 } 00725 } 00726 return $specialPageAliases; 00727 } 00728 } 00729 00730 class extensionLanguages extends languages { 00731 00735 private $mMessageGroup; 00736 00741 function __construct( MessageGroup $group ) { 00742 $this->mMessageGroup = $group; 00743 00744 $this->mIgnoredMessages = $this->mMessageGroup->getIgnored(); 00745 $this->mOptionalMessages = $this->mMessageGroup->getOptional(); 00746 } 00747 00753 public function name() { 00754 return $this->mMessageGroup->getLabel(); 00755 } 00756 00762 protected function loadFile( $code ) { 00763 if ( !isset( $this->mRawMessages[$code] ) ) { 00764 $this->mRawMessages[$code] = $this->mMessageGroup->load( $code ); 00765 if ( empty( $this->mRawMessages[$code] ) ) { 00766 $this->mRawMessages[$code] = array(); 00767 } 00768 } 00769 } 00770 }