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