1 /* 2 ***************************************************************************** 3 * Copyright (C) 2000-2007, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ***************************************************************************** 6 */ 7 package com.ibm.rbm; 8 9 10 import java.io.IOException; 11 import java.io.PrintStream; 12 import java.io.Writer; 13 import java.text.SimpleDateFormat; 14 import java.text.ParseException; 15 import java.util.*; 16 17 /** 18 * A class representing a single translation item and all of the meta-data associated with that translation 19 * 20 * @author Jared Jackson - Email: <a href="mailto:jjared@almaden.ibm.com">jjared@almaden.ibm.com</a> 21 * @see com.ibm.rbm.RBManager 22 */ 23 public class BundleItem { 24 private String name; // The name of the NLS item key 25 private String value; // The translation of the key item 26 private String comment; // A comment about this item 27 private boolean translated; // Has this item been translated? 28 private Date created; // The date of creation of the item 29 private Date modified; // The last modification date of the item 30 private String creator; // The name of the person who created the item 31 private String modifier; // The name of the person who last modified the item 32 private Hashtable lookups; // A hash table of lookups for the item (i.e. ({#}, Meaning) pairs) 33 private BundleGroup group; // The parent group of the item 34 35 /** 36 * Basic data constructor for a resource bundle item. 37 * @param parent The BundleGroup to which the item belongs. This group will have its own Bundle parent. 38 * @param name The NLS lookup key common across all bundle files in the resource bundle 39 * @param value The translated value of the item appropriate for the encoding of the bundle file to which the item belongs 40 */ 41 BundleItem(BundleGroup parent, String name, String value)42 public BundleItem(BundleGroup parent, String name, String value) { 43 this.name = name; 44 this.value = value; 45 this.group = parent; 46 comment = null; 47 translated = false; 48 created = new Date(); // Defaults to the system's current date 49 modified = new Date(); // Defaults to the system's current date 50 creator = null; 51 modifier = null; 52 lookups = new Hashtable(); 53 } 54 55 /** 56 * Returns the BundleGroup to which this item belongs 57 */ 58 getParentGroup()59 public BundleGroup getParentGroup() { 60 return group; 61 } 62 63 /** 64 * Returns the date this item was last modified. 65 */ 66 getModifiedDate()67 public Date getModifiedDate() { 68 return modified; 69 } 70 71 /** 72 * Returns the date the item was first created. 73 */ 74 getCreatedDate()75 public Date getCreatedDate() { 76 return created; 77 } 78 79 /** 80 * Returns the login name of the user that created the item. 81 */ 82 getCreator()83 public String getCreator() { 84 return creator; 85 } 86 87 /** 88 * Returns the login name of the user that last modified the item. 89 */ 90 getModifier()91 public String getModifier() { 92 return modifier; 93 } 94 95 /** 96 * Returns the NLS lookup key for the item. 97 */ 98 getKey()99 public String getKey() { 100 return name; 101 } 102 103 /** 104 * Returns the translation value for the item. 105 */ 106 getTranslation()107 public String getTranslation() { 108 return value; 109 } 110 111 /** 112 * Returns a comment associated with the item. 113 */ 114 getComment()115 public String getComment() { 116 return comment; 117 } 118 119 /** 120 * Has the item yet been translated, or was it merely derived from a previous 121 * bundle file? 122 */ 123 isTranslated()124 public boolean isTranslated() { 125 return translated; 126 } 127 128 /** 129 * Returns a hashtable of the various lookups associated with the item. Lookups are 130 * context sensitive information stored within the resource item and have their own 131 * meta-data associated with themselves. 132 */ 133 getLookups()134 public Hashtable getLookups() { 135 return lookups; 136 } 137 138 /** 139 * Sets the translated value of the item. A true mark indicates that the item has 140 * been examined or modified and is ready for use in the encoding specified by the 141 * parent Bundle. 142 */ 143 setTranslated(boolean isTranslated)144 public void setTranslated(boolean isTranslated) { 145 if (translated == isTranslated) return; 146 translated = isTranslated; 147 if (this.getParentGroup() != null && this.getParentGroup().getParentBundle() != null) { 148 Bundle bundle = this.getParentGroup().getParentBundle(); 149 if (isTranslated) bundle.removeUntranslatedItem(this.name); 150 else bundle.addUntranslatedItem(this); 151 } 152 } 153 154 /** 155 * Sets the comment associated with this item. 156 */ 157 setComment(String comment)158 public void setComment(String comment) { 159 this.comment = comment; 160 } 161 162 /** 163 * Given a hashtable of lookups, associates those lookups with this item. 164 */ 165 setLookups(Hashtable lookups)166 public void setLookups(Hashtable lookups) { 167 this.lookups = lookups; 168 } 169 170 /** 171 * Sets the NLS key associated with this item. Be careful using this method, as 172 * it does not change the lookup value of any other items in the resource bundle. 173 * This must be done at a higher level. 174 */ 175 setKey(String keyName)176 public void setKey(String keyName) { 177 name = keyName; 178 } 179 180 /** 181 * Sets the translation value of the item. 182 */ 183 setTranslation(String translationValue)184 public void setTranslation(String translationValue) { 185 value = translationValue; 186 } 187 188 /** 189 * Sets the parent BundleGroup of the item. 190 */ 191 setParentGroup(BundleGroup group)192 public void setParentGroup(BundleGroup group) { 193 this.group = group; 194 } 195 196 /** 197 * Associates a login name of the creator of the item with the item. 198 */ 199 setCreator(String name)200 public void setCreator(String name) { 201 creator = name; 202 } 203 204 /** 205 * Associates a login name of the last modifier of the item with the item. 206 */ 207 setModifier(String name)208 public void setModifier(String name) { 209 modifier = name; 210 } 211 212 /** 213 * Sets the created date of the item given a date formatted string. 214 * The format can be either 'YYYY-MM-DD' (e.g. 20002-02-05) or 215 * the format can be 'YYYMMDDTHHMMSSZ' (e.g. 20020205T103000Z) 216 */ 217 setCreatedDate(String dateStr)218 public void setCreatedDate(String dateStr) { 219 if (dateStr != null) created = parseDateFromString(dateStr); 220 } 221 222 /** 223 * Sets the created date of the item. 224 */ 225 setCreatedDate(Date date)226 public void setCreatedDate(Date date) { 227 created = date; 228 } 229 230 /** 231 * Sets the last modififcation date of the item given a date formatted string. 232 * The format can be either 'YYYY-MM-DD' (e.g. 2002-02-05) or 233 * the format can be 'YYYMMDDTHHMMSSZ' (e.g. 20020205T103000Z) 234 */ 235 setModifiedDate(String dateStr)236 public void setModifiedDate(String dateStr) { 237 if (dateStr != null) 238 modified = parseDateFromString(dateStr); 239 } 240 241 /** 242 * Sets the last modification date of the item. 243 */ 244 setModifiedDate(Date date)245 public void setModifiedDate(Date date) { 246 modified = date; 247 } 248 249 /** 250 * Simply returns the lookup name of the item. 251 */ 252 toString()253 public String toString() { 254 return name; 255 } 256 257 /** 258 * Returns the formatted output of this bundle item as it would be included in a .properties 259 * formatted resource bundle file. This format also contains the meta-data used by RBManager in 260 * the form of parseable comments. 261 */ 262 toOutputString()263 public String toOutputString() { 264 String retStr = (translated ? "# @translated true" : "# @translated false"); 265 if (created != null) { 266 GregorianCalendar createdCal = new GregorianCalendar(); 267 createdCal.setTime(created); 268 int year = createdCal.get(Calendar.YEAR); 269 int month = createdCal.get(Calendar.MONTH)+1; 270 int day = createdCal.get(Calendar.DAY_OF_MONTH); 271 retStr += " @created " + String.valueOf(year) + "-" 272 + (month > 9 ? String.valueOf(month) : "0" + String.valueOf(month)) + "-" 273 + (day > 9 ? String.valueOf(day) : "0" + String.valueOf(day)); 274 } 275 if (modified != null) { 276 GregorianCalendar modifiedCal = new GregorianCalendar(); 277 modifiedCal.setTime(modified); 278 int year = modifiedCal.get(Calendar.YEAR); 279 int month = modifiedCal.get(Calendar.MONTH)+1; 280 int day = modifiedCal.get(Calendar.DAY_OF_MONTH); 281 retStr += " @modified " + String.valueOf(year) + "-" 282 + (month > 9 ? String.valueOf(month) : "0" + String.valueOf(month)) + "-" 283 + (day > 9 ? String.valueOf(day) : "0" + String.valueOf(day)); 284 } 285 if (creator != null) retStr += " @creator " + creator; 286 if (modifier != null) retStr += " @modifier " + modifier; 287 Enumeration elems = lookups.keys(); 288 while (elems.hasMoreElements()) { 289 String str = (String)elems.nextElement(); 290 retStr += "\n# @{" + str + "} " + (String)lookups.get(str); 291 } 292 if (comment != null) retStr += "\n# @comment " + comment; 293 294 retStr += "\n" + name + "=" + saveConvert(value); 295 return retStr; 296 } 297 298 /** 299 * Writes the formatted contents to a PrintStream. 300 */ 301 writeContents(PrintStream ps)302 public void writeContents(PrintStream ps) { 303 ps.println(this.toOutputString()); 304 } 305 306 /** 307 * Writes the formatted contents to a writer such as a FileWriter. 308 */ 309 writeContents(Writer w)310 public void writeContents(Writer w) throws IOException { 311 w.write(this.toOutputString() + "\n"); 312 } 313 314 /* 315 * Converts unicodes to encoded \\uxxxx 316 * and writes out any of the characters in specialSaveChars 317 * with a preceding slash 318 */ 319 // Taken from java.util.Properties saveConvert(String theString)320 private String saveConvert(String theString) { 321 char aChar; 322 int len = theString.length(); 323 StringBuffer outBuffer = new StringBuffer(len*2); 324 325 for(int x=0; x<len; ) { 326 aChar = theString.charAt(x++); 327 switch(aChar) { 328 case '\\':outBuffer.append('\\'); outBuffer.append('\\'); 329 continue; 330 case '\t':outBuffer.append('\\'); outBuffer.append('t'); 331 continue; 332 case '\n':outBuffer.append('\\'); outBuffer.append('n'); 333 continue; 334 case '\r':outBuffer.append('\\'); outBuffer.append('r'); 335 continue; 336 case '\f':outBuffer.append('\\'); outBuffer.append('f'); 337 continue; 338 default: 339 if ((aChar < 20) || (aChar > 127)) { 340 outBuffer.append('\\'); 341 outBuffer.append('u'); 342 outBuffer.append(toHex((aChar >> 12) & 0xF)); 343 outBuffer.append(toHex((aChar >> 8) & 0xF)); 344 outBuffer.append(toHex((aChar >> 4) & 0xF)); 345 outBuffer.append(toHex((aChar >> 0) & 0xF)); 346 } 347 else { 348 if (specialSaveChars.indexOf(aChar) != -1) 349 outBuffer.append('\\'); 350 outBuffer.append(aChar); 351 } 352 } 353 } 354 return outBuffer.toString(); 355 } 356 357 /** 358 * Convert a nibble to a hex character 359 * @param nibble the nibble to convert. 360 */ 361 // Taken from java.util.Properties toHex(int nibble)362 private static char toHex(int nibble) { 363 return hexDigit[(nibble & 0xF)]; 364 } 365 366 /** A table of hex digits */ 367 // Taken from java.util.Properties 368 private static final char[] hexDigit = { 369 '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' 370 }; 371 372 // Taken from java.util.Properties 373 private static final String specialSaveChars = "=: \t\r\n\f#!"; 374 parseDateFromString(String dateStr)375 private Date parseDateFromString(String dateStr) { 376 SimpleDateFormat format = null; 377 if (dateStr.length() == 10) 378 format = new SimpleDateFormat("yyyy-MM-dd"); // Simple format 379 else 380 format = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'"); // TMX ISO format 381 try { 382 return format.parse(dateStr); 383 } catch (ParseException pe) { 384 return new Date(); 385 } 386 } 387 }