00001 <?php 00012 class languages { 00013 protected $mLanguages; # List of languages 00014 00015 protected $mRawMessages; # Raw list of the messages in each language 00016 protected $mMessages; # Messages in each language (except for English), divided to groups 00017 protected $mGeneralMessages; # General messages in English, divided to groups 00018 protected $mIgnoredMessages; # All the messages which should be exist only in the English file 00019 protected $mOptionalMessages; # All the messages which may be translated or not, depending on the language 00020 00021 protected $mNamespaceNames; # Namespace names 00022 protected $mNamespaceAliases; # Namespace aliases 00023 protected $mMagicWords; # Magic words 00024 protected $mSpecialPageAliases; # Special page aliases 00025 00032 function __construct( $exif = true ) { 00033 require( dirname(__FILE__) . '/messageTypes.inc' ); 00034 $this->mIgnoredMessages = $wgIgnoredMessages; 00035 if ( $exif ) { 00036 $this->mOptionalMessages = array_merge( $wgOptionalMessages ); 00037 } else { 00038 $this->mOptionalMessages = array_merge( $wgOptionalMessages, $wgEXIFMessages ); 00039 } 00040 00041 $this->mLanguages = array_keys( Language::getLanguageNames( true ) ); 00042 sort( $this->mLanguages ); 00043 } 00044 00050 public function getLanguages() { 00051 return $this->mLanguages; 00052 } 00053 00059 public function getIgnoredMessages() { 00060 return $this->mIgnoredMessages; 00061 } 00062 00068 public function getOptionalMessages() { 00069 return $this->mOptionalMessages; 00070 } 00071 00077 protected function loadFile( $code ) { 00078 if ( isset( $this->mRawMessages[$code] ) && 00079 isset( $this->mNamespaceNames[$code] ) && 00080 isset( $this->mNamespaceAliases[$code] ) && 00081 isset( $this->mMagicWords[$code] ) && 00082 isset( $this->mSpecialPageAliases[$code] ) ) { 00083 return; 00084 } 00085 $this->mRawMessages[$code] = array(); 00086 $this->mNamespaceNames[$code] = array(); 00087 $this->mNamespaceAliases[$code] = array(); 00088 $this->mMagicWords[$code] = array(); 00089 $this->mSpecialPageAliases[$code] = array(); 00090 $filename = Language::getMessagesFileName( $code ); 00091 if ( file_exists( $filename ) ) { 00092 require( $filename ); 00093 if ( isset( $messages ) ) { 00094 $this->mRawMessages[$code] = $messages; 00095 } 00096 if ( isset( $namespaceNames ) ) { 00097 $this->mNamespaceNames[$code] = $namespaceNames; 00098 } 00099 if ( isset( $namespaceAliases ) ) { 00100 $this->mNamespaceAliases[$code] = $namespaceAliases; 00101 } 00102 if ( isset( $magicWords ) ) { 00103 $this->mMagicWords[$code] = $magicWords; 00104 } 00105 if ( isset( $specialPageAliases ) ) { 00106 $this->mSpecialPageAliases[$code] = $specialPageAliases; 00107 } 00108 } 00109 } 00110 00121 private function loadMessages( $code ) { 00122 if ( isset( $this->mMessages[$code] ) ) { 00123 return; 00124 } 00125 $this->loadFile( $code ); 00126 $this->loadGeneralMessages(); 00127 $this->mMessages[$code]['all'] = $this->mRawMessages[$code]; 00128 $this->mMessages[$code]['required'] = array(); 00129 $this->mMessages[$code]['optional'] = array(); 00130 $this->mMessages[$code]['obsolete'] = array(); 00131 $this->mMessages[$code]['translated'] = array(); 00132 foreach ( $this->mMessages[$code]['all'] as $key => $value ) { 00133 if ( isset( $this->mGeneralMessages['required'][$key] ) ) { 00134 $this->mMessages[$code]['required'][$key] = $value; 00135 $this->mMessages[$code]['translated'][$key] = $value; 00136 } else if ( isset( $this->mGeneralMessages['optional'][$key] ) ) { 00137 $this->mMessages[$code]['optional'][$key] = $value; 00138 $this->mMessages[$code]['translated'][$key] = $value; 00139 } else { 00140 $this->mMessages[$code]['obsolete'][$key] = $value; 00141 } 00142 } 00143 } 00144 00153 private function loadGeneralMessages() { 00154 if ( isset( $this->mGeneralMessages ) ) { 00155 return; 00156 } 00157 $this->loadFile( 'en' ); 00158 $this->mGeneralMessages['all'] = $this->mRawMessages['en']; 00159 $this->mGeneralMessages['required'] = array(); 00160 $this->mGeneralMessages['optional'] = array(); 00161 $this->mGeneralMessages['ignored'] = array(); 00162 $this->mGeneralMessages['translatable'] = array(); 00163 foreach ( $this->mGeneralMessages['all'] as $key => $value ) { 00164 if ( in_array( $key, $this->mIgnoredMessages ) ) { 00165 $this->mGeneralMessages['ignored'][$key] = $value; 00166 } else if ( in_array( $key, $this->mOptionalMessages ) ) { 00167 $this->mGeneralMessages['optional'][$key] = $value; 00168 $this->mGeneralMessages['translatable'][$key] = $value; 00169 } else { 00170 $this->mGeneralMessages['required'][$key] = $value; 00171 $this->mGeneralMessages['translatable'][$key] = $value; 00172 } 00173 } 00174 } 00175 00189 public function getMessages( $code ) { 00190 $this->loadMessages( $code ); 00191 return $this->mMessages[$code]; 00192 } 00193 00204 public function getGeneralMessages() { 00205 $this->loadGeneralMessages(); 00206 return $this->mGeneralMessages; 00207 } 00208 00216 public function getNamespaceNames( $code ) { 00217 $this->loadFile( $code ); 00218 return $this->mNamespaceNames[$code]; 00219 } 00220 00228 public function getNamespaceAliases( $code ) { 00229 $this->loadFile( $code ); 00230 return $this->mNamespaceAliases[$code]; 00231 } 00232 00240 public function getMagicWords( $code ) { 00241 $this->loadFile( $code ); 00242 return $this->mMagicWords[$code]; 00243 } 00244 00252 public function getSpecialPageAliases( $code ) { 00253 $this->loadFile( $code ); 00254 return $this->mSpecialPageAliases[$code]; 00255 } 00256 00264 public function getUntranslatedMessages( $code ) { 00265 $this->loadGeneralMessages(); 00266 $this->loadMessages( $code ); 00267 return array_diff_key( $this->mGeneralMessages['required'], $this->mMessages[$code]['required'] ); 00268 } 00269 00277 public function getDuplicateMessages( $code ) { 00278 $this->loadGeneralMessages(); 00279 $this->loadMessages( $code ); 00280 $duplicateMessages = array(); 00281 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00282 if ( $this->mGeneralMessages['translatable'][$key] == $value ) { 00283 $duplicateMessages[$key] = $value; 00284 } 00285 } 00286 return $duplicateMessages; 00287 } 00288 00296 public function getObsoleteMessages( $code ) { 00297 $this->loadGeneralMessages(); 00298 $this->loadMessages( $code ); 00299 return $this->mMessages[$code]['obsolete']; 00300 } 00301 00309 public function getMessagesWithMismatchVariables( $code ) { 00310 $this->loadGeneralMessages(); 00311 $this->loadMessages( $code ); 00312 $variables = array( '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' ); 00313 $mismatchMessages = array(); 00314 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00315 $missing = false; 00316 foreach ( $variables as $var ) { 00317 if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) && 00318 !preg_match( "/$var/sU", $value ) ) { 00319 $missing = true; 00320 } 00321 if ( !preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) && 00322 preg_match( "/$var/sU", $value ) ) { 00323 $missing = true; 00324 } 00325 } 00326 if ( $missing ) { 00327 $mismatchMessages[$key] = $value; 00328 } 00329 } 00330 return $mismatchMessages; 00331 } 00332 00340 public function getMessagesWithoutPlural( $code ) { 00341 $this->loadGeneralMessages(); 00342 $this->loadMessages( $code ); 00343 $messagesWithoutPlural = array(); 00344 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00345 if ( stripos( $this->mGeneralMessages['translatable'][$key], '{{plural:' ) !== false && stripos( $value, '{{plural:' ) === false ) { 00346 $messagesWithoutPlural[$key] = $value; 00347 } 00348 } 00349 return $messagesWithoutPlural; 00350 } 00351 00359 public function getEmptyMessages( $code ) { 00360 $this->loadGeneralMessages(); 00361 $this->loadMessages( $code ); 00362 $emptyMessages = array(); 00363 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00364 if ( $value === '' || $value === '-' ) { 00365 $emptyMessages[$key] = $value; 00366 } 00367 } 00368 return $emptyMessages; 00369 } 00370 00378 public function getMessagesWithWhitespace( $code ) { 00379 $this->loadGeneralMessages(); 00380 $this->loadMessages( $code ); 00381 $messagesWithWhitespace = array(); 00382 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00383 if ( $this->mGeneralMessages['translatable'][$key] !== '' && $value !== rtrim( $value ) ) { 00384 $messagesWithWhitespace[$key] = $value; 00385 } 00386 } 00387 return $messagesWithWhitespace; 00388 } 00389 00397 public function getNonXHTMLMessages( $code ) { 00398 $this->loadGeneralMessages(); 00399 $this->loadMessages( $code ); 00400 $wrongPhrases = array( 00401 '<hr *\\?>', 00402 '<br *\\?>', 00403 '<hr/>', 00404 '<br/>', 00405 '<hr>', 00406 '<br>', 00407 ); 00408 $wrongPhrases = '~(' . implode( '|', $wrongPhrases ) . ')~sDu'; 00409 $nonXHTMLMessages = array(); 00410 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00411 if ( preg_match( $wrongPhrases, $value ) ) { 00412 $nonXHTMLMessages[$key] = $value; 00413 } 00414 } 00415 return $nonXHTMLMessages; 00416 } 00417 00425 public function getMessagesWithWrongChars( $code ) { 00426 $this->loadGeneralMessages(); 00427 $this->loadMessages( $code ); 00428 $wrongChars = array( 00429 '[LRM]' => "\xE2\x80\x8E", 00430 '[RLM]' => "\xE2\x80\x8F", 00431 '[LRE]' => "\xE2\x80\xAA", 00432 '[RLE]' => "\xE2\x80\xAB", 00433 '[POP]' => "\xE2\x80\xAC", 00434 '[LRO]' => "\xE2\x80\xAD", 00435 '[RLO]' => "\xE2\x80\xAB", 00436 '[ZWSP]'=> "\xE2\x80\x8B", 00437 '[NBSP]'=> "\xC2\xA0", 00438 '[WJ]' => "\xE2\x81\xA0", 00439 '[BOM]' => "\xEF\xBB\xBF", 00440 '[FFFD]'=> "\xEF\xBF\xBD", 00441 ); 00442 $wrongRegExp = '/(' . implode( '|', array_values( $wrongChars ) ) . ')/sDu'; 00443 $wrongCharsMessages = array(); 00444 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00445 if ( preg_match( $wrongRegExp, $value ) ) { 00446 foreach ( $wrongChars as $viewableChar => $hiddenChar ) { 00447 $value = str_replace( $hiddenChar, $viewableChar, $value ); 00448 } 00449 $wrongCharsMessages[$key] = $value; 00450 } 00451 } 00452 return $wrongCharsMessages; 00453 } 00454 00462 public function getMessagesWithDubiousLinks( $code ) { 00463 $this->loadGeneralMessages(); 00464 $this->loadMessages( $code ); 00465 $tc = Title::legalChars() . '#%{}'; 00466 $messages = array(); 00467 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00468 $matches = array(); 00469 preg_match_all( "/\[\[([{$tc}]+)(?:\\|(.+?))?]]/sDu", $value, $matches ); 00470 for ($i = 0; $i < count($matches[0]); $i++ ) { 00471 if ( preg_match( "/.*project.*/isDu", $matches[1][$i] ) ) { 00472 $messages[$key][] = $matches[0][$i]; 00473 } 00474 } 00475 00476 00477 if ( isset( $messages[$key] ) ) { 00478 $messages[$key] = implode( $messages[$key],", " ); 00479 } 00480 } 00481 return $messages; 00482 } 00483 00491 public function getMessagesWithUnbalanced( $code ) { 00492 $this->loadGeneralMessages(); 00493 $this->loadMessages( $code ); 00494 $messages = array(); 00495 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { 00496 $a = $b = $c = $d = 0; 00497 foreach ( preg_split( '//', $value ) as $char ) { 00498 switch ( $char ) { 00499 case '[': 00500 $a++; 00501 break; 00502 case ']': 00503 $b++; 00504 break; 00505 case '{': 00506 $c++; 00507 break; 00508 case '}': 00509 $d++; 00510 break; 00511 } 00512 } 00513 00514 if ( $a !== $b || $c !== $d ) { 00515 $messages[$key] = "$a, $b, $c, $d"; 00516 } 00517 00518 } 00519 return $messages; 00520 } 00521 00529 public function getUntranslatedNamespaces( $code ) { 00530 $this->loadFile( 'en' ); 00531 $this->loadFile( $code ); 00532 return array_flip( array_diff_key( $this->mNamespaceNames['en'], $this->mNamespaceNames[$code] ) ); 00533 } 00534 00542 public function getProblematicProjectTalks( $code ) { 00543 $this->loadFile( $code ); 00544 $namespaces = array(); 00545 00546 # Check default namespace name 00547 if( isset( $this->mNamespaceNames[$code][NS_PROJECT_TALK] ) ) { 00548 $default = $this->mNamespaceNames[$code][NS_PROJECT_TALK]; 00549 if ( strpos( $default, '$1' ) === FALSE ) { 00550 $namespaces[$default] = 'default'; 00551 } 00552 } 00553 00554 # Check namespace aliases 00555 foreach( $this->mNamespaceAliases[$code] as $key => $value ) { 00556 if ( $value == NS_PROJECT_TALK && strpos( $key, '$1' ) === FALSE ) { 00557 $namespaces[$key] = ''; 00558 } 00559 } 00560 00561 return $namespaces; 00562 } 00563 00571 public function getUntranslatedMagicWords( $code ) { 00572 $this->loadFile( 'en' ); 00573 $this->loadFile( $code ); 00574 $magicWords = array(); 00575 foreach ( $this->mMagicWords['en'] as $key => $value ) { 00576 if ( !isset( $this->mMagicWords[$code][$key] ) ) { 00577 $magicWords[$key] = $value[1]; 00578 } 00579 } 00580 return $magicWords; 00581 } 00582 00590 public function getObsoleteMagicWords( $code ) { 00591 $this->loadFile( 'en' ); 00592 $this->loadFile( $code ); 00593 $magicWords = array(); 00594 foreach ( $this->mMagicWords[$code] as $key => $value ) { 00595 if ( !isset( $this->mMagicWords['en'][$key] ) ) { 00596 $magicWords[$key] = $value[1]; 00597 } 00598 } 00599 return $magicWords; 00600 } 00601 00609 public function getOverridingMagicWords( $code ) { 00610 $this->loadFile( 'en' ); 00611 $this->loadFile( $code ); 00612 $magicWords = array(); 00613 foreach ( $this->mMagicWords[$code] as $key => $local ) { 00614 if ( !isset( $this->mMagicWords['en'][$key] ) ) { 00615 # Unrecognized magic word 00616 continue; 00617 } 00618 $en = $this->mMagicWords['en'][$key]; 00619 array_shift( $local ); 00620 array_shift( $en ); 00621 foreach ( $en as $word ) { 00622 if ( !in_array( $word, $local ) ) { 00623 $magicWords[$key] = $word; 00624 break; 00625 } 00626 } 00627 } 00628 return $magicWords; 00629 } 00630 00638 public function getCaseMismatchMagicWords( $code ) { 00639 $this->loadFile( 'en' ); 00640 $this->loadFile( $code ); 00641 $magicWords = array(); 00642 foreach ( $this->mMagicWords[$code] as $key => $local ) { 00643 if ( !isset( $this->mMagicWords['en'][$key] ) ) { 00644 # Unrecognized magic word 00645 continue; 00646 } 00647 if ( $local[0] != $this->mMagicWords['en'][$key][0] ) { 00648 $magicWords[$key] = $local[0]; 00649 } 00650 } 00651 return $magicWords; 00652 } 00653 00661 public function getUntraslatedSpecialPages( $code ) { 00662 $this->loadFile( 'en' ); 00663 $this->loadFile( $code ); 00664 $specialPageAliases = array(); 00665 foreach ( $this->mSpecialPageAliases['en'] as $key => $value ) { 00666 if ( !isset( $this->mSpecialPageAliases[$code][$key] ) ) { 00667 $specialPageAliases[$key] = $value[0]; 00668 } 00669 } 00670 return $specialPageAliases; 00671 } 00672 00680 public function getObsoleteSpecialPages( $code ) { 00681 $this->loadFile( 'en' ); 00682 $this->loadFile( $code ); 00683 $specialPageAliases = array(); 00684 foreach ( $this->mSpecialPageAliases[$code] as $key => $value ) { 00685 if ( !isset( $this->mSpecialPageAliases['en'][$key] ) ) { 00686 $specialPageAliases[$key] = $value[0]; 00687 } 00688 } 00689 return $specialPageAliases; 00690 } 00691 } 00692 00693 class extensionLanguages extends languages { 00694 private $mMessageGroup; # The message group 00695 00700 function __construct( MessageGroup $group ) { 00701 $this->mMessageGroup = $group; 00702 00703 $bools = $this->mMessageGroup->getBools(); 00704 $this->mIgnoredMessages = $bools['ignored']; 00705 $this->mOptionalMessages = $bools['optional']; 00706 } 00707 00713 public function name() { 00714 return $this->mMessageGroup->getLabel(); 00715 } 00716 00722 protected function loadFile( $code ) { 00723 if( !isset( $this->mRawMessages[$code] ) ) { 00724 $this->mRawMessages[$code] = $this->mMessageGroup->load( $code ); 00725 if( empty( $this->mRawMessages[$code] ) ) { 00726 $this->mRawMessages[$code] = array(); 00727 } 00728 } 00729 } 00730 }