/* ****************************************************************************** * Copyright (C) 2003-2013, International Business Machines Corporation and * * others. All Rights Reserved. * ****************************************************************************** */ package com.ibm.icu.dev.tool.localeconverter; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.text.MessageFormat; import java.util.Date; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import com.ibm.icu.dev.tool.UOption; public final class XLIFF2ICUConverter { /** * These must be kept in sync with getOptions(). */ private static final int HELP1 = 0; private static final int HELP2 = 1; private static final int SOURCEDIR = 2; private static final int DESTDIR = 3; private static final int TARGETONLY = 4; private static final int SOURCEONLY = 5; private static final int MAKE_SOURCE_ROOT = 6; private static final int XLIFF_1_0 = 7; private static final UOption[] options = new UOption[] { UOption.HELP_H(), UOption.HELP_QUESTION_MARK(), UOption.SOURCEDIR(), UOption.DESTDIR(), UOption.create("target-only", 't', UOption.OPTIONAL_ARG), UOption.create("source-only", 'c', UOption.OPTIONAL_ARG), UOption.create("make-source-root", 'r', UOption.NO_ARG), UOption.create("xliff-1.0", 'x', UOption.NO_ARG) }; private static final int ARRAY_RESOURCE = 0; private static final int ALIAS_RESOURCE = 1; private static final int BINARY_RESOURCE = 2; private static final int INTEGER_RESOURCE = 3; private static final int INTVECTOR_RESOURCE = 4; private static final int TABLE_RESOURCE = 5; private static final String NEW_RESOURCES[] = { "x-icu-array", "x-icu-alias", "x-icu-binary", "x-icu-integer", "x-icu-intvector", "x-icu-table" }; private static final String OLD_RESOURCES[] = { "array", "alias", "bin", "int", "intvector", "table" }; private String resources[]; private static final String ROOT = "root"; private static final String RESTYPE = "restype"; private static final String RESNAME = "resname"; //private static final String YES = "yes"; //private static final String NO = "no"; private static final String TRANSLATE = "translate"; //private static final String BODY = "body"; private static final String GROUPS = "group"; private static final String FILES = "file"; private static final String TRANSUNIT = "trans-unit"; private static final String BINUNIT = "bin-unit"; private static final String BINSOURCE = "bin-source"; //private static final String TS = "ts"; //private static final String ORIGINAL = "original"; private static final String SOURCELANGUAGE = "source-language"; private static final String TARGETLANGUAGE = "target-language"; private static final String TARGET = "target"; private static final String SOURCE = "source"; private static final String NOTE = "note"; private static final String XMLLANG = "xml:lang"; private static final String FILE = "file"; private static final String INTVECTOR = "intvector"; private static final String ARRAYS = "array"; private static final String STRINGS = "string"; private static final String BIN = "bin"; private static final String INTS = "int"; private static final String TABLE = "table"; private static final String IMPORT = "import"; private static final String HREF = "href"; private static final String EXTERNALFILE = "external-file"; private static final String INTERNALFILE = "internal-file"; private static final String ALTTRANS = "alt-trans"; private static final String CRC = "crc"; private static final String ALIAS = "alias"; private static final String LINESEP = System.getProperty("line.separator"); private static final String BOM = "\uFEFF"; private static final String CHARSET = "UTF-8"; private static final String OPENBRACE = "{"; private static final String CLOSEBRACE = "}"; private static final String COLON = ":"; private static final String COMMA = ","; private static final String QUOTE = "\""; private static final String COMMENTSTART = "/**"; private static final String COMMENTEND = " */"; private static final String TAG = " * @"; private static final String COMMENTMIDDLE = " * "; private static final String SPACE = " "; private static final String INDENT = " "; private static final String EMPTY = ""; private static final String ID = "id"; public static void main(String[] args) { XLIFF2ICUConverter cnv = new XLIFF2ICUConverter(); cnv.processArgs(args); } private String sourceDir = null; //private String fileName = null; private String destDir = null; private boolean targetOnly = false; private String targetFileName = null; private boolean makeSourceRoot = false; private String sourceFileName = null; private boolean sourceOnly = false; private boolean xliff10 = false; private void processArgs(String[] args) { int remainingArgc = 0; try{ remainingArgc = UOption.parseArgs(args, options); }catch (Exception e){ System.err.println("ERROR: "+ e.toString()); usage(); } if(args.length==0 || options[HELP1].doesOccur || options[HELP2].doesOccur) { usage(); } if(remainingArgc==0){ System.err.println("ERROR: Either the file name to be processed is not "+ "specified or the it is specified after the -t/-c \n"+ "option which has an optional argument. Try rearranging "+ "the options."); usage(); } if(options[SOURCEDIR].doesOccur) { sourceDir = options[SOURCEDIR].value; } if(options[DESTDIR].doesOccur) { destDir = options[DESTDIR].value; } if(options[TARGETONLY].doesOccur){ targetOnly = true; targetFileName = options[TARGETONLY].value; } if(options[SOURCEONLY].doesOccur){ sourceOnly = true; sourceFileName = options[SOURCEONLY].value; } if(options[MAKE_SOURCE_ROOT].doesOccur){ makeSourceRoot = true; } if(options[XLIFF_1_0].doesOccur) { xliff10 = true; } if(destDir==null){ destDir = "."; } if(sourceOnly == true && targetOnly == true){ System.err.println("--source-only and --target-only are specified. Please check the arguments and try again."); usage(); } for (int i = 0; i < remainingArgc; i++) { //int lastIndex = args[i].lastIndexOf(File.separator, args[i].length()) + 1; /* add 1 to skip past the separator */ //fileName = args[i].substring(lastIndex, args[i].length()); String xmlfileName = getFullPath(false,args[i]); System.out.println("Processing file: "+xmlfileName); createRB(xmlfileName); } } private void usage() { System.out.println("\nUsage: XLIFF2ICUConverter [OPTIONS] [FILES]\n\n"+ "This program is used to convert XLIFF files to ICU ResourceBundle TXT files.\n"+ "Please refer to the following options. Options are not case sensitive.\n"+ "Options:\n"+ "-s or --sourcedir source directory for files followed by path, default is current directory.\n" + "-d or --destdir destination directory, followed by the path, default is current directory.\n" + "-h or -? or --help this usage text.\n"+ "-t or --target-only only generate the target language txt file, followed by optional output file name.\n" + " Cannot be used in conjunction with --source-only.\n"+ "-c or --source-only only generate the source language bundle followed by optional output file name.\n"+ " Cannot be used in conjunction with --target-only.\n"+ "-r or --make-source-root produce root bundle from source elements.\n" + "-x or --xliff-1.0 source file is XLIFF 1.0" + "example: com.ibm.icu.dev.tool.localeconverter.XLIFF2ICUConverter -t -s xxx -d yyy myResources.xlf"); System.exit(-1); } private String getFullPath(boolean fileType, String fName){ String str; int lastIndex1 = fName.lastIndexOf(File.separator, fName.length()) + 1; /*add 1 to skip past the separator*/ int lastIndex2 = fName.lastIndexOf('.', fName.length()); if (fileType == true) { if(lastIndex2 == -1){ fName = fName.trim() + ".txt"; }else{ if(!fName.substring(lastIndex2).equalsIgnoreCase(".txt")){ fName = fName.substring(lastIndex1,lastIndex2) + ".txt"; } } if (destDir != null && fName != null) { str = destDir + File.separator + fName.trim(); } else { str = System.getProperty("user.dir") + File.separator + fName.trim(); } } else { if(lastIndex2 == -1){ fName = fName.trim() + ".xlf"; }else{ if(!fName.substring(lastIndex2).equalsIgnoreCase(".xml") && fName.substring(lastIndex2).equalsIgnoreCase(".xlf")){ fName = fName.substring(lastIndex1,lastIndex2) + ".xlf"; } } if(sourceDir != null && fName != null) { str = sourceDir + File.separator + fName; } else if (lastIndex1 > 0) { str = fName; } else { str = System.getProperty("user.dir") + File.separator + fName; } } return str; } /* * Utility method to translate a String filename to URL. * * Note: This method is not necessarily proven to get the * correct URL for every possible kind of filename; it should * be improved. It handles the most common cases that we've * encountered when running Conformance tests on Xalan. * Also note, this method does not handle other non-file: * flavors of URLs at all. * * If the name is null, return null. * If the name starts with a common URI scheme (namely the ones * found in the examples of RFC2396), then simply return the * name as-is (the assumption is that it's already a URL) * Otherwise we attempt (cheaply) to convert to a file:/// URL. */ private static String filenameToURL(String filename){ // null begets null - something like the commutative property if (null == filename){ return null; } // Don't translate a string that already looks like a URL if (filename.startsWith("file:") || filename.startsWith("http:") || filename.startsWith("ftp:") || filename.startsWith("gopher:") || filename.startsWith("mailto:") || filename.startsWith("news:") || filename.startsWith("telnet:") ){ return filename; } File f = new File(filename); String tmp = null; try{ // This normally gives a better path tmp = f.getCanonicalPath(); }catch (IOException ioe){ // But this can be used as a backup, for cases // where the file does not exist, etc. tmp = f.getAbsolutePath(); } // URLs must explicitly use only forward slashes if (File.separatorChar == '\\') { tmp = tmp.replace('\\', '/'); } // Note the presumption that it's a file reference // Ensure we have the correct number of slashes at the // start: we always want 3 /// if it's absolute // (which we should have forced above) if (tmp.startsWith("/")){ return "file://" + tmp; } else{ return "file:///" + tmp; } } private boolean isXmlLang (String lang){ int suffix; char c; if (lang.length () < 2){ return false; } c = lang.charAt(1); if (c == '-') { c = lang.charAt(0); if (!(c == 'i' || c == 'I' || c == 'x' || c == 'X')){ return false; } suffix = 1; } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { c = lang.charAt(0); if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))){ return false; } suffix = 2; } else{ return false; } while (suffix < lang.length ()) { c = lang.charAt(suffix); if (c != '-'){ break; } while (++suffix < lang.length ()) { c = lang.charAt(suffix); if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))){ break; } } } return ((lang.length() == suffix) && (c != '-')); } private void createRB(String xmlfileName) { String urls = filenameToURL(xmlfileName); DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); dfactory.setNamespaceAware(true); Document doc = null; if (xliff10) { dfactory.setValidating(true); resources = OLD_RESOURCES; } else { try { SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = schemaFactory.newSchema(); dfactory.setSchema(schema); } catch (SAXException e) { System.err.println("Can't create the schema..."); System.exit(-1); } catch (UnsupportedOperationException e) { System.err.println("ERROR:\tOne of the schema operations is not supported with this JVM."); System.err.println("\tIf you are using GNU Java, you should try using the latest Sun JVM."); System.err.println("\n*Here is the stack trace:"); e.printStackTrace(); System.exit(-1); } resources = NEW_RESOURCES; } ErrorHandler nullHandler = new ErrorHandler() { public void warning(SAXParseException e) throws SAXException { } public void error(SAXParseException e) throws SAXException { System.err.println("The XLIFF document is invalid, please check it first: "); System.err.println("Line "+e.getLineNumber()+", Column "+e.getColumnNumber()); System.err.println("Error: " + e.getMessage()); System.exit(-1); } public void fatalError(SAXParseException e) throws SAXException { throw e; } }; try { DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); docBuilder.setErrorHandler(nullHandler); doc = docBuilder.parse(new InputSource(urls)); NodeList nlist = doc.getElementsByTagName(FILES); if(nlist.getLength()>1){ throw new RuntimeException("Multiple elements in the XLIFF file not supported."); } // get the value of source-language attribute String sourceLang = getLanguageName(doc, SOURCELANGUAGE); // get the value of target-language attribute String targetLang = getLanguageName(doc, TARGETLANGUAGE); // get the list of elements NodeList sourceList = doc.getElementsByTagName(SOURCE); // get the list of target elements NodeList targetList = doc.getElementsByTagName(TARGET); // check if the xliff file has source elements in multiple languages // the source-language value should be the same as xml:lang values // of all the source elements. String xmlSrcLang = checkLangAttribute(sourceList, sourceLang); // check if the xliff file has target elements in multiple languages // the target-language value should be the same as xml:lang values // of all the target elements. String xmlTargetLang = checkLangAttribute(targetList, targetLang); // Create the Resource linked list which will hold the // source and target bundles after parsing Resource[] set = new Resource[2]; set[0] = new ResourceTable(); set[1] = new ResourceTable(); // lenient extraction of source language if(makeSourceRoot == true){ set[0].name = ROOT; }else if(sourceLang!=null){ set[0].name = sourceLang.replace('-','_'); }else{ if(xmlSrcLang != null){ set[0].name = xmlSrcLang.replace('-','_'); }else{ System.err.println("ERROR: Could not figure out the source language of the file. Please check the XLIFF file."); System.exit(-1); } } // lenient extraction of the target language if(targetLang!=null){ set[1].name = targetLang.replace('-','_'); }else{ if(xmlTargetLang!=null){ set[1].name = xmlTargetLang.replace('-','_'); }else{ System.err.println("WARNING: Could not figure out the target language of the file. Producing source bundle only."); } } // check if any elements are present NodeList altTrans = doc.getElementsByTagName(ALTTRANS); if(altTrans.getLength()>0){ System.err.println("WARNING: elements in found. Ignoring all elements."); } // get all the group elements NodeList list = doc.getElementsByTagName(GROUPS); // process the first group element. The first group element is // the base table that must be parsed recursively parseTable(list.item(0), set); // write out the bundle writeResource(set, xmlfileName); } catch (Throwable se) { System.err.println("ERROR: " + se.toString()); System.exit(1); } } private void writeResource(Resource[] set, String xmlfileName){ if(targetOnly==false){ writeResource(set[0], xmlfileName, sourceFileName); } if(sourceOnly == false){ if(targetOnly==true && set[1].name == null){ throw new RuntimeException("The "+ xmlfileName +" does not contain translation\n"); } if(set[1].name != null){ writeResource(set[1], xmlfileName, targetFileName); } } } private void writeResource(Resource set, String sourceFilename, String targetFilename){ try { String outputFileName = null; if(targetFilename != null){ outputFileName = destDir+File.separator+targetFilename+".txt"; }else{ outputFileName = destDir+File.separator+set.name+".txt"; } FileOutputStream file = new FileOutputStream(outputFileName); BufferedOutputStream writer = new BufferedOutputStream(file); writeHeader(writer,sourceFilename); //Now start writing the resource; Resource current = set; while(current!=null){ current.write(writer, 0, false); current = current.next; } writer.flush(); writer.close(); } catch (Exception ie) { System.err.println("ERROR :" + ie.toString()); return; } } private String getLanguageName(Document doc, String lang){ if(doc!=null){ NodeList list = doc.getElementsByTagName(FILE); Node node = list.item(0); NamedNodeMap attr = node.getAttributes(); Node orig = attr.getNamedItem(lang); if(orig != null){ String name = orig.getNodeValue(); NodeList groupList = doc.getElementsByTagName(GROUPS); Node group = groupList.item(0); NamedNodeMap groupAtt = group.getAttributes(); Node id = groupAtt.getNamedItem(ID); if(id!=null){ String idVal = id.getNodeValue(); if(!name.equals(idVal)){ System.out.println("WARNING: The id value != language name. " + "Please compare the output with the orignal " + "ICU ResourceBundle before proceeding."); } } if(!isXmlLang(name)){ System.err.println("The attribute "+ lang + "=\""+ name + "\" of element is invalid."); System.exit(-1); } return name; } } return null; } // check if the xliff file is translated into multiple languages // The XLIFF specification allows for single element // as the child of but the attributes of the // element may different across elements // check for it. Similar is the case with elements private String checkLangAttribute(NodeList list, String origName){ String oldLangName=origName; for(int i = 0 ;i element without xml:lang attribute. Please fix the below element in the XLIFF file.\n"+ node.toString()); System.exit(-1); }else{ langName = origName; } }else{ langName = lang.getNodeValue(); } if(oldLangName!=null && langName!=null && !langName.equals(oldLangName)){ throw new RuntimeException("The elements must be bilingual, multilingual tranlations not supported. xml:lang = " + oldLangName + " and xml:lang = " + langName); } oldLangName = langName; } return oldLangName; } private class Resource{ String[] note = new String[20]; int noteLen = 0; String translate; String comment; String name; Resource next; public String escapeSyntaxChars(String val){ // escape the embedded quotes char[] str = val.toCharArray(); StringBuffer result = new StringBuffer(); for(int i=0; i 0){ // print the start of the comment writeIndent(writer, numIndent); write(writer, COMMENTSTART+LINESEP); // print comment if any if(comment!=null){ writeIndent(writer, numIndent); write(writer, COMMENTMIDDLE); write(writer, comment); write(writer, LINESEP); } // print the translate attribute if any if(! translateIsDefault){ writeIndent(writer, numIndent); write(writer, TAG+TRANSLATE+SPACE); write(writer, translate); write(writer, LINESEP); } // print note elements if any for(int i=0; i, and elements for(Node transUnit = node.getFirstChild(); transUnit!=null; transUnit = transUnit.getNextSibling()){ short type = transUnit.getNodeType(); String name = transUnit.getNodeName(); if(type == Node.COMMENT_NODE){ // get the comment currentSource.comment = currentTarget.comment = transUnit.getNodeValue(); }else if( type == Node.ELEMENT_NODE){ if(name.equals(SOURCE)){ // save the source and target values currentSource.name = currentTarget.name = resName; currentSource.val = currentTarget.val = transUnit.getFirstChild().getNodeValue(); currentSource.translate = currentTarget.translate = translate; }else if(name.equals(NOTE)){ // save the note values currentSource.note[currentSource.noteLen++] = currentTarget.note[currentTarget.noteLen++] = transUnit.getFirstChild().getNodeValue(); }else if(name.equals(TARGET)){ // if there is a target element replace it currentTarget.val = transUnit.getFirstChild().getNodeValue(); } } } } private void parseResourceInt(Node node, ResourceInt[] set){ ResourceInt currentSource; ResourceInt currentTarget; currentSource = set[0]; currentTarget = set[1]; String resName = getAttributeValue(node, RESNAME); String translate = getAttributeValue(node, TRANSLATE); // loop to pickup , and elements for(Node transUnit = node.getFirstChild(); transUnit!=null; transUnit = transUnit.getNextSibling()){ short type = transUnit.getNodeType(); String name = transUnit.getNodeName(); if(type == Node.COMMENT_NODE){ // get the comment currentSource.comment = currentTarget.comment = transUnit.getNodeValue(); }else if( type == Node.ELEMENT_NODE){ if(name.equals(SOURCE)){ // save the source and target values currentSource.name = currentTarget.name = resName; currentSource.translate = currentTarget.translate = translate; currentSource.val = currentTarget.val = transUnit.getFirstChild().getNodeValue(); }else if(name.equals(NOTE)){ // save the note values currentSource.note[currentSource.noteLen++] = currentTarget.note[currentTarget.noteLen++] = transUnit.getFirstChild().getNodeValue(); }else if(name.equals(TARGET)){ // if there is a target element replace it currentTarget.val = transUnit.getFirstChild().getNodeValue(); } } } } private void parseResourceAlias(Node node, ResourceAlias[] set){ ResourceAlias currentSource; ResourceAlias currentTarget; currentSource = set[0]; currentTarget = set[1]; String resName = getAttributeValue(node, RESNAME); String translate = getAttributeValue(node, TRANSLATE); // loop to pickup , and elements for(Node transUnit = node.getFirstChild(); transUnit!=null; transUnit = transUnit.getNextSibling()){ short type = transUnit.getNodeType(); String name = transUnit.getNodeName(); if(type == Node.COMMENT_NODE){ // get the comment currentSource.comment = currentTarget.comment = transUnit.getNodeValue(); }else if( type == Node.ELEMENT_NODE){ if(name.equals(SOURCE)){ // save the source and target values currentSource.name = currentTarget.name = resName; currentSource.translate = currentTarget.translate = translate; currentSource.val = currentTarget.val = transUnit.getFirstChild().getNodeValue(); }else if(name.equals(NOTE)){ // save the note values currentSource.note[currentSource.noteLen++] = currentTarget.note[currentTarget.noteLen++] = transUnit.getFirstChild().getNodeValue(); }else if(name.equals(TARGET)){ // if there is a target element replace it currentTarget.val = transUnit.getFirstChild().getNodeValue(); } } } } private void parseResourceBinary(Node node, ResourceBinary[] set){ ResourceBinary currentSource; ResourceBinary currentTarget; currentSource = set[0]; currentTarget = set[1]; // loop to pickup , and elements for(Node transUnit = node.getFirstChild(); transUnit!=null; transUnit = transUnit.getNextSibling()){ short type = transUnit.getNodeType(); String name = transUnit.getNodeName(); if(type == Node.COMMENT_NODE){ // get the comment currentSource.comment = currentTarget.comment = transUnit.getNodeValue(); }else if( type == Node.ELEMENT_NODE){ if(name.equals(BINSOURCE)){ // loop to pickup internal-file/extenal-file element continue; }else if(name.equals(NOTE)){ // save the note values currentSource.note[currentSource.noteLen++] = currentTarget.note[currentTarget.noteLen++] = transUnit.getFirstChild().getNodeValue(); }else if(name.equals(INTERNALFILE)){ // if there is a target element replace it String crc = getAttributeValue(transUnit, CRC); String value = transUnit.getFirstChild().getNodeValue(); //verify that the binary value conforms to the CRC if(Integer.parseInt(crc, 10) != CalculateCRC32.computeCRC32(value)) { System.err.println("ERROR: CRC value incorrect! Please check."); System.exit(1); } currentTarget.internal = currentSource.internal= value; }else if(name.equals(EXTERNALFILE)){ currentSource.external = getAttributeValue(transUnit, HREF); currentTarget.external = currentSource.external; } } } } private void parseTransUnit(Node node, Resource[] set){ String attrType = getAttributeValue(node, RESTYPE); String translate = getAttributeValue(node, TRANSLATE); if(attrType==null || attrType.equals(STRINGS)){ ResourceString[] strings = new ResourceString[2]; strings[0] = new ResourceString(); strings[1] = new ResourceString(); parseResourceString(node, strings); strings[0].translate = strings[1].translate = translate; set[0] = strings[0]; set[1] = strings[1]; }else if(attrType.equals(resources[INTEGER_RESOURCE])){ ResourceInt[] ints = new ResourceInt[2]; ints[0] = new ResourceInt(); ints[1] = new ResourceInt(); parseResourceInt(node, ints); ints[0].translate = ints[1].translate = translate; set[0] = ints[0]; set[1] = ints[1]; }else if(attrType.equals(resources[ALIAS_RESOURCE])){ ResourceAlias[] ints = new ResourceAlias[2]; ints[0] = new ResourceAlias(); ints[1] = new ResourceAlias(); parseResourceAlias(node, ints); ints[0].translate = ints[1].translate = translate; set[0] = ints[0]; set[1] = ints[1]; } } private void parseBinUnit(Node node, Resource[] set){ if (getAttributeValue(node, RESTYPE).equals(resources[BINARY_RESOURCE])) { ResourceBinary[] bins = new ResourceBinary[2]; bins[0] = new ResourceBinary(); bins[1] = new ResourceBinary(); Resource currentSource = bins[0]; Resource currentTarget = bins[1]; String resName = getAttributeValue(node, RESNAME); String translate = getAttributeValue(node, TRANSLATE); currentTarget.name = currentSource.name = resName; currentSource.translate = currentTarget.translate = translate; for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()){ short type = child.getNodeType(); String name = child.getNodeName(); if(type == Node.COMMENT_NODE){ currentSource.comment = currentTarget.comment = child.getNodeValue(); }else if(type == Node.ELEMENT_NODE){ if(name.equals(BINSOURCE)){ parseResourceBinary(child, bins); }else if(name.equals(NOTE)){ String note = child.getFirstChild().getNodeValue(); currentSource.note[currentSource.noteLen++] = currentTarget.note[currentTarget.noteLen++] = note; } } } set[0] = bins[0]; set[1] = bins[1]; } } private void parseArray(Node node, Resource[] set){ if(set[0]==null){ set[0] = new ResourceArray(); set[1] = new ResourceArray(); } Resource currentSource = set[0]; Resource currentTarget = set[1]; String resName = getAttributeValue(node, RESNAME); currentSource.name = currentTarget.name = resName; boolean isFirst = true; for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()){ short type = child.getNodeType(); String name = child.getNodeName(); if(type == Node.COMMENT_NODE){ currentSource.comment = currentTarget.comment = child.getNodeValue(); }else if(type == Node.ELEMENT_NODE){ if(name.equals(TRANSUNIT)){ Resource[] next = new Resource[2]; parseTransUnit(child, next); if(isFirst==true){ ((ResourceArray) currentSource).first = next[0]; ((ResourceArray) currentTarget).first = next[1]; currentSource = ((ResourceArray) currentSource).first; currentTarget = ((ResourceArray) currentTarget).first; isFirst = false; }else{ currentSource.next = next[0]; currentTarget.next = next[1]; // set the next pointers currentSource = currentSource.next; currentTarget = currentTarget.next; } }else if(name.equals(NOTE)){ String note = child.getFirstChild().getNodeValue(); currentSource.note[currentSource.noteLen++] = currentTarget.note[currentTarget.noteLen++] = note; }else if(name.equals(BINUNIT)){ Resource[] next = new Resource[2]; parseBinUnit(child, next); if(isFirst==true){ ((ResourceArray) currentSource).first = next[0]; ((ResourceArray) currentTarget).first = next[1]; currentSource = ((ResourceArray) currentSource).first.next; currentTarget = ((ResourceArray) currentTarget).first.next; isFirst = false; }else{ currentSource.next = next[0]; currentTarget.next = next[1]; // set the next pointers currentSource = currentSource.next; currentTarget = currentTarget.next; } } } } } private void parseIntVector(Node node, Resource[] set){ if(set[0]==null){ set[0] = new ResourceIntVector(); set[1] = new ResourceIntVector(); } Resource currentSource = set[0]; Resource currentTarget = set[1]; String resName = getAttributeValue(node, RESNAME); String translate = getAttributeValue(node,TRANSLATE); currentSource.name = currentTarget.name = resName; currentSource.translate = translate; boolean isFirst = true; for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()){ short type = child.getNodeType(); String name = child.getNodeName(); if(type == Node.COMMENT_NODE){ currentSource.comment = currentTarget.comment = child.getNodeValue(); }else if(type == Node.ELEMENT_NODE){ if(name.equals(TRANSUNIT)){ Resource[] next = new Resource[2]; parseTransUnit(child, next); if(isFirst==true){ // the down cast should be safe .. if not something is terribly wrong!! ((ResourceIntVector) currentSource).first = (ResourceInt)next[0]; ((ResourceIntVector) currentTarget).first = (ResourceInt) next[1]; currentSource = ((ResourceIntVector) currentSource).first; currentTarget = ((ResourceIntVector) currentTarget).first; isFirst = false; }else{ currentSource.next = next[0]; currentTarget.next = next[1]; // set the next pointers currentSource = currentSource.next; currentTarget = currentTarget.next; } }else if(name.equals(NOTE)){ String note = child.getFirstChild().getNodeValue(); currentSource.note[currentSource.noteLen++] = currentTarget.note[currentTarget.noteLen++] = note; } } } } private void parseTable(Node node, Resource[] set){ if(set[0]==null){ set[0] = new ResourceTable(); set[1] = new ResourceTable(); } Resource currentSource = set[0]; Resource currentTarget = set[1]; String resName = getAttributeValue(node, RESNAME); String translate = getAttributeValue(node,TRANSLATE); if(resName!=null && currentSource.name==null && currentTarget.name==null){ currentSource.name = currentTarget.name = resName; } currentTarget.translate = currentSource.translate = translate; boolean isFirst = true; for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()){ short type = child.getNodeType(); String name = child.getNodeName(); if(type == Node.COMMENT_NODE){ currentSource.comment = currentTarget.comment = child.getNodeValue(); }else if(type == Node.ELEMENT_NODE){ if(name.equals(GROUPS)){ Resource[] next = new Resource[2]; parseGroup(child, next); if(isFirst==true){ // the down cast should be safe .. if not something is terribly wrong!! ((ResourceTable) currentSource).first = next[0]; ((ResourceTable) currentTarget).first = next[1]; currentSource = ((ResourceTable) currentSource).first; currentTarget = ((ResourceTable) currentTarget).first; isFirst = false; }else{ currentSource.next = next[0]; currentTarget.next = next[1]; // set the next pointers currentSource = currentSource.next; currentTarget = currentTarget.next; } }else if(name.equals(TRANSUNIT)){ Resource[] next = new Resource[2]; parseTransUnit(child, next); if(isFirst==true){ // the down cast should be safe .. if not something is terribly wrong!! ((ResourceTable) currentSource).first = next[0]; ((ResourceTable) currentTarget).first = next[1]; currentSource = ((ResourceTable) currentSource).first; currentTarget = ((ResourceTable) currentTarget).first; isFirst = false; }else{ currentSource.next = next[0]; currentTarget.next = next[1]; // set the next pointers currentSource = currentSource.next; currentTarget = currentTarget.next; } }else if(name.equals(NOTE)){ String note = child.getFirstChild().getNodeValue(); currentSource.note[currentSource.noteLen++] = currentTarget.note[currentTarget.noteLen++] = note; }else if(name.equals(BINUNIT)){ Resource[] next = new Resource[2]; parseBinUnit(child, next); if(isFirst==true){ // the down cast should be safe .. if not something is terribly wrong!! ((ResourceTable) currentSource).first = next[0]; ((ResourceTable) currentTarget).first = next[1]; currentSource = ((ResourceTable) currentSource).first; currentTarget = ((ResourceTable) currentTarget).first; isFirst = false; }else{ currentSource.next = next[0]; currentTarget.next = next[1]; // set the next pointers currentSource = currentSource.next; currentTarget = currentTarget.next; } } } } } private void parseGroup(Node node, Resource[] set){ // figure out what kind of group this is String resType = getAttributeValue(node, RESTYPE); if(resType.equals(resources[ARRAY_RESOURCE])){ parseArray(node, set); }else if( resType.equals(resources[TABLE_RESOURCE])){ parseTable(node, set); }else if( resType.equals(resources[INTVECTOR_RESOURCE])){ parseIntVector(node, set); } } private void writeLine(OutputStream writer, String line) { try { byte[] bytes = line.getBytes(CHARSET); writer.write(bytes, 0, bytes.length); } catch (Exception e) { System.err.println(e); System.exit(1); } } private void writeHeader(OutputStream writer, String fileName){ final String header = "// ***************************************************************************" + LINESEP + "// *" + LINESEP + "// * Tool: com.ibm.icu.dev.tool.localeconverter.XLIFF2ICUConverter.java" + LINESEP + "// * Date & Time: {0,date,MM/dd/yyyy hh:mm:ss a z}"+ LINESEP + "// * Source File: {1}" + LINESEP + "// *" + LINESEP + "// ***************************************************************************" + LINESEP; writeBOM(writer); MessageFormat format = new MessageFormat(header); Object args[] = {new Date(System.currentTimeMillis()), fileName}; writeLine(writer, format.format(args)); } private void writeBOM(OutputStream buffer) { try { byte[] bytes = BOM.getBytes(CHARSET); buffer.write(bytes, 0, bytes.length); } catch(Exception e) { System.err.println(e); System.exit(1); } } }