MediaWiki  REL1_24
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 
00065     function __construct() {
00066         wfRunHooks( 'LocalisationIgnoredOptionalMessages',
00067             array( &$this->mIgnoredMessages, &$this->mOptionalMessages ) );
00068 
00069         $this->mLanguages = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) );
00070         sort( $this->mLanguages );
00071     }
00072 
00078     public function getLanguages() {
00079         return $this->mLanguages;
00080     }
00081 
00087     public function getIgnoredMessages() {
00088         return $this->mIgnoredMessages;
00089     }
00090 
00096     public function getOptionalMessages() {
00097         return $this->mOptionalMessages;
00098     }
00099 
00105     protected function loadFile( $code ) {
00106         if ( isset( $this->mRawMessages[$code] ) &&
00107             isset( $this->mFallback[$code] ) &&
00108             isset( $this->mNamespaceNames[$code] ) &&
00109             isset( $this->mNamespaceAliases[$code] ) &&
00110             isset( $this->mMagicWords[$code] ) &&
00111             isset( $this->mSpecialPageAliases[$code] )
00112         ) {
00113             return;
00114         }
00115         $this->mRawMessages[$code] = array();
00116         $this->mFallback[$code] = '';
00117         $this->mNamespaceNames[$code] = array();
00118         $this->mNamespaceAliases[$code] = array();
00119         $this->mMagicWords[$code] = array();
00120         $this->mSpecialPageAliases[$code] = array();
00121 
00122         $jsonfilename = Language::getJsonMessagesFileName( $code );
00123         if ( file_exists( $jsonfilename ) ) {
00124             $json = Language::getLocalisationCache()->readJSONFile( $jsonfilename );
00125             $this->mRawMessages[$code] = $json['messages'];
00126         }
00127 
00128         $filename = Language::getMessagesFileName( $code );
00129         if ( file_exists( $filename ) ) {
00130             require $filename;
00131             if ( isset( $fallback ) ) {
00132                 $this->mFallback[$code] = $fallback;
00133             }
00134             if ( isset( $namespaceNames ) ) {
00135                 $this->mNamespaceNames[$code] = $namespaceNames;
00136             }
00137             if ( isset( $namespaceAliases ) ) {
00138                 $this->mNamespaceAliases[$code] = $namespaceAliases;
00139             }
00140             if ( isset( $magicWords ) ) {
00141                 $this->mMagicWords[$code] = $magicWords;
00142             }
00143             if ( isset( $specialPageAliases ) ) {
00144                 $this->mSpecialPageAliases[$code] = $specialPageAliases;
00145             }
00146         }
00147     }
00148 
00163     private function loadMessages( $code ) {
00164         if ( isset( $this->mMessages[$code] ) ) {
00165             return;
00166         }
00167         $this->loadFile( $code );
00168         $this->loadGeneralMessages();
00169         $this->mMessages[$code]['all'] = $this->mRawMessages[$code];
00170         $this->mMessages[$code]['required'] = array();
00171         $this->mMessages[$code]['optional'] = array();
00172         $this->mMessages[$code]['obsolete'] = array();
00173         $this->mMessages[$code]['translated'] = array();
00174         foreach ( $this->mMessages[$code]['all'] as $key => $value ) {
00175             if ( isset( $this->mGeneralMessages['required'][$key] ) ) {
00176                 $this->mMessages[$code]['required'][$key] = $value;
00177                 $this->mMessages[$code]['translated'][$key] = $value;
00178             } elseif ( isset( $this->mGeneralMessages['optional'][$key] ) ) {
00179                 $this->mMessages[$code]['optional'][$key] = $value;
00180                 $this->mMessages[$code]['translated'][$key] = $value;
00181             } else {
00182                 $this->mMessages[$code]['obsolete'][$key] = $value;
00183             }
00184         }
00185     }
00186 
00198     private function loadGeneralMessages() {
00199         if ( isset( $this->mGeneralMessages ) ) {
00200             return;
00201         }
00202         $this->loadFile( 'en' );
00203         $this->mGeneralMessages['all'] = $this->mRawMessages['en'];
00204         $this->mGeneralMessages['required'] = array();
00205         $this->mGeneralMessages['optional'] = array();
00206         $this->mGeneralMessages['ignored'] = array();
00207         $this->mGeneralMessages['translatable'] = array();
00208         foreach ( $this->mGeneralMessages['all'] as $key => $value ) {
00209             if ( in_array( $key, $this->mIgnoredMessages ) ) {
00210                 $this->mGeneralMessages['ignored'][$key] = $value;
00211             } elseif ( in_array( $key, $this->mOptionalMessages ) ) {
00212                 $this->mGeneralMessages['optional'][$key] = $value;
00213                 $this->mGeneralMessages['translatable'][$key] = $value;
00214             } else {
00215                 $this->mGeneralMessages['required'][$key] = $value;
00216                 $this->mGeneralMessages['translatable'][$key] = $value;
00217             }
00218         }
00219     }
00220 
00237     public function getMessages( $code ) {
00238         $this->loadMessages( $code );
00239 
00240         return $this->mMessages[$code];
00241     }
00242 
00256     public function getGeneralMessages() {
00257         $this->loadGeneralMessages();
00258 
00259         return $this->mGeneralMessages;
00260     }
00261 
00269     public function getFallback( $code ) {
00270         $this->loadFile( $code );
00271 
00272         return $this->mFallback[$code];
00273     }
00274 
00282     public function getNamespaceNames( $code ) {
00283         $this->loadFile( $code );
00284 
00285         return $this->mNamespaceNames[$code];
00286     }
00287 
00295     public function getNamespaceAliases( $code ) {
00296         $this->loadFile( $code );
00297 
00298         return $this->mNamespaceAliases[$code];
00299     }
00300 
00308     public function getMagicWords( $code ) {
00309         $this->loadFile( $code );
00310 
00311         return $this->mMagicWords[$code];
00312     }
00313 
00321     public function getSpecialPageAliases( $code ) {
00322         $this->loadFile( $code );
00323 
00324         return $this->mSpecialPageAliases[$code];
00325     }
00326 
00334     public function getUntranslatedMessages( $code ) {
00335         $this->loadGeneralMessages();
00336         $this->loadMessages( $code );
00337 
00338         return array_diff_key( $this->mGeneralMessages['required'], $this->mMessages[$code]['required'] );
00339     }
00340 
00348     public function getDuplicateMessages( $code ) {
00349         $this->loadGeneralMessages();
00350         $this->loadMessages( $code );
00351         $duplicateMessages = array();
00352         foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
00353             if ( $this->mGeneralMessages['translatable'][$key] == $value ) {
00354                 $duplicateMessages[$key] = $value;
00355             }
00356         }
00357 
00358         return $duplicateMessages;
00359     }
00360 
00368     public function getObsoleteMessages( $code ) {
00369         $this->loadGeneralMessages();
00370         $this->loadMessages( $code );
00371 
00372         return $this->mMessages[$code]['obsolete'];
00373     }
00374 
00382     public function getMessagesWithMismatchVariables( $code ) {
00383         $this->loadGeneralMessages();
00384         $this->loadMessages( $code );
00385         $variables = array( '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' );
00386         $mismatchMessages = array();
00387         foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
00388             $missing = false;
00389             foreach ( $variables as $var ) {
00390                 if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
00391                     !preg_match( "/$var/sU", $value )
00392                 ) {
00393                     $missing = true;
00394                 }
00395                 if ( !preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
00396                     preg_match( "/$var/sU", $value )
00397                 ) {
00398                     $missing = true;
00399                 }
00400             }
00401             if ( $missing ) {
00402                 $mismatchMessages[$key] = $value;
00403             }
00404         }
00405 
00406         return $mismatchMessages;
00407     }
00408 
00416     public function getMessagesWithoutPlural( $code ) {
00417         $this->loadGeneralMessages();
00418         $this->loadMessages( $code );
00419         $messagesWithoutPlural = array();
00420         foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
00421             if ( stripos( $this->mGeneralMessages['translatable'][$key], '{{plural:' ) !== false &&
00422                 stripos( $value, '{{plural:' ) === false
00423             ) {
00424                 $messagesWithoutPlural[$key] = $value;
00425             }
00426         }
00427 
00428         return $messagesWithoutPlural;
00429     }
00430 
00438     public function getEmptyMessages( $code ) {
00439         $this->loadGeneralMessages();
00440         $this->loadMessages( $code );
00441         $emptyMessages = array();
00442         foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
00443             if ( $value === '' || $value === '-' ) {
00444                 $emptyMessages[$key] = $value;
00445             }
00446         }
00447 
00448         return $emptyMessages;
00449     }
00450 
00458     public function getMessagesWithWhitespace( $code ) {
00459         $this->loadGeneralMessages();
00460         $this->loadMessages( $code );
00461         $messagesWithWhitespace = array();
00462         foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
00463             if ( $this->mGeneralMessages['translatable'][$key] !== '' && $value !== rtrim( $value ) ) {
00464                 $messagesWithWhitespace[$key] = $value;
00465             }
00466         }
00467 
00468         return $messagesWithWhitespace;
00469     }
00470 
00478     public function getNonXHTMLMessages( $code ) {
00479         $this->loadGeneralMessages();
00480         $this->loadMessages( $code );
00481         $wrongPhrases = array(
00482             '<hr *\\?>',
00483             '<br *\\?>',
00484             '<hr/>',
00485             '<br/>',
00486             '<hr>',
00487             '<br>',
00488         );
00489         $wrongPhrases = '~(' . implode( '|', $wrongPhrases ) . ')~sDu';
00490         $nonXHTMLMessages = array();
00491         foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
00492             if ( preg_match( $wrongPhrases, $value ) ) {
00493                 $nonXHTMLMessages[$key] = $value;
00494             }
00495         }
00496 
00497         return $nonXHTMLMessages;
00498     }
00499 
00507     public function getMessagesWithWrongChars( $code ) {
00508         $this->loadGeneralMessages();
00509         $this->loadMessages( $code );
00510         $wrongChars = array(
00511             '[LRM]' => "\xE2\x80\x8E",
00512             '[RLM]' => "\xE2\x80\x8F",
00513             '[LRE]' => "\xE2\x80\xAA",
00514             '[RLE]' => "\xE2\x80\xAB",
00515             '[POP]' => "\xE2\x80\xAC",
00516             '[LRO]' => "\xE2\x80\xAD",
00517             '[RLO]' => "\xE2\x80\xAB",
00518             '[ZWSP]' => "\xE2\x80\x8B",
00519             '[NBSP]' => "\xC2\xA0",
00520             '[WJ]' => "\xE2\x81\xA0",
00521             '[BOM]' => "\xEF\xBB\xBF",
00522             '[FFFD]' => "\xEF\xBF\xBD",
00523         );
00524         $wrongRegExp = '/(' . implode( '|', array_values( $wrongChars ) ) . ')/sDu';
00525         $wrongCharsMessages = array();
00526         foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
00527             if ( preg_match( $wrongRegExp, $value ) ) {
00528                 foreach ( $wrongChars as $viewableChar => $hiddenChar ) {
00529                     $value = str_replace( $hiddenChar, $viewableChar, $value );
00530                 }
00531                 $wrongCharsMessages[$key] = $value;
00532             }
00533         }
00534 
00535         return $wrongCharsMessages;
00536     }
00537 
00545     public function getMessagesWithDubiousLinks( $code ) {
00546         $this->loadGeneralMessages();
00547         $this->loadMessages( $code );
00548         $tc = Title::legalChars() . '#%{}';
00549         $messages = array();
00550         foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
00551             $matches = array();
00552             preg_match_all( "/\[\[([{$tc}]+)(?:\\|(.+?))?]]/sDu", $value, $matches );
00553             $numMatches = count( $matches[0] );
00554             for ( $i = 0; $i < $numMatches; $i++ ) {
00555                 if ( preg_match( "/.*project.*/isDu", $matches[1][$i] ) ) {
00556                     $messages[$key][] = $matches[0][$i];
00557                 }
00558             }
00559 
00560             if ( isset( $messages[$key] ) ) {
00561                 $messages[$key] = implode( $messages[$key], ", " );
00562             }
00563         }
00564 
00565         return $messages;
00566     }
00567 
00575     public function getMessagesWithUnbalanced( $code ) {
00576         $this->loadGeneralMessages();
00577         $this->loadMessages( $code );
00578         $messages = array();
00579         foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
00580             $a = $b = $c = $d = 0;
00581             foreach ( preg_split( '//', $value ) as $char ) {
00582                 switch ( $char ) {
00583                     case '[':
00584                         $a++;
00585                         break;
00586                     case ']':
00587                         $b++;
00588                         break;
00589                     case '{':
00590                         $c++;
00591                         break;
00592                     case '}':
00593                         $d++;
00594                         break;
00595                 }
00596             }
00597 
00598             if ( $a !== $b || $c !== $d ) {
00599                 $messages[$key] = "$a, $b, $c, $d";
00600             }
00601         }
00602 
00603         return $messages;
00604     }
00605 
00613     public function getUntranslatedNamespaces( $code ) {
00614         $this->loadFile( 'en' );
00615         $this->loadFile( $code );
00616         $namespacesDiff = array_diff_key( $this->mNamespaceNames['en'], $this->mNamespaceNames[$code] );
00617         if ( isset( $namespacesDiff[NS_MAIN] ) ) {
00618             unset( $namespacesDiff[NS_MAIN] );
00619         }
00620 
00621         return $namespacesDiff;
00622     }
00623 
00631     public function getProblematicProjectTalks( $code ) {
00632         $this->loadFile( $code );
00633         $namespaces = array();
00634 
00635         # Check default namespace name
00636         if ( isset( $this->mNamespaceNames[$code][NS_PROJECT_TALK] ) ) {
00637             $default = $this->mNamespaceNames[$code][NS_PROJECT_TALK];
00638             if ( strpos( $default, '$1' ) === false ) {
00639                 $namespaces[$default] = 'default';
00640             }
00641         }
00642 
00643         # Check namespace aliases
00644         foreach ( $this->mNamespaceAliases[$code] as $key => $value ) {
00645             if ( $value == NS_PROJECT_TALK && strpos( $key, '$1' ) === false ) {
00646                 $namespaces[$key] = '';
00647             }
00648         }
00649 
00650         return $namespaces;
00651     }
00652 
00660     public function getUntranslatedMagicWords( $code ) {
00661         $this->loadFile( 'en' );
00662         $this->loadFile( $code );
00663         $magicWords = array();
00664         foreach ( $this->mMagicWords['en'] as $key => $value ) {
00665             if ( !isset( $this->mMagicWords[$code][$key] ) ) {
00666                 $magicWords[$key] = $value[1];
00667             }
00668         }
00669 
00670         return $magicWords;
00671     }
00672 
00680     public function getObsoleteMagicWords( $code ) {
00681         $this->loadFile( 'en' );
00682         $this->loadFile( $code );
00683         $magicWords = array();
00684         foreach ( $this->mMagicWords[$code] as $key => $value ) {
00685             if ( !isset( $this->mMagicWords['en'][$key] ) ) {
00686                 $magicWords[$key] = $value[1];
00687             }
00688         }
00689 
00690         return $magicWords;
00691     }
00692 
00700     public function getOverridingMagicWords( $code ) {
00701         $this->loadFile( 'en' );
00702         $this->loadFile( $code );
00703         $magicWords = array();
00704         foreach ( $this->mMagicWords[$code] as $key => $local ) {
00705             if ( !isset( $this->mMagicWords['en'][$key] ) ) {
00706                 # Unrecognized magic word
00707                 continue;
00708             }
00709             $en = $this->mMagicWords['en'][$key];
00710             array_shift( $local );
00711             array_shift( $en );
00712             foreach ( $en as $word ) {
00713                 if ( !in_array( $word, $local ) ) {
00714                     $magicWords[$key] = $word;
00715                     break;
00716                 }
00717             }
00718         }
00719 
00720         return $magicWords;
00721     }
00722 
00730     public function getCaseMismatchMagicWords( $code ) {
00731         $this->loadFile( 'en' );
00732         $this->loadFile( $code );
00733         $magicWords = array();
00734         foreach ( $this->mMagicWords[$code] as $key => $local ) {
00735             if ( !isset( $this->mMagicWords['en'][$key] ) ) {
00736                 # Unrecognized magic word
00737                 continue;
00738             }
00739             if ( $local[0] != $this->mMagicWords['en'][$key][0] ) {
00740                 $magicWords[$key] = $local[0];
00741             }
00742         }
00743 
00744         return $magicWords;
00745     }
00746 
00754     public function getUntraslatedSpecialPages( $code ) {
00755         $this->loadFile( 'en' );
00756         $this->loadFile( $code );
00757         $specialPageAliases = array();
00758         foreach ( $this->mSpecialPageAliases['en'] as $key => $value ) {
00759             if ( !isset( $this->mSpecialPageAliases[$code][$key] ) ) {
00760                 $specialPageAliases[$key] = $value[0];
00761             }
00762         }
00763 
00764         return $specialPageAliases;
00765     }
00766 
00774     public function getObsoleteSpecialPages( $code ) {
00775         $this->loadFile( 'en' );
00776         $this->loadFile( $code );
00777         $specialPageAliases = array();
00778         foreach ( $this->mSpecialPageAliases[$code] as $key => $value ) {
00779             if ( !isset( $this->mSpecialPageAliases['en'][$key] ) ) {
00780                 $specialPageAliases[$key] = $value[0];
00781             }
00782         }
00783 
00784         return $specialPageAliases;
00785     }
00786 }
00787 
00788 class ExtensionLanguages extends Languages {
00792     private $mMessageGroup;
00793 
00798     function __construct( MessageGroup $group ) {
00799         $this->mMessageGroup = $group;
00800 
00801         $this->mIgnoredMessages = $this->mMessageGroup->getIgnored();
00802         $this->mOptionalMessages = $this->mMessageGroup->getOptional();
00803     }
00804 
00810     public function name() {
00811         return $this->mMessageGroup->getLabel();
00812     }
00813 
00819     protected function loadFile( $code ) {
00820         if ( !isset( $this->mRawMessages[$code] ) ) {
00821             $this->mRawMessages[$code] = $this->mMessageGroup->load( $code );
00822             if ( empty( $this->mRawMessages[$code] ) ) {
00823                 $this->mRawMessages[$code] = array();
00824             }
00825         }
00826     }
00827 }