MediaWiki  REL1_23
languages.inc
Go to the documentation of this file.
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 }