PythonSingleFFS.php

Go to the documentation of this file.
00001 <?php
00002 
00007 class PythonSingleFFS extends SimpleFFS {
00008     public function getFileExtensions() {
00009         return array( '.py' );
00010     }
00011 
00017     protected static $cache = array();
00018 
00025     protected function splitSections( $data, $filename = 'unknown' ) {
00026         $data = SimpleFFS::fixNewLines( $data );
00027 
00028         $splitter = 'msg = {';
00029 
00030         $pos = strpos( $data, $splitter );
00031         if ( $pos === false ) {
00032             throw new MWException( "MWEFFS1: File $filename: splitter not found" );
00033         }
00034 
00035         $offset = $pos + strlen( $splitter );
00036         $header = substr( $data, 0, $offset );
00037         // Avoid buildup of whitespace
00038         $header = trim( $header );
00039 
00040         $pattern = '.*?},\s';
00041         $regexp = "~$pattern~xsu";
00042         $matches = array();
00043         preg_match_all( $regexp, $data, $matches, PREG_SET_ORDER, $offset );
00044 
00045         $sections = array();
00046         $sections[] = $header;
00047 
00048         foreach ( $matches as $data ) {
00049             $pattern = "'([a-z-]+)'\s*:\s*{";
00050             $regexp = "~$pattern~su";
00051             $matches = array();
00052             if ( !preg_match( $regexp, $data[0], $matches ) ) {
00053                 throw new MWException( "MWEFFS2: File $filename: malformed section: {$data[0]}" );
00054             }
00055             $code = $matches[1];
00056             // Normalize number of newlines
00057             $sections[$code] = trim( $data[0], "\n" );
00058         }
00059 
00060         return $sections;
00061     }
00062 
00063     public function read( $code ) {
00064         $code = $this->group->mapCode( $code );
00065         $filename = $this->group->getSourceFilePath( $code );
00066         if ( !file_exists( $filename ) ) {
00067             return false;
00068         }
00069 
00070         if ( isset( self::$cache[$filename]['parsed'][$code] ) ) {
00071             return self::$cache[$filename]['parsed'][$code];
00072         }
00073 
00074         if ( !isset( self::$cache[$filename] ) ) {
00075             // Clear the cache if the filename changes to reduce memory use
00076             self::$cache = array();
00077 
00078             $contents = file_get_contents( $filename );
00079             self::$cache[$filename]['sections'] =
00080                 $this->splitSections( $contents, $filename );
00081 
00082             self::$cache[$filename]['parsed'] = $this->parseFile();
00083         }
00084 
00085         if ( !isset( self::$cache[$filename]['parsed'][$code] ) ) {
00086             return null;
00087         }
00088 
00089         return self::$cache[$filename]['parsed'][$code];
00090     }
00091 
00092     protected function parseFile() {
00093         /* N levels of escaping
00094          * - for PHP string
00095          * - for Python string
00096          * - for shell command
00097          * - and wfShellExec will wrap the whole command once more
00098          */
00099         $filename = $this->group->getSourceFilePath( 'mul' );
00100         $filename = addcslashes( $filename, '\\"' );
00101         $command = wfEscapeShellArg( "import simplejson as json; execfile(\"$filename\"); " .
00102             "print json.dumps(msg)" );
00103         $json = wfShellExec( "python -c $command" );
00104 
00105         $parsed = FormatJson::decode( $json, true );
00106         if ( !is_array( $parsed ) ) {
00107             throw new MWException( "Failed to decode python file $filename" );
00108         }
00109         $sections = array();
00110         foreach ( $parsed as $code => $messages ) {
00111             $sections[$code] = array( 'MESSAGES' => $messages );
00112         }
00113 
00114         return $sections;
00115     }
00116 
00117     public function readFromVariable( $data ) {
00118         throw new MWException( 'Not yet supported' );
00119     }
00120 
00125     protected function writeReal( MessageCollection $collection ) {
00126         $mangler = $this->group->getMangler();
00127         $code = $collection->getLanguage();
00128         $code = $this->group->mapCode( $code );
00129 
00130         $block = $this->generateMessageBlock( $collection, $mangler );
00131         if ( $block === '' ) {
00132             return '';
00133         }
00134 
00135         // Ugly code, relies on side effects
00136         $this->read( 'mul' );
00137         $filename = $this->group->getSourceFilePath( $code );
00138         $cache = &self::$cache[$filename];
00139 
00140         // Generating authors
00141         if ( isset( $cache['sections'][$code] ) ) {
00142             // More premature optimization
00143             $fromFile = self::parseAuthorsFromString( $cache['sections'][$code] );
00144             $collection->addCollectionAuthors( $fromFile );
00145         }
00146 
00147         $authors = $collection->getAuthors();
00148         $authors = $this->filterAuthors( $authors, $code );
00149 
00150         $authorList = '';
00151         foreach ( $authors as $author ) {
00152             $authorList .= "\t# Author: $author\n";
00153         }
00154 
00155         $section = "$authorList\t'$code': {\n$block\t},";
00156 
00157         // Store the written part, so that when next language is called,
00158         // the new version will be used (instead of the old parsed version
00159         $cache['sections'][$code] = $section;
00160 
00161         // Make a copy we can alter
00162         $sections = $cache['sections'];
00163         $priority = array();
00164 
00165         global $wgTranslateDocumentationLanguageCode;
00166         $codes = array(
00167             0, // File header
00168             $this->group->getSourceLanguage(),
00169             $wgTranslateDocumentationLanguageCode,
00170         );
00171         foreach ( $codes as $pcode ) {
00172             if ( isset( $sections[$pcode] ) ) {
00173                 $priority[] = $sections[$pcode];
00174                 unset( $sections[$pcode] );
00175             }
00176         }
00177 
00178         ksort( $sections );
00179 
00180         return implode( "\n", $priority ) . "\n" . implode( "\n", $sections ) . "\n};\n";
00181     }
00182 
00183     protected function generateMessageBlock( MessageCollection $collection, StringMatcher $mangler ) {
00184         $block = '';
00185 
00189         foreach ( $collection as $message ) {
00190             $translation = $message->translation();
00191             if ( $translation === null ) {
00192                 continue;
00193             }
00194 
00195             $key = addcslashes( $message->key(), "\n'\\" );
00196             $translation = addcslashes( $translation, "\n'\\" );
00197             $translation = str_replace( TRANSLATE_FUZZY, '', $translation );
00198 
00199             $block .= "\t\t'{$key}': u'{$translation}',\n";
00200         }
00201 
00202         return $block;
00203     }
00204 
00210     protected static function parseAuthorsFromString( $string ) {
00211         preg_match_all( '/# Author: (.*)/', $string, $m );
00212 
00213         return $m[1];
00214     }
00215 }
Generated on Tue Oct 29 00:00:23 2013 for MediaWiki Translate Extension by  doxygen 1.6.3