1 package freeguide.build.i18n; 2 3 import java.io.File; 4 import java.io.FileFilter; 5 import java.io.FileInputStream; 6 import java.io.IOException; 7 import java.io.InputStreamReader; 8 9 import java.util.ArrayList; 10 import java.util.Iterator; 11 import java.util.List; 12 import java.util.Map; 13 import java.util.Properties; 14 import java.util.Set; 15 import java.util.TreeSet; 16 import java.util.regex.Pattern; 17 18 /** 19 * DOCUMENT ME! 20 * 21 * @author $author$ 22 * @version $Revision$ 23 */ 24 public class CheckLocalization 25 { 26 protected static Pattern PATTERN_MAIN = 27 Pattern.compile( ".+[A-Za-z]{3,}\\.properties" ); 28 protected static Map<String, String> translatedGlobal; 29 30 /** 31 * DOCUMENT_ME! 32 * 33 * @param args DOCUMENT_ME! 34 * 35 * @throws Exception DOCUMENT_ME! 36 */ main( String[] args )37 public static void main( String[] args ) throws Exception 38 { 39 final File mainProps = 40 new File( "src/resources/i18n/MessagesBundle.properties" ); 41 final File[] propFiles = 42 new File( "src/resources/i18n/" ).listFiles( 43 new FileFilter( ) 44 { 45 public boolean accept( File pathname ) 46 { 47 return PATTERN_MAIN.matcher( pathname.getName( ) ) 48 .matches( ); 49 } 50 } ); 51 52 translatedGlobal = readPropertiesFile( mainProps ); 53 54 System.out.println( 55 "================= Files with untranslated strings =================" ); 56 57 for( final File f : propFiles ) 58 { 59 processFileFindUntranslated( f ); 60 } 61 62 System.out.println( 63 "================= Translation with non-exists strings =================" ); 64 65 for( final File f : propFiles ) 66 { 67 processFileFindUnused( f ); 68 } 69 70 for( final String lang : "be,de,it,fr".split( "," ) ) 71 { 72 System.out.println( 73 "================= Language info: " + lang 74 + " =================" ); 75 76 for( final File f : propFiles ) 77 { 78 processLang( lang, f ); 79 } 80 } 81 } 82 processLang( final String lang, final File propFile )83 protected static void processLang( final String lang, final File propFile ) 84 throws IOException 85 { 86 final Map<String, String> baseStrings = readPropertiesFile( propFile ); 87 final File transFile = 88 new File( 89 propFile.getPath( ) 90 .replaceAll( 91 "\\.properties", '_' + lang + ".properties" ) ); 92 93 if( !transFile.exists( ) ) 94 { 95 System.out.println( 96 " There is no file : " + transFile.getPath( ) ); 97 98 return; 99 } 100 101 final Map<String, String> translatedStrings = 102 readPropertiesFile( transFile ); 103 104 final Set<String> untranslated = 105 new TreeSet<String>( baseStrings.keySet( ) ); 106 removeFromSet( untranslated, translatedStrings.keySet( ) ); 107 108 if( untranslated.size( ) > 0 ) 109 { 110 System.out.println( 111 " Untranslated strings in " + propFile.getPath( ) 112 + " for language '" + lang + "':" ); 113 114 for( String str : untranslated ) 115 { 116 System.out.println( " \"" + str + '"' ); 117 } 118 } 119 120 final Set<String> unused = 121 new TreeSet<String>( translatedStrings.keySet( ) ); 122 removeFromSet( unused, baseStrings.keySet( ) ); 123 124 if( unused.size( ) > 0 ) 125 { 126 System.out.println( 127 " Unused translations in " + propFile.getPath( ) 128 + " for language '" + lang + "':" ); 129 130 for( String str : unused ) 131 { 132 System.out.println( " \"" + str + '"' ); 133 } 134 } 135 } 136 getJavaFilesForPropertiesFile( final File propFile )137 protected static File[] getJavaFilesForPropertiesFile( 138 final File propFile ) 139 { 140 final List<File> allFiles = new ArrayList<File>( ); 141 142 String classesDir = propFile.getName( ); 143 classesDir = classesDir.substring( 144 0, classesDir.length( ) - ".properties".length( ) ); 145 classesDir = classesDir.replace( '_', '/' ); 146 147 if( classesDir.equals( "MessagesBundle" ) ) 148 { 149 classesDir = "src/freeguide/common/"; 150 findFile( 151 new File( classesDir ), allFiles, 152 new FileFilter( ) 153 { 154 public boolean accept( File pathname ) 155 { 156 return pathname.getName( ).endsWith( ".java" ); 157 } 158 } ); 159 classesDir = "src/freeguide/plugins/program/"; 160 findFile( 161 new File( classesDir ), allFiles, 162 new FileFilter( ) 163 { 164 public boolean accept( File pathname ) 165 { 166 return pathname.getName( ).endsWith( ".java" ); 167 } 168 } ); 169 } 170 else 171 { 172 classesDir = "src/freeguide/plugins/" + classesDir; 173 findFile( 174 new File( classesDir ), allFiles, 175 new FileFilter( ) 176 { 177 public boolean accept( File pathname ) 178 { 179 return pathname.getName( ).endsWith( ".java" ); 180 } 181 } ); 182 } 183 184 return allFiles.toArray( new File[allFiles.size( )] ); 185 } 186 readFile( final File f )187 protected static String readFile( final File f ) throws IOException 188 { 189 final StringBuffer buf = new StringBuffer( ); 190 final InputStreamReader in = 191 new InputStreamReader( new FileInputStream( f ), "UTF-8" ); 192 193 try 194 { 195 char[] buffer = new char[65536]; 196 197 while( true ) 198 { 199 int len = in.read( buffer ); 200 201 if( len < 0 ) 202 { 203 break; 204 } 205 206 buf.append( buffer, 0, len ); 207 } 208 } 209 finally 210 { 211 in.close( ); 212 } 213 214 return buf.toString( ); 215 } 216 readPropertiesFile( final File f )217 protected static Map<String, String> readPropertiesFile( final File f ) 218 throws IOException 219 { 220 final Properties result = new Properties( ); 221 result.load( new FileInputStream( f ) ); 222 223 return (Map)result; 224 } 225 getStringsForTranslationFromFile( final File f )226 protected static Set<String> getStringsForTranslationFromFile( 227 final File f ) throws IOException 228 { 229 MODE mode = MODE.DATA; 230 final Set<String> result = new TreeSet<String>( ); 231 232 StringBuffer str = new StringBuffer( ); 233 StringBuffer command = new StringBuffer( ); 234 char prevC = '\0'; 235 236 final String data = readFile( f ); 237 238 for( int i = 0; i < data.length( ); i++ ) 239 { 240 char c = data.charAt( i ); 241 242 switch( mode ) 243 { 244 case DATA: 245 246 if( ( prevC == '/' ) && ( c == '*' ) ) 247 { 248 mode = MODE.COMMENT; 249 } 250 else if( ( prevC == '/' ) && ( c == '/' ) ) 251 { 252 mode = MODE.LINE_COMMENT; 253 } 254 else if( ( c == '"' ) && ( prevC != '\'' ) ) 255 { 256 mode = MODE.STRING; 257 } 258 259 break; 260 261 case COMMENT: 262 263 if( ( prevC == '*' ) && ( c == '/' ) ) 264 { 265 mode = MODE.DATA; 266 command.setLength( 0 ); 267 } 268 269 break; 270 271 case LINE_COMMENT: 272 273 if( c == '\n' ) 274 { 275 mode = MODE.DATA; 276 } 277 278 break; 279 280 case STRING: 281 282 if( ( c == '"' ) && ( prevC != '\\' ) ) 283 { 284 mode = MODE.DATA; 285 286 if( isNeedToLocalize( command.toString( ) ) ) 287 { 288 result.add( str.toString( ) ); 289 } 290 291 str.setLength( 0 ); 292 } 293 else 294 { 295 str.append( c ); 296 } 297 298 break; 299 } 300 301 if( mode == MODE.DATA ) 302 { 303 if( ( c == ';' ) || ( c == '{' ) || ( c == '}' ) ) 304 { 305 command.setLength( 0 ); 306 } 307 else 308 { 309 command.append( c ); 310 } 311 } 312 313 prevC = c; 314 } 315 316 return result; 317 } 318 isNeedToLocalize( final String command )319 protected static boolean isNeedToLocalize( final String command ) 320 { 321 if( command.contains( "static" ) && command.contains( "final" ) ) 322 { 323 return false; 324 } 325 326 if( command.contains( "Exception(" ) ) 327 { 328 return false; 329 } 330 331 if( 332 command.replaceAll( "\\s+", "" ) 333 .contains( "Application.getInstance().getLogger()." ) ) 334 { 335 return false; 336 } 337 338 return true; 339 } 340 findFile( final File dir, final List<File> files, final FileFilter filter )341 protected static void findFile( 342 final File dir, final List<File> files, final FileFilter filter ) 343 { 344 final File[] fs = dir.listFiles( ); 345 346 if( fs == null ) 347 { 348 return; 349 } 350 351 for( final File f : fs ) 352 { 353 if( f.isFile( ) ) 354 { 355 if( filter.accept( f ) ) 356 { 357 files.add( f ); 358 } 359 } 360 else 361 { 362 if( !f.getName( ).equals( ".svn" ) ) 363 { 364 findFile( f, files, filter ); 365 } 366 } 367 } 368 } 369 processFileFindUntranslated( final File propFile )370 protected static void processFileFindUntranslated( final File propFile ) 371 throws Exception 372 { 373 System.out.println( "Translation '" + propFile.getName( ) + "' :" ); 374 375 final Map<String, String> translated = readPropertiesFile( propFile ); 376 377 for( final File f : getJavaFilesForPropertiesFile( propFile ) ) 378 { 379 final Set<String> forTranslation = 380 getStringsForTranslationFromFile( f ); 381 removeFromSet( forTranslation, translated.keySet( ) ); 382 removeFromSet( forTranslation, translatedGlobal.keySet( ) ); 383 384 if( forTranslation.size( ) > 0 ) 385 { 386 System.out.println( 387 " Untranslated strings in " + f.getPath( ) + " :" ); 388 389 for( String str : forTranslation ) 390 { 391 System.out.println( " \"" + str + '"' ); 392 } 393 } 394 } 395 } 396 processFileFindUnused( final File propFile )397 protected static void processFileFindUnused( final File propFile ) 398 throws Exception 399 { 400 final Map<String, String> translated = readPropertiesFile( propFile ); 401 final Set<String> keys = translated.keySet( ); 402 403 for( final File f : getJavaFilesForPropertiesFile( propFile ) ) 404 { 405 final Set<String> forTranslation = 406 getStringsForTranslationFromFile( f ); 407 408 removeFromSet( keys, forTranslation ); 409 } 410 411 if( keys.size( ) > 0 ) 412 { 413 System.out.println( 414 "Unused strings in '" + propFile.getName( ) + "' :" ); 415 416 for( String str : keys ) 417 { 418 System.out.println( " \"" + str + '"' ); 419 } 420 } 421 } 422 removeFromSet( final Set<String> sourceSet, final Set<String> removeSet )423 protected static void removeFromSet( 424 final Set<String> sourceSet, final Set<String> removeSet ) 425 { 426 for( final Iterator<String> it = sourceSet.iterator( ); 427 it.hasNext( ); ) 428 { 429 if( removeSet.contains( it.next( ) ) ) 430 { 431 it.remove( ); 432 } 433 } 434 } 435 protected static enum MODE 436 {DATA, 437 COMMENT, 438 LINE_COMMENT, 439 STRING; 440 } 441 } 442