00001 <?php 00012 class MessageWriter { 00013 static $optionalComment = 'only translate this message to other languages if you have to change it'; 00014 static $ignoredComment = "do not translate or duplicate this message to other languages"; 00015 00016 static $messageStructure; 00017 static $blockComments; 00018 static $messageComments; 00019 static $ignoredMessages; 00020 static $optionalMessages; 00021 00030 public static function writeMessagesToFile( $messages, $code, $write, $listUnknown, $removeUnknown ) { 00031 # Rewrite the messages array 00032 $messages = self::writeMessagesArray( $messages, $code == 'en', false, $removeUnknown ); 00033 $messagesText = $messages[0]; 00034 $sortedMessages = $messages[1]; 00035 00036 # Write to the file 00037 $filename = Language::getMessagesFileName( $code ); 00038 $contents = file_get_contents( $filename ); 00039 if( strpos( $contents, '$messages' ) !== false ) { 00040 $contents = explode( '$messages', $contents ); 00041 if( $messagesText == '$messages' . $contents[1] ) { 00042 echo "Generated messages for language $code. Same as the current file.\n"; 00043 } else { 00044 if( $write ) { 00045 $new = $contents[0]; 00046 $new .= $messagesText; 00047 file_put_contents( $filename, $new ); 00048 echo "Generated and wrote messages for language $code.\n"; 00049 } else { 00050 echo "Generated messages for language $code. Please run the script again (without the parameter \"dry-run\") to write the array to the file.\n"; 00051 } 00052 } 00053 if( $listUnknown && isset( $sortedMessages['unknown'] ) && !empty( $sortedMessages['unknown'] ) ) { 00054 if ( $removeUnknown ) 00055 echo "\nThe following " . count( $sortedMessages['unknown'] ) . " unknown messages have been removed:\n"; 00056 else 00057 echo "\nThere are " . count( $sortedMessages['unknown'] ) . " unknown messages, please check them:\n"; 00058 foreach( $sortedMessages['unknown'] as $key => $value ) { 00059 echo "* " . $key . "\n"; 00060 } 00061 } 00062 } else { 00063 echo "Generated messages for language $code. There seem to be no messages array in the file.\n"; 00064 } 00065 } 00066 00075 public static function writeMessagesArray( $messages, $ignoredComments = false, $prefix = false, $removeUnknown = false ) { 00076 # Load messages 00077 $dir = $prefix ? $prefix : dirname( __FILE__ ); 00078 00079 require( $dir . '/messages.inc' ); 00080 self::$messageStructure = $wgMessageStructure; 00081 self::$blockComments = $wgBlockComments; 00082 self::$messageComments = $wgMessageComments; 00083 00084 require( $dir . '/messageTypes.inc' ); 00085 self::$ignoredMessages = $wgIgnoredMessages; 00086 self::$optionalMessages = $wgOptionalMessages; 00087 00088 00089 # Sort messages to blocks 00090 $sortedMessages['unknown'] = $messages; 00091 foreach( self::$messageStructure as $blockName => $block ) { 00092 foreach( $block as $key ) { 00093 if( array_key_exists( $key, $sortedMessages['unknown'] ) ) { 00094 $sortedMessages[$blockName][$key] = $sortedMessages['unknown'][$key]; 00095 unset( $sortedMessages['unknown'][$key] ); 00096 } 00097 } 00098 } 00099 00100 # Write all the messages 00101 $messagesText = "\$messages = array( 00102 "; 00103 foreach( $sortedMessages as $block => $messages ) { 00104 # Skip if it's the block of unknown messages - handle that in the end of file 00105 if( $block == 'unknown' ) { 00106 continue; 00107 } 00108 00109 if( $ignoredComments ) { 00110 $ignored = self::$ignoredMessages; 00111 $optional = self::$optionalMessages; 00112 } else { 00113 $ignored = array(); 00114 $optional = array(); 00115 } 00116 $comments = self::makeComments( array_keys($messages), self::$messageComments, $ignored, $optional ); 00117 00118 # Write the block 00119 $messagesText .= self::writeMessagesBlock( self::$blockComments[$block], $messages, $comments ); 00120 } 00121 00122 # Write the unknown messages, alphabetically sorted. 00123 # Of course, we don't have any comments for them, because they are unknown. 00124 if ( !$removeUnknown ) { 00125 ksort( $sortedMessages['unknown'] ); 00126 $messagesText .= self::writeMessagesBlock( 'Unknown messages', $sortedMessages['unknown'] ); 00127 } 00128 $messagesText .= "); 00129 "; 00130 return array( $messagesText, $sortedMessages ); 00131 } 00132 00141 public static function makeComments( $messages, $comments, $ignored, $optional ) { 00142 # Comment collector 00143 $commentArray = array(); 00144 00145 # List of keys only 00146 foreach( $messages as $key ) { 00147 $commentsForKey = array(); 00148 00149 # Add descriptive comment for this message if there is one 00150 if( array_key_exists( $key, $comments ) ) { 00151 $commentsForKey[] = $comments[$key]; 00152 } 00153 00154 # For translator information only 00155 if( in_array( $key, $ignored ) ) { 00156 $commentsForKey[] = self::$ignoredComment; 00157 } elseif( in_array( $key, $optional ) ) { 00158 $commentsForKey[] = self::$optionalComment; 00159 } 00160 00161 # Format one or more comments nicely and store in array 00162 if( count( $commentsForKey ) ) { 00163 $commentArray[$key] = ' # ' . implode( '; ', $commentsForKey ); 00164 } 00165 } 00166 00167 return $commentArray; 00168 } 00169 00180 public static function writeMessagesBlock( $blockComment, $messages, 00181 $messageComments = array(), $prefix = '' ) { 00182 00183 $blockText = ''; 00184 00185 # Skip the block if it includes no messages 00186 if( empty( $messages ) ) { 00187 return ''; 00188 } 00189 00190 # Format the block comment (if exists); check for multiple lines comments 00191 if( !empty( $blockComment ) ) { 00192 if( strpos( $blockComment, "\n" ) === false ) { 00193 $blockText .= "$prefix# $blockComment 00194 "; 00195 } else { 00196 $blockText .= "$prefix/* 00197 $blockComment 00198 */ 00199 "; 00200 } 00201 } 00202 00203 # Get max key length 00204 $maxKeyLength = max( array_map( 'strlen', array_keys( $messages ) ) ); 00205 00206 # Format the messages 00207 foreach( $messages as $key => $value ) { 00208 # Add the key name 00209 $blockText .= "$prefix'$key'"; 00210 00211 # Add the appropriate block whitespace 00212 $blockText .= str_repeat( ' ', $maxKeyLength - strlen( $key ) ); 00213 00214 # Refer to the value 00215 $blockText .= ' => '; 00216 00217 # Check for the appropriate apostrophe and add the value 00218 # Quote \ here, because it needs always escaping 00219 $value = addcslashes( $value, '\\' ); 00220 00221 # For readability 00222 $single = "'"; 00223 $double = '"'; 00224 00225 if( strpos( $value, $single ) === false ) { 00226 # Nothing ugly, just use ' 00227 $blockText .= $single.$value.$single; 00228 } elseif( strpos( $value, $double ) === false && !preg_match('/\$[a-zA-Z_\x7f-\xff]/', $value) ) { 00229 # No "-quotes, no variables that need quoting, use " 00230 $blockText .= $double.$value.$double; 00231 } else { 00232 # Something needs quoting, pick the quote which causes less quoting 00233 $quote = substr_count( $value, $double ) + substr_count( $value, '$' ) >= substr_count( $value, $single ) ? $single : $double; 00234 if( $quote === $double ) { 00235 $extra = '$'; 00236 } else { 00237 $extra = ''; 00238 } 00239 $blockText .= $quote . addcslashes( $value, $quote . $extra ) . $quote; 00240 } 00241 00242 # Comma 00243 $blockText .= ','; 00244 00245 # Add comments, if there is any 00246 if( array_key_exists( $key, $messageComments ) ) { 00247 $blockText .= $messageComments[$key]; 00248 } 00249 00250 # Newline 00251 $blockText .= " 00252 "; 00253 } 00254 00255 # Newline to end the block 00256 $blockText .= " 00257 "; 00258 00259 return $blockText; 00260 } 00261 }