1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 25 import java.util.*; 26 import java.io.*; 27 28 public class JPropEx 29 { 30 private String inputFileArg = ""; 31 private String outputFileArg = ""; 32 private String pathPrefixArg = ""; 33 private String pathPostfixArg = ""; 34 private String projectArg = ""; 35 private String rootArg = ""; 36 private Vector forcedLangsArg; 37 private Vector langsArg; 38 private String inputSdfFileArg = ""; 39 private boolean isQuiet = false; 40 private final String resourceType = "javaproperties"; 41 private final String sourceLanguage = "en-US"; 42 43 static final int JAVA_TYPE = 0; 44 static final int JAVA_ENUS_TYPE = 1; 45 static final int EXTENSION_TYPE = 2; 46 JPropEx()47 public JPropEx() 48 { 49 //data = new SdfData(); 50 } 51 JPropEx( String args[] )52 public JPropEx( String args[] ) 53 { 54 super(); 55 parseArguments( args ); 56 testCL(); 57 //testArguments(); 58 if( inputSdfFileArg != null && inputSdfFileArg.length() > 0 ) 59 merge(); 60 else 61 extract(); 62 } 63 getSimpleArg( String[] args , int x )64 private String getSimpleArg( String[] args , int x ) 65 { 66 if( x < args.length ) x++; 67 else 68 { 69 System.err.println("ERROR: Missing arg for "+args[ x ]+"\n"); 70 help(); 71 } 72 return args[ x ]; 73 } getComplexArg( String[] args , int x )74 private Vector getComplexArg( String[] args , int x ) 75 { 76 if( x < args.length ) x++; 77 else 78 { 79 System.err.println("ERROR: Missing arg for "+args[ x ]+"\n"); 80 help(); 81 } 82 String value = args[ x ]; 83 Vector values = new Vector( Arrays.asList( value.split(",") ) ); 84 return values; 85 } 86 testCL()87 private void testCL() 88 { 89 if( inputFileArg.length()>0 && ( ( pathPrefixArg.length()>0 && pathPostfixArg.length()>0 ) || outputFileArg.length()>0 ) && projectArg.length()>0 && rootArg.length()>0 && langsArg.size()>0 ) 90 if( ( inputSdfFileArg.length()>0 && ( outputFileArg.length()>0 || ( pathPrefixArg.length()>0 && pathPostfixArg.length()>0 ) ) ) || ( inputFileArg.length()>0 && outputFileArg.length()>0 ) ) 91 return; 92 System.out.println("ERROR: Strange parameters!"); 93 help(); 94 System.exit( -1 ); 95 } help()96 private void help() 97 { 98 System.out.println("jpropex -> extract / merge java properties files"); 99 System.out.println("-p <project> -r <project_root> -i <input>|@<input> -o <output> -x <path1> -y <path2> -m <sdf_file> -l <lang>\n"); 100 System.out.println("Example:\ncd /data/cws/l10ntooling17/DEV300/ooo/reportbuilder/java/com/sun/star/report/function/metadata"); 101 System.out.println("Extract:\njpropex -p reportbuilder -r ../../../../../../.. -i Title-Function.properties -o new.sdf -l en-US"); 102 System.out.println("Merge: use either ( -x path -y more_path ) or ( -o ) and ( -i filename ) or ( -i @filename ). @filename contains a list with files"); 103 System.out.println("jpropex -p reportbuilder -r ../../../../../../.. -x ../../../../../../../unxlngx6.pro/class/com/sun/star/report/function/metadata -y ivo -i @abc -l all -lf en-US,de,fr,pt -m ../../../../../../../common.pro/misc/reportbuilder/java/com/sun/star/report/function/metadata/localize.sdf"); 104 System.out.println("jpropex -p reportbuilder -r ../../../../../../.. -x ../../../../../../../unxlngx6.pro/class/com/sun/star/report/function/metadata -y ivo -i @abc -l all -lf en-US,de,fr,pt -m ../../../../../../../common.pro/misc/reportbuilder/java/com/sun/star/report/function/metadata/localize.sdf"); 105 System.out.println("jpropex -p reportbuilder -r ../../../../../../.. -o ../../../../../../../unxlngx6.pro/class/com/sun/star/report/function/metadata/ -i Title-Function.properties -l all -lf en-US,de,fr,pt -m ../../../../../../../common.pro/misc/reportbuilder/java/com/sun/star/report/function/metadata/localize.sdf"); 106 System.out.println("jpropex -p reportbuilder -r ../../../../../../.. -x ../../../../../../../unxlngx6.pro/class/com/sun/star/report/function/metadata -y ivooo -i Title-Function.properties -l all -lf en-US,de,fr,pt -m ../../../../../../../common.pro/misc/reportbuilder/java/com/sun/star/report/function/metadata/localize.sdf"); 107 System.exit( -1 ); 108 } 109 extract()110 private void extract() 111 { 112 SdfData data = new SdfData(); 113 java.util.Properties prop = loadProp( inputFileArg ); 114 115 // Get a prototype that already contains the most common settings 116 SdfEntity dolly = prepareSdfObj( inputFileArg ); 117 String key; 118 SdfEntity currentStr; 119 String value; 120 String str; 121 for( Enumeration e = prop.propertyNames() ; e.hasMoreElements() ; ) 122 { 123 key = (String) e.nextElement(); 124 currentStr = (SdfEntity) dolly.clone(); 125 // Set the new GID and the string text 126 currentStr.setGid( key ); 127 value = prop.getProperty( key , "" ); 128 //if( value.equals("") ) System.err.println("Warning: in file "+inputFileArg+" the string with the key "+key+" has a empty string!"); 129 str = (prop.getProperty( key )).replaceAll("\t" , " " ); // remove tab 130 str = str.replaceAll("\n"," "); // remove return 131 currentStr.setText( str ); 132 if( str.length() > 0 ) 133 data.add( currentStr ); 134 } 135 data.write( outputFileArg ); 136 } 137 prepareSdfObj( String filename )138 private SdfEntity prepareSdfObj( String filename ) 139 { 140 String path = makeAbs( filename ).trim(); 141 String myRootArg = makeAbs( rootArg ).trim(); 142 myRootArg = myRootArg.replace( "\\","/"); 143 myRootArg += "/"; 144 path = path.replace("\\","/"); 145 path = path.replace( myRootArg, "" ); 146 path = path.replace("/","\\"); 147 // TODO: Make this static 148 java.text.SimpleDateFormat dateformat = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 149 String date = dateformat.format( new Date() ); 150 return new SdfEntity( projectArg , path , "0" /* dummy1 */ , resourceType , "", "" , "" , "" , "0" /* dummy2 */ , 151 sourceLanguage , "", "" , "" , "" , date ); 152 } 153 merge()154 private void merge() 155 { 156 SdfData data = getSdfData(); 157 if( inputFileArg.startsWith("@") ) 158 { 159 // Read files 160 Vector fileList = readFileList( inputFileArg ); 161 for( Enumeration e = fileList.elements(); e.hasMoreElements(); ) 162 mergeFile( (String) e.nextElement() , data , false ); 163 } 164 else 165 { 166 // Single file 167 mergeFile( inputFileArg , data , true ); 168 } 169 } 170 readFileList( String filename )171 private Vector readFileList( String filename ) 172 { 173 Vector lines = new Vector(); 174 try 175 { 176 BufferedReader in = new BufferedReader( new FileReader( filename.substring( 1 ) ) ); 177 while( in.ready() ) 178 lines.add( in.readLine().trim() ); 179 } 180 catch( IOException e ) 181 { 182 System.out.println("ERROR: Can't open file '"+filename.substring( 1 )+"'"); 183 System.exit( -1 ); 184 } 185 return lines; 186 } 187 mergeFile( String filename , SdfData data , boolean isSingleFile )188 private void mergeFile( String filename , SdfData data , boolean isSingleFile ) 189 { 190 int type = detectFormat( filename ); 191 java.util.Properties sourceProp = loadProp( filename ); 192 Vector langs = getLanguages( data ); 193 HashMap props = new HashMap(); 194 // Create a properties object for every language 195 for( Enumeration e = langs.elements(); e.hasMoreElements();) 196 { 197 props.put( (String)e.nextElement() , new java.util.Properties() ); 198 } 199 // Get a prototype that already contains the most common settings 200 201 SdfEntity dolly = prepareSdfObj( filename ); 202 String key; 203 String sourceString; 204 SdfEntity curStr; 205 SdfEntity curEntity; 206 SdfEntity mergedEntity; 207 String curLang; 208 for( Enumeration e = sourceProp.propertyNames() ; e.hasMoreElements() ; ) // For all property keys 209 { 210 key = (String) e.nextElement(); 211 sourceString = sourceProp.getProperty( key ); 212 curStr = (SdfEntity) dolly.clone(); 213 curStr.setGid( key ); 214 for( Enumeration lang = langs.elements(); lang.hasMoreElements(); ) // merge in every language 215 { 216 curEntity = (SdfEntity) curStr.clone(); 217 curLang = (String) lang.nextElement(); 218 curEntity.setLangid( curLang ); 219 mergedEntity = data.get( curEntity ); 220 if( mergedEntity == null ) 221 { 222 // in case there is no translation then fallback to the en-US source string 223 ( (java.util.Properties) props.get( curLang )).setProperty( curEntity.getGid() , sourceString ); 224 } 225 else 226 { 227 // Set the merged text from the sdf file 228 ( (java.util.Properties) props.get( curLang )).setProperty( mergedEntity.getGid() , mergedEntity.getText() ); // TODO: Quoting ??? 229 } 230 } 231 232 } 233 // Now write them out 234 String lang; 235 for( Iterator i = props.keySet().iterator() ; i.hasNext() ; ) 236 { 237 lang = (String) i.next(); 238 writeSinglePropertiesFile( filename , (java.util.Properties) props.get( lang ) , lang , isSingleFile , type ); 239 } 240 } writeSinglePropertiesFile( String filename , java.util.Properties prop , String lang , boolean isSingleFile , int type )241 private void writeSinglePropertiesFile( String filename , java.util.Properties prop , String lang , boolean isSingleFile , int type ) 242 { 243 // Prepare path to file 244 int filenameIdx = filename.lastIndexOf( "/" ) > 0 ? filename.lastIndexOf( "/" )+1 : 0 ; 245 String path = new String(); 246 String name = new String(); 247 String lcLang = lang.toLowerCase(); 248 // use of -x <path> -y <more_path> 249 // -> <path>/<lang>/<more_path> 250 if( pathPrefixArg != null && pathPrefixArg.length()>0 && pathPostfixArg != null && pathPostfixArg.length()>0 ) 251 { 252 path = new StringBuffer().append( pathPrefixArg ).append( "/" ).append( lcLang ).append( "/" ).append( pathPostfixArg ).append( "/" ).toString(); 253 name += formatFilename( filename , filenameIdx , lang , type ); 254 } 255 //use of -i <one_filename> 256 else if( !isSingleFile && outputFileArg != null && outputFileArg.length()>0 ) 257 { 258 //name = outputFileArg; 259 path = outputFileArg; 260 name += formatFilename( filename , filenameIdx , lang , type ); 261 } 262 //use of -i @<file_containing_many_filenames> 263 else if( isSingleFile && outputFileArg != null && outputFileArg.length()>0 ) 264 { 265 //name = outputFileArg; 266 path = outputFileArg; 267 name += formatFilename( filename , filenameIdx , lang , type ); 268 } 269 else 270 { 271 System.err.println("ERROR: No outputfile specified .. either -o or -x -y !"); 272 System.exit( -1 ); 273 } 274 275 File dir = new File( path ); 276 try 277 { 278 if( !dir.exists() && path.length()>0 ) 279 { 280 if( !dir.mkdirs() ) 281 { 282 System.out.println("ERROR: Can't create directory '"+path+"' !!!"); 283 System.exit( -1 ); 284 } 285 } 286 } 287 catch( SecurityException e ) 288 { 289 System.out.println("ERROR: Can't create directory '"+path+"'!!!Wrong Permissions?"); 290 System.exit( -1 ); 291 } 292 path += name; 293 // Write the properties file 294 //System.out.println("DBG: Writing to "+path); 295 try{ 296 BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream( path ) ); 297 if( prop == null ) 298 System.out.println("DBG: prop == null!!!"); 299 prop.store( out , "" ); // Legal headers? 300 } 301 catch( IOException e ) 302 { 303 System.out.println("ERROR: Can't write file '"+path+"' !!!!"); 304 System.exit( -1 ); 305 } 306 } 307 308 // we have different types of properties in the source code 309 // each needs a different file nameing scheme detectFormat( String filename )310 private int detectFormat( String filename ) 311 { 312 if( filename.endsWith( "_en_US.properties" ) ) 313 return EXTENSION_TYPE; 314 else if( filename.endsWith("_en_us.properties" ) ) 315 return JAVA_ENUS_TYPE; 316 else if( filename.endsWith( ".properties" ) ) 317 return JAVA_TYPE; 318 319 // Can not detect, exit 320 System.err.println("ERROR: Invalid file name. Only allowed (case sensitive!) *_en_US.properties , *_en_us.properties or *.properties\n"); 321 System.exit(-1); 322 return JAVA_TYPE; // dummy 323 } 324 formatFilename( String filename , int filenameIdx , String lang , int type )325 private String formatFilename( String filename , int filenameIdx , String lang , int type ) 326 { 327 328 if( !lang.equals( "en-US" ) ) 329 { 330 // Parse iso code 331 int pos = lang.indexOf("-"); 332 String langpart1 = new String(); 333 String langpart2 = new String(); 334 if( pos == -1 ) 335 { 336 langpart1 = lang; 337 } 338 else if( pos > 0 ) 339 { 340 langpart1 = lang.substring( 0 , pos ); 341 langpart2 = lang.substring( pos+1 , lang.length() ); 342 } 343 // change filename according to the type 344 switch( type ) 345 { 346 // -> de_DE 347 case EXTENSION_TYPE: 348 lang = langpart1.toLowerCase(); 349 if( langpart2.length() > 0 ) // -> en_US 350 lang += "_" + langpart2.toUpperCase(); 351 else // -> de_DE 352 lang += "_" + langpart1.toUpperCase(); 353 return new StringBuffer().append( filename.substring( filenameIdx , filename.lastIndexOf( "_en_US.properties" ) ) ) 354 .append( "_" ).append( lang.replaceAll("-","_") ).append( ".properties" ).toString(); 355 // -> de 356 case JAVA_ENUS_TYPE: 357 lang = langpart1.toLowerCase(); 358 if( langpart2.length() > 0 ) 359 lang += "_" + langpart2.toLowerCase(); 360 return new StringBuffer().append( filename.substring( filenameIdx , filename.lastIndexOf( "_en_us.properties" ) ) ) 361 .append( "_" ).append( lang.replaceAll("-","_") ).append( ".properties" ).toString(); 362 // -> de 363 case JAVA_TYPE: 364 lang = langpart1.toLowerCase(); 365 if( langpart2.length() > 0 ) 366 lang += "_" + langpart2.toLowerCase(); 367 return new StringBuffer().append( filename.substring( filenameIdx , filename.lastIndexOf( ".properties" ) ) ) 368 .append( "_" ).append( lang.replaceAll("-","_") ).append( ".properties" ).toString(); 369 default: 370 System.err.println("ERROR: Something is really broken here, l10ntools/java/jprop/java/JPropEx.java :: formatFilename()"); 371 System.exit( -1 ); 372 break; 373 } 374 } 375 return filename; // don't change en-US source file name 376 } getSdfData()377 private SdfData getSdfData() 378 { 379 SdfData data = new SdfData( inputSdfFileArg ); 380 data.read(); 381 return data; 382 } getLanguages( SdfData data )383 private Vector getLanguages( SdfData data ) 384 { 385 Vector langs = new Vector(); 386 387 if( ((String)langsArg.get( 0 )).equalsIgnoreCase( "all" ) ) // for "-l all" use all languages found in the -m sdf file 388 langs.addAll( data.getLanguages() ); 389 else 390 langs.addAll( langsArg ); // use the langs giving by -l 391 392 if( forcedLangsArg != null ) 393 langs.addAll( forcedLangsArg ); 394 395 return removeDupes( langs ); 396 } removeDupes( Vector vec )397 private Vector removeDupes( Vector vec ) 398 { 399 Collection coll = new LinkedHashSet( vec ); 400 return new Vector( coll ); 401 } loadProp( String filename )402 private java.util.Properties loadProp( String filename ) 403 { 404 java.util.Properties prop = new java.util.Properties(); 405 try 406 { 407 prop.load( new BufferedInputStream( new NoLocalizeFilter( new FileInputStream( filename ) ) ) ); 408 } 409 catch( IOException e ) 410 { 411 System.err.println("ERROR: Can't read file '"+filename+"'!!!"); 412 } 413 return prop; 414 } parseArguments( String[] args )415 private void parseArguments( String[] args ) 416 { 417 418 if( args.length == 0 ) 419 { 420 System.out.println("ERROR: No args???"); 421 help(); 422 System.exit( -1 ); 423 } 424 for( int x = 0; x < args.length ; x++ ) 425 { 426 if( args[ x ].equalsIgnoreCase("-i") ) 427 { 428 // Input resource file 429 inputFileArg = getSimpleArg( args , x ); 430 } 431 else if( args[ x ].equalsIgnoreCase("-o") ) 432 { 433 // Output sdf file 434 outputFileArg = getSimpleArg( args , x ); 435 } 436 else if( args[ x ].equalsIgnoreCase("-x") ) 437 { 438 // path prefix 439 pathPrefixArg = getSimpleArg( args , x ); 440 } 441 else if( args[ x ].equalsIgnoreCase("-y") ) 442 { 443 // path postfix 444 pathPostfixArg = getSimpleArg( args , x ); 445 } 446 else if( args[ x ].equalsIgnoreCase("-p") ) 447 { 448 // project 449 projectArg = getSimpleArg( args , x ); 450 } 451 else if( args[ x ].equalsIgnoreCase("-r") ) 452 { 453 // root 454 rootArg = getSimpleArg( args , x ); 455 rootArg = makeAbs( rootArg ); 456 } 457 else if( args[ x ].equalsIgnoreCase("-lf") ) 458 { 459 // forced langs 460 forcedLangsArg = getComplexArg( args , x ); 461 } 462 else if( args[ x ].equalsIgnoreCase("-l") ) 463 { 464 // langs 465 langsArg = getComplexArg( args , x ); 466 } 467 else if( args[ x ].equalsIgnoreCase("-m") ) 468 { 469 // input sdf file 470 inputSdfFileArg = getSimpleArg( args , x ); 471 } 472 else if( args[ x ].equalsIgnoreCase("-qq") ) 473 { 474 isQuiet = true; 475 } 476 } 477 } makeAbs( String path )478 private String makeAbs( String path ) 479 { 480 File file; 481 try 482 { 483 file = new File( path ); 484 return file.getCanonicalPath(); 485 }catch( IOException e ) 486 { 487 e.printStackTrace(); 488 System.exit( -1 ); 489 } 490 return null; 491 } 492 /* private boolean testArguments() 493 { 494 // nice merge 495 if( inputSdfFileArg != null && inputSdfFileArg.length()>0 ) 496 // nice merge 497 return projectArg != null && rootArg != null && inputFileArg != null && pathPrefixArg != null && pathPostfixArg != null && langsArg != null && 498 projectArg.length()>0 && rootArg.length()>0 && inputFileArg.length()>0 && pathPrefixArg.length()>0 && pathPostfixArg.length()>0 && langsArg.size()>0 ; 499 else 500 // nice extract 501 return projectArg != null && rootArg != null && inputFileArg != null && outputFileArg != null && langsArg != null && 502 projectArg.length()>0 && rootArg.length()>0 && inputFileArg.length()>0 && outputFileArg.length()>0 && langsArg.size()>0; 503 } 504 */ 505 } 506