MediaWikiExtensionFFS.php

Go to the documentation of this file.
00001 <?php
00017 class MediaWikiExtensionFFS extends SimpleFFS {
00018     public function supportsFuzzy() {
00019         return 'write';
00020     }
00021 
00022     public function getFileExtensions() {
00023         return array( '.i18n.php' );
00024     }
00025 
00031     protected static $cache = array();
00032 
00039     protected function splitSections( $data, $filename = 'unknown' ) {
00040         $data = SimpleFFS::fixNewLines( $data );
00041 
00042         $splitter = '$messages = array();';
00043 
00044         $pos = strpos( $data, $splitter );
00045         if ( $pos === false ) {
00046             throw new MWException( "MWEFFS1: File $filename: splitter not found" );
00047         }
00048 
00049         $offset = $pos + strlen( $splitter );
00050         $header = substr( $data, 0, $offset );
00051 
00052         $pattern = '(?: /\*\* .*? \*/ \n )? (?: \\$.*?  \n\);(?:\n\n|\s+\z) )';
00053         $regexp = "~$pattern~xsu";
00054         $matches = array();
00055         preg_match_all( $regexp, $data, $matches, PREG_SET_ORDER, $offset );
00056 
00057         $sections = array();
00058         $sections[] = $header;
00059 
00060         foreach ( $matches as $data ) {
00061             $pattern = "\\\$messages\['([a-z-]+)'\]";
00062             $regexp = "~$pattern~su";
00063             $matches = array();
00064             if ( !preg_match( $regexp, $data[0], $matches ) ) {
00065                 throw new MWException( "MWEFFS2: File $filename: malformed section: {$data[0]}" );
00066             }
00067             $code = $matches[1];
00068             // Normalize number of newlines after each section
00069             $sections[$code] = rtrim( $data[0] );
00070         }
00071 
00072         return $sections;
00073     }
00074 
00075     public function read( $code ) {
00076         $filename = $this->group->getSourceFilePath( $code );
00077         if ( !file_exists( $filename ) ) {
00078             return false;
00079         }
00080 
00081         if ( isset( self::$cache[$filename]['parsed'][$code] ) ) {
00082             return self::$cache[$filename]['parsed'][$code];
00083         }
00084 
00085         if ( !isset( self::$cache[$filename] ) ) {
00086             // Clear the cache if the filename changes to reduce memory use
00087             self::$cache = array();
00088 
00089             $contents = file_get_contents( $filename );
00090             self::$cache[$filename]['sections'] =
00091                 $this->splitSections( $contents, $filename );
00092         }
00093 
00094         // Shorten
00095         $cache = &self::$cache[$filename];
00096 
00097         $value = false;
00098         if ( isset( $cache['sections'][$code] ) ) {
00099             $value = $this->readFromVariable( $cache['sections'][$code] );
00100         }
00101 
00102         $cache['parsed'][$code] = $value;
00103 
00104         return $value;
00105     }
00106 
00107     public function readFromVariable( $data ) {
00108         $messages = array();
00109         eval( $data );
00110 
00111         $c = count( $messages );
00112         if ( $c !== 1 ) {
00113             throw new MWException( "MWEFFS3: Expected 1, got $c: $data" );
00114         }
00115 
00116         $messages = array_shift( $messages );
00117         $mangler = $this->group->getMangler();
00118         $messages = $mangler->mangle( $messages );
00119 
00120         return array(
00121             'MESSAGES' => $messages,
00122         );
00123     }
00124 
00129     protected function writeReal( MessageCollection $collection ) {
00130         $mangler = $this->group->getMangler();
00131         $code = $collection->getLanguage();
00132 
00133         $block = $this->generateMessageBlock( $collection, $mangler );
00134         if ( $block === false ) {
00135             return '';
00136         }
00137 
00138         // Ugly code, relies on side effects
00139         // Avoid parsing stuff with fake language code
00140         // Premature optimization
00141         $this->read( 'mul' );
00142         $filename = $this->group->getSourceFilePath( $code );
00143         $cache = &self::$cache[$filename];
00144 
00145         // Generating authors
00146         if ( isset( $cache['sections'][$code] ) ) {
00147             // More premature optimization
00148             $fromFile = self::parseAuthorsFromString( $cache['sections'][$code] );
00149             $collection->addCollectionAuthors( $fromFile );
00150         }
00151 
00152         $authors = $collection->getAuthors();
00153         $authors = $this->filterAuthors( $authors, $code );
00154 
00155         $authorList = '';
00156         foreach ( $authors as $author ) {
00157             $authorList .= "\n * @author $author";
00158         }
00159 
00160         // And putting all together
00161         $name = TranslateUtils::getLanguageName( $code );
00162         $native = TranslateUtils::getLanguageName( $code, $code );
00163 
00164         $section = <<<PHP
00167 \$messages['$code'] = array($block);
00168 PHP;
00169 
00170         // Store the written part, so that when next language is called,
00171         // the new version will be used (instead of the old parsed version
00172         $cache['sections'][$code] = $section;
00173 
00174         // Make a copy we can alter
00175         $sections = $cache['sections'];
00176         $priority = array();
00177 
00178         global $wgTranslateDocumentationLanguageCode;
00179         $codes = array(
00180             0, // File header
00181             $this->group->getSourceLanguage(),
00182             $wgTranslateDocumentationLanguageCode,
00183         );
00184         foreach ( $codes as $pcode ) {
00185             if ( isset( $sections[$pcode] ) ) {
00186                 $priority[] = $sections[$pcode];
00187                 unset( $sections[$pcode] );
00188             }
00189         }
00190 
00191         ksort( $sections );
00192 
00193         return implode( "\n\n", $priority ) . "\n\n" . implode( "\n\n", $sections ) . "\n";
00194     }
00195 
00196     protected function generateMessageBlock( MessageCollection $collection, StringMatcher $mangler ) {
00197         $block = '';
00201         foreach ( $collection as $key => $m ) {
00202             $value = $m->translation();
00203             if ( $value === null ) {
00204                 continue;
00205             }
00206 
00207             $key = $mangler->unmangle( $key );
00208             $value = str_replace( TRANSLATE_FUZZY, '', $value );
00209             $fuzzy = $m->hasTag( 'fuzzy' ) ? ' # Fuzzy' : '';
00210 
00211             $key = self::quote( $key );
00212             $value = self::quote( $value );
00213             $block .= "\t$key => $value,$fuzzy\n";
00214         }
00215 
00216         // Do not create empty sections
00217         if ( $block === '' ) {
00218             return false;
00219         }
00220 
00221         return "\n$block";
00222     }
00223 
00229     protected static function parseAuthorsFromString( $string ) {
00230         preg_match_all( '/@author (.*)/', $string, $m );
00231 
00232         return $m[1];
00233     }
00234 
00242     protected static function quote( $value ) {
00243         # Check for the appropriate apostrophe and add the value
00244         # Quote \ here, because it needs always escaping
00245         $value = addcslashes( $value, '\\' );
00246 
00247         # For readability
00248         $single = "'";
00249         $double = '"';
00250         $quote = $single; // Default
00251 
00252         # It is safe to use '-quoting, unless there is '-quote in the text
00253         if ( strpos( $value, $single ) !== false ) {
00254             # In case there are no variables that need to be escaped, just use "-quote
00255             if ( strpos( $value, $double ) === false && !preg_match( '/\$[^0-9]/', $value ) ) {
00256                 $quote = $double;
00257             } else {
00258                 # Something needs quoting, so pick the quote which causes less quoting
00259                 $doubleEsc = substr_count( $value, $double ) + substr_count( $value, '$' );
00260                 $singleEsc = substr_count( $value, $single );
00261 
00262                 if ( $doubleEsc < $singleEsc ) {
00263                     $quote = $double;
00264                     $extra = '$';
00265                 } else {
00266                     $extra = '';
00267                 }
00268 
00269                 $value = addcslashes( $value, $quote . $extra );
00270             }
00271         }
00272 
00273         return $quote . $value . $quote;
00274     }
00275 }
Generated on Tue Oct 29 00:00:23 2013 for MediaWiki Translate Extension by  doxygen 1.6.3