1 18 package org.apache.tools.ant.taskdefs.optional.i18n; 19 20 import java.io.BufferedReader ; 21 import java.io.BufferedWriter ; 22 import java.io.File ; 23 import java.io.FileInputStream ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.io.InputStreamReader ; 27 import java.io.OutputStreamWriter ; 28 import java.util.Hashtable ; 29 import java.util.Locale ; 30 import java.util.Vector ; 31 import org.apache.tools.ant.BuildException; 32 import org.apache.tools.ant.DirectoryScanner; 33 import org.apache.tools.ant.Project; 34 import org.apache.tools.ant.taskdefs.MatchingTask; 35 import org.apache.tools.ant.types.FileSet; 36 import org.apache.tools.ant.util.FileUtils; 37 import org.apache.tools.ant.util.LineTokenizer; 38 39 44 public class Translate extends MatchingTask { 45 48 private static final int BUNDLE_SPECIFIED_LANGUAGE_COUNTRY_VARIANT = 0; 49 52 private static final int BUNDLE_SPECIFIED_LANGUAGE_COUNTRY = 1; 53 56 private static final int BUNDLE_SPECIFIED_LANGUAGE = 2; 57 60 private static final int BUNDLE_NOMATCH = 3; 61 65 private static final int BUNDLE_DEFAULT_LANGUAGE_COUNTRY_VARIANT = 4; 66 70 private static final int BUNDLE_DEFAULT_LANGUAGE_COUNTRY = 5; 71 75 private static final int BUNDLE_DEFAULT_LANGUAGE = 6; 76 79 private static final int BUNDLE_MAX_ALTERNATIVES = BUNDLE_DEFAULT_LANGUAGE + 1; 80 83 private String bundle; 84 85 88 private String bundleLanguage; 89 90 93 private String bundleCountry; 94 95 98 private String bundleVariant; 99 100 103 private File toDir; 104 105 108 private String srcEncoding; 109 110 113 private String destEncoding; 114 115 118 private String bundleEncoding; 119 120 123 private String startToken; 124 125 128 private String endToken; 129 130 134 private boolean forceOverwrite; 135 136 139 private Vector filesets = new Vector (); 140 141 144 private Hashtable resourceMap = new Hashtable (); 145 149 private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); 150 151 154 private long[] bundleLastModified = new long[BUNDLE_MAX_ALTERNATIVES]; 155 156 159 private long srcLastModified; 160 161 164 private long destLastModified; 165 166 169 private boolean loaded = false; 170 171 175 public void setBundle(String bundle) { 176 this.bundle = bundle; 177 } 178 179 183 public void setBundleLanguage(String bundleLanguage) { 184 this.bundleLanguage = bundleLanguage; 185 } 186 187 191 public void setBundleCountry(String bundleCountry) { 192 this.bundleCountry = bundleCountry; 193 } 194 195 199 public void setBundleVariant(String bundleVariant) { 200 this.bundleVariant = bundleVariant; 201 } 202 203 207 public void setToDir(File toDir) { 208 this.toDir = toDir; 209 } 210 211 215 public void setStartToken(String startToken) { 216 this.startToken = startToken; 217 } 218 219 223 public void setEndToken(String endToken) { 224 this.endToken = endToken; 225 } 226 227 232 public void setSrcEncoding(String srcEncoding) { 233 this.srcEncoding = srcEncoding; 234 } 235 236 241 public void setDestEncoding(String destEncoding) { 242 this.destEncoding = destEncoding; 243 } 244 245 250 public void setBundleEncoding(String bundleEncoding) { 251 this.bundleEncoding = bundleEncoding; 252 } 253 254 261 public void setForceOverwrite(boolean forceOverwrite) { 262 this.forceOverwrite = forceOverwrite; 263 } 264 265 269 public void addFileset(FileSet set) { 270 filesets.addElement(set); 271 } 272 273 282 public void execute() throws BuildException { 283 if (bundle == null) { 284 throw new BuildException("The bundle attribute must be set.", 285 getLocation()); 286 } 287 288 if (startToken == null) { 289 throw new BuildException("The starttoken attribute must be set.", 290 getLocation()); 291 } 292 293 if (endToken == null) { 294 throw new BuildException("The endtoken attribute must be set.", 295 getLocation()); 296 } 297 298 if (bundleLanguage == null) { 299 Locale l = Locale.getDefault(); 300 bundleLanguage = l.getLanguage(); 301 } 302 303 if (bundleCountry == null) { 304 bundleCountry = Locale.getDefault().getCountry(); 305 } 306 307 if (bundleVariant == null) { 308 Locale l = new Locale (bundleLanguage, bundleCountry); 309 bundleVariant = l.getVariant(); 310 } 311 312 if (toDir == null) { 313 throw new BuildException("The todir attribute must be set.", 314 getLocation()); 315 } 316 317 if (!toDir.exists()) { 318 toDir.mkdirs(); 319 } else if (toDir.isFile()) { 320 throw new BuildException(toDir + " is not a directory"); 321 } 322 323 if (srcEncoding == null) { 324 srcEncoding = System.getProperty("file.encoding"); 325 } 326 327 if (destEncoding == null) { 328 destEncoding = srcEncoding; 329 } 330 331 if (bundleEncoding == null) { 332 bundleEncoding = srcEncoding; 333 } 334 335 loadResourceMaps(); 336 337 translate(); 338 } 339 340 359 private void loadResourceMaps() throws BuildException { 360 Locale locale = new Locale (bundleLanguage, 361 bundleCountry, 362 bundleVariant); 363 String language = locale.getLanguage().length() > 0 364 ? "_" + locale.getLanguage() : ""; 365 String country = locale.getCountry().length() > 0 366 ? "_" + locale.getCountry() : ""; 367 String variant = locale.getVariant().length() > 0 368 ? "_" + locale.getVariant() : ""; 369 String bundleFile = bundle + language + country + variant; 370 processBundle(bundleFile, BUNDLE_SPECIFIED_LANGUAGE_COUNTRY_VARIANT, false); 371 372 bundleFile = bundle + language + country; 373 processBundle(bundleFile, BUNDLE_SPECIFIED_LANGUAGE_COUNTRY, false); 374 375 bundleFile = bundle + language; 376 processBundle(bundleFile, BUNDLE_SPECIFIED_LANGUAGE, false); 377 378 bundleFile = bundle; 379 processBundle(bundleFile, BUNDLE_NOMATCH, false); 380 381 locale = Locale.getDefault(); 384 385 language = locale.getLanguage().length() > 0 386 ? "_" + locale.getLanguage() : ""; 387 country = locale.getCountry().length() > 0 388 ? "_" + locale.getCountry() : ""; 389 variant = locale.getVariant().length() > 0 390 ? "_" + locale.getVariant() : ""; 391 bundleEncoding = System.getProperty("file.encoding"); 392 393 bundleFile = bundle + language + country + variant; 394 processBundle(bundleFile, BUNDLE_DEFAULT_LANGUAGE_COUNTRY_VARIANT, false); 395 396 bundleFile = bundle + language + country; 397 processBundle(bundleFile, BUNDLE_DEFAULT_LANGUAGE_COUNTRY, false); 398 399 bundleFile = bundle + language; 400 processBundle(bundleFile, BUNDLE_DEFAULT_LANGUAGE, true); 401 } 402 403 406 private void processBundle(final String bundleFile, final int i, 407 final boolean checkLoaded) throws BuildException { 408 final File propsFile = getProject().resolveFile(bundleFile + ".properties"); 409 FileInputStream ins = null; 410 try { 411 ins = new FileInputStream (propsFile); 412 loaded = true; 413 bundleLastModified[i] = propsFile.lastModified(); 414 log("Using " + propsFile, Project.MSG_DEBUG); 415 loadResourceMap(ins); 416 } catch (IOException ioe) { 417 log(propsFile + " not found.", Project.MSG_DEBUG); 418 if (!loaded && checkLoaded) { 422 throw new BuildException(ioe.getMessage(), getLocation()); 423 } 424 } 425 } 426 427 431 private void loadResourceMap(FileInputStream ins) throws BuildException { 432 try { 433 BufferedReader in = null; 434 InputStreamReader isr = new InputStreamReader (ins, bundleEncoding); 435 in = new BufferedReader (isr); 436 String line = null; 437 while ((line = in.readLine()) != null) { 438 if (line.trim().length() > 1 && '#' != line.charAt(0) && '!' != line.charAt(0)) { 440 int sepIndex = line.indexOf('='); 442 if (-1 == sepIndex) { 443 sepIndex = line.indexOf(':'); 444 } 445 if (-1 == sepIndex) { 446 for (int k = 0; k < line.length(); k++) { 447 if (Character.isSpaceChar(line.charAt(k))) { 448 sepIndex = k; 449 break; 450 } 451 } 452 } 453 if (-1 != sepIndex) { 455 String key = line.substring(0, sepIndex).trim(); 456 String value = line.substring(sepIndex + 1).trim(); 457 while (value.endsWith("\\")) { 459 value = value.substring(0, value.length() - 1); 460 if ((line = in.readLine()) != null) { 461 value = value + line.trim(); 462 } else { 463 break; 464 } 465 } 466 if (key.length() > 0) { 467 if (resourceMap.get(key) == null) { 469 resourceMap.put(key, value); 470 } 471 } 472 } 473 } 474 } 475 if (in != null) { 476 in.close(); 477 } 478 } catch (IOException ioe) { 479 throw new BuildException(ioe.getMessage(), getLocation()); 480 } 481 } 482 483 495 private void translate() throws BuildException { 496 int filesProcessed = 0; 497 for (int i = 0; i < filesets.size(); i++) { 498 FileSet fs = (FileSet) filesets.elementAt(i); 499 DirectoryScanner ds = fs.getDirectoryScanner(getProject()); 500 String [] srcFiles = ds.getIncludedFiles(); 501 for (int j = 0; j < srcFiles.length; j++) { 502 try { 503 File dest = FILE_UTILS.resolveFile(toDir, srcFiles[j]); 504 try { 506 File destDir = new File (dest.getParent()); 507 if (!destDir.exists()) { 508 destDir.mkdirs(); 509 } 510 } catch (Exception e) { 511 log("Exception occurred while trying to check/create " 512 + " parent directory. " + e.getMessage(), 513 Project.MSG_DEBUG); 514 } 515 destLastModified = dest.lastModified(); 516 File src = FILE_UTILS.resolveFile(ds.getBasedir(), srcFiles[j]); 517 srcLastModified = src.lastModified(); 518 boolean needsWork = forceOverwrite 520 || destLastModified < srcLastModified; 521 if (!needsWork) { 522 for (int icounter = 0; icounter < BUNDLE_MAX_ALTERNATIVES; icounter++) { 523 needsWork = (destLastModified < bundleLastModified[icounter]); 524 if (needsWork) { 525 break; 526 } 527 } 528 } 529 if (needsWork) { 530 log("Processing " + srcFiles[j], 531 Project.MSG_DEBUG); 532 FileOutputStream fos = new FileOutputStream (dest); 533 BufferedWriter out 534 = new BufferedWriter (new OutputStreamWriter (fos, destEncoding)); 535 FileInputStream fis = new FileInputStream (src); 536 BufferedReader in 537 = new BufferedReader (new InputStreamReader (fis, srcEncoding)); 538 String line; 539 LineTokenizer lineTokenizer = new LineTokenizer(); 540 lineTokenizer.setIncludeDelims(true); 541 line = lineTokenizer.getToken(in); 542 while ((line) != null) { 543 546 int startIndex = line.indexOf(startToken); 549 while (startIndex >= 0 550 && (startIndex + startToken.length()) <= line.length()) { 551 String replace = null; 555 556 int endIndex = line.indexOf( 560 endToken, startIndex + startToken.length()); 561 if (endIndex < 0) { 562 startIndex += 1; 563 } else { 564 String token = line.substring( 566 startIndex + startToken.length(), endIndex); 567 568 boolean validToken = true; 571 for (int k = 0; k < token.length() && validToken; k++) { 572 char c = token.charAt(k); 573 if (c == ':' || c == '=' 574 || Character.isSpaceChar(c)) { 575 validToken = false; 576 } 577 } 578 if (!validToken) { 579 startIndex += 1; 580 } else { 581 if (resourceMap.containsKey(token)) { 583 replace = (String ) resourceMap.get(token); 584 } else { 585 log("Replacement string missing for: " 586 + token, Project.MSG_VERBOSE); 587 replace = startToken + token + endToken; 588 } 589 590 591 line = line.substring(0, startIndex) 593 + replace 594 + line.substring(endIndex + endToken.length()); 595 596 startIndex += replace.length(); 598 } 599 } 600 601 startIndex = line.indexOf(startToken, startIndex); 603 } 604 out.write(line); 605 line = lineTokenizer.getToken(in); 606 } 607 if (in != null) { 608 in.close(); 609 } 610 if (out != null) { 611 out.close(); 612 } 613 ++filesProcessed; 614 } else { 615 log("Skipping " + srcFiles[j] 616 + " as destination file is up to date", 617 Project.MSG_VERBOSE); 618 } 619 } catch (IOException ioe) { 620 throw new BuildException(ioe.getMessage(), getLocation()); 621 } 622 } 623 } 624 log("Translation performed on " + filesProcessed + " file(s).", Project.MSG_DEBUG); 625 } 626 } 627 | Popular Tags |