blob: 3d98a641297edf8b944caf53ebd097a9576e3d63 [file] [log] [blame]
/*
******************************************************************************
* Copyright (C) 2003, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/dev/tool/localeconverter/XLIFF2ICUConverter.java,v $
* $Date: 2003/05/19
* $Revision: 1.3 $
*
******************************************************************************
*/
package com.ibm.icu.dev.tool.localeconverter;
import com.ibm.icu.dev.tool.UOption;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NamedNodeMap;
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 javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.util.*;
public class XLIFF2ICUConverter {
protected String sourceDir = null;
protected String fileName = null;
protected String packageName = null;
protected String destDir = null;
protected String xmlfileName = null;
protected Document doc;
/**
* 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 PACKAGE_NAME = 4;
private static final int FILENAME = 5;
private static final UOption[] options = new UOption[] {
UOption.HELP_H(),
UOption.HELP_QUESTION_MARK(),
UOption.SOURCEDIR(),
UOption.DESTDIR(),
UOption.PACKAGE_NAME(),
};
private static int tabCount = 0;
private static ArrayList[] buf;
private static ArrayList bundleLang;
private static ArrayList bundleName;
private static ArrayList bundleList;
private static int bundleLen = 0;
private static final String RESTYPE = "restype";
private static final String RESNAME = "resname";
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 TS = "ts";
private static final String ORIGINAL = "original";
private static final String SOURCELANGUAGE = "source-language";
private static final String TARGET = "target";
private static final String SOURCE = "source";
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 HREF = "href";
private static final String EXTERNALFILE = "external-file";
private static final String CRC = "crc";
private static final String LINESEP = System.getProperty("line.separator");
private static final String BOM = "\uFEFF";
public static void main(String[] args) {
XLIFF2ICUConverter cnv = new XLIFF2ICUConverter();
cnv.processArgs(args);
}
private void processArgs(String[] args) {
int remainingArgc = UOption.parseArgs(args, options);
if(args.length==0 || options[HELP1].doesOccur || options[HELP2].doesOccur) {
usage();
}
if(options[SOURCEDIR].doesOccur) {
sourceDir = options[SOURCEDIR].value;
}
if(options[DESTDIR].doesOccur) {
destDir = options[DESTDIR].value;
}
if(options[PACKAGE_NAME].doesOccur) {
packageName = options[PACKAGE_NAME].value;
}
for (int i = 0; i < remainingArgc; i++) {
tabCount = 0;
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());
convert(args[i]);
}
}
private void convert(String fileName) {
xmlfileName = getFullPath(false,fileName);
bundleName = new ArrayList();
bundleLang = new ArrayList();
bundleList = new ArrayList();
createRB(xmlfileName);
bundleLen = bundleList.size();
if(bundleLen == 0) {
boolean b;
b = bundleList.add(getFullPath(true, fileName));
if(b==false){
throw new RuntimeException("Could add "+fileName + "to bundleList");
}
int lastIndex = fileName.lastIndexOf('.', fileName.length());
b = bundleName.add(fileName.substring(0, lastIndex));
if(b==false){
throw new RuntimeException("Could add "+fileName.substring(0, lastIndex) + "to bundleList");
}
bundleLen++;
}
buf = new ArrayList[bundleLen];
for(int s = 0; s < bundleLen; s++) {
buf[s] = new ArrayList();
}
doc = parse(xmlfileName);
wirteAll();
}
private void usage() {
System.out.println("\nUsage: XLIFF2ICUConverter [OPTIONS] [FILES]\n\n"+
"This program is used to convert XML files to TXT files.\n"+
"Please refer to the following options. Options are not \n"+
"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" +
"-p or --package-name user may specify the package name explicitly.\n" +
"-h or -? or --help this usage text.\n"+
"example: XLIFF2ICUConverter -s xxx -d yyy myResources.xml");
}
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 (destDir != null && fName != null) {
str = destDir + File.separator + fName.substring(lastIndex1, lastIndex2) + ".txt";
} else {
str = System.getProperty("user.dir") + File.separator + fName.substring(lastIndex1, lastIndex2) + ".txt";
}
} else {
if(sourceDir != null && fName != null) {
str = sourceDir + File.separator + fName.substring(lastIndex1, lastIndex2) + ".xlf";
} else if (lastIndex1 > 0) {
str = fName;
} else {
str = System.getProperty("user.dir") + File.separator + fName.substring(lastIndex1, lastIndex2) + ".xlf";
}
}
return str;
}
private static String crc = "";
private static int transID = -1;
private static boolean isIntvector = false;
private void writeRB(Node doc) {
String resType = "string";
String resName = "";
String resValue = "";
switch(doc.getNodeType()){
case Node.ATTRIBUTE_NODE: {
break;
}
case Node.CDATA_SECTION_NODE: {
break;
}
case Node.COMMENT_NODE: {
}
case Node.DOCUMENT_FRAGMENT_NODE: {
break;
}
case Node.DOCUMENT_NODE: {
Node child = doc.getFirstChild();
while( child != null) {
writeRB(child);
child = child.getNextSibling();
}
break;
}
case Node.DOCUMENT_TYPE_NODE: {
break;
}
case Node.ELEMENT_NODE: {
crc = "";
NamedNodeMap attributes = doc.getAttributes();
int attrCount = attributes.getLength();
for (int i = 0; i < attrCount; i++) {
Node attribute = attributes.item(i);
if (attribute.getNodeName().equals(RESTYPE)) {
resType = attribute.getNodeValue();
if (resType.equals(INTVECTOR)) {
isIntvector = true;
}
} else if (attribute.getNodeName().equals(RESNAME)) {
resName = attribute.getNodeValue();
} else if (attribute.getNodeName().equals(HREF)) {
resValue = attribute.getNodeValue();
} else if (attribute.getNodeName().equals(CRC)) {
crc = attribute.getNodeValue();
}
}
if(doc.getNodeName().equals(GROUPS) && doc.getParentNode().getNodeName().equals(BODY)) {
transID = -1;
for(int s = 0; s < bundleLen; s++){
Calendar c = Calendar.getInstance();
buf[s].add("// ***************************************************************************" + LINESEP);
buf[s].add("// *" + LINESEP);
buf[s].add("// * Tool: com.ibm.icu.dev.tool.localeconverter.XLIFF2ICUConverter.java" + LINESEP);
buf[s].add("// * Date & Time: " + c.get(Calendar.YEAR) + "/" + (c.get(Calendar.MONTH)+1) + "/" + c.get(Calendar.DAY_OF_MONTH) + " " + c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE)+ LINESEP);
buf[s].add("// * Source File: " + fileName + LINESEP);
buf[s].add("// *" + LINESEP);
buf[s].add("// ***************************************************************************" + LINESEP);
buf[s].add(LINESEP);
buf[s].add(LINESEP);
buf[s].add((String)bundleName.get(s) + "{" + LINESEP);
}
} else if (doc.getNodeName().equals(GROUPS)){
transID = -1;
if (!isIntvector) {
writeTabs();
tabCount++;
for(int s = 0; s < bundleLen; s++){
buf[s].add(resName + ":" + resType + "{" + LINESEP);
}
} else {
writeTabs();
tabCount++;
for(int s = 0; s < bundleLen; s++){
buf[s].add(resName + ":" + INTVECTOR + "{" + LINESEP);
}
}
} else if (doc.getNodeName().equals(TRANSUNIT)||doc.getNodeName().equals(BINUNIT)){
writeTabs();
if (resType.equals(STRINGS)) {
transID = 0;
} else{
transID = -1;
}
if (resType.equals(STRINGS)||resType.equals(BIN)) {
for(int s = 0; s < bundleLen; s++){
buf[s].add(resName + ":" + resType + "{\"");
}
} else if (resType.equals(INTS) && isIntvector){
} else {
for(int s = 0; s < bundleLen; s++){
buf[s].add(resName + ":" + resType + "{");
}
}
} else if (doc.getNodeName().equals(EXTERNALFILE)) {
for(int s = 0; s < bundleLen; s++){
buf[s].add("\"" + resValue + "\"");
}
}
Node child = doc.getFirstChild();
if (child != null) {
while( child != null) {
writeRB(child);
child = child.getNextSibling();
}
}
if(doc.getNodeName().equals(GROUPS)) {
tabCount--;
writeTabs();
for(int s = 0; s < bundleLen; s++){
buf[s].add("}" + LINESEP);
}
isIntvector = false;
}else if (doc.getNodeName().equals(TRANSUNIT)||doc.getNodeName().equals(BINUNIT)){
if (resType.equals(STRINGS)||resType.equals(BIN)) {
for(int s = 0; s < bundleLen; s++){
buf[s].add("\"}" + LINESEP);
}
} else if (resType.equals(INTS)&&isIntvector){
for(int s = 0; s < bundleLen; s++){
buf[s].add("," + LINESEP);
}
} else {
for(int s = 0; s < bundleLen; s++){
buf[s].add("}" + LINESEP);
}
}
}
break;
}
case Node.ENTITY_NODE: {
break;
}
case Node.ENTITY_REFERENCE_NODE: {
break;
}
case Node.NOTATION_NODE: {
break;
}
case Node.PROCESSING_INSTRUCTION_NODE: {
break;
}
case Node.TEXT_NODE: {
try {
int index = doc.getNodeValue().indexOf("\"");
if(index != -1) {
resValue = doc.getNodeValue().replaceAll("\"", "\\\\\"");
} else {
resValue = doc.getNodeValue();
}
} catch (Exception e) {
e.printStackTrace();
}
if (transID == -1) {
if (!crc.equals("")){
if ((int)(resValue.charAt(0))!= 10){
if(Integer.parseInt(crc, 10) != CalculateCRC32.computeCRC32(resValue)) {
System.out.println("crc error! Please check.");
System.exit(1);
} else {
crc = "";
}
}
}
for(int s = 0; s < bundleLen; s++){
if ((int)(resValue.charAt(0))!= 10){
buf[s].add(resValue);
}
}
} else {
if ((int)(resValue.charAt(0))!= 10){
buf[transID].add(resValue);
transID++;
}
}
break;
}
default:
System.err.println("Unrecongized node type");
}
}
/**
* 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.
*
* @param String local path\filename of a file
* @return a file:/// URL, the same string if it appears to
* already be a URL, or null if error
*/
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 void createRB(String docsrc) {
boolean tag = false;
String urls = filenameToURL(docsrc);
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
dfactory.setNamespaceAware(true);
ErrorHandler nullHandler = new ErrorHandler() {
public void warning(SAXParseException e) throws SAXException {/*System.err.println("Warning: " + e.getMessage());*/}
public void error(SAXParseException e) throws SAXException {System.err.println("Error: " + e.getMessage());}
public void fatalError(SAXParseException e) throws SAXException {
throw e;
}
};
try {
DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
docBuilder.setErrorHandler(nullHandler);
doc = docBuilder.parse(new InputSource(urls));
String pkg = "";
String f = "";
String lg = "";
NodeList nlist1 = doc.getElementsByTagName(FILES);
for (int i = 0; i < nlist1.getLength(); i++) {
Node n = nlist1.item(i);
NamedNodeMap attributes = n.getAttributes();
int attrCount = attributes.getLength();
for (int k = 0; k < attrCount; k++) {
Node attribute = attributes.item(k);
if (attribute.getNodeName().equals(TS)) {
pkg = attribute.getNodeValue();
}
if (attribute.getNodeName().equals(ORIGINAL)) {
f = attribute.getNodeValue();
}
if (attribute.getNodeName().equals(SOURCELANGUAGE)) {
lg = attribute.getNodeValue();
}
}
}
if(packageName != null) {
pkg = packageName;
}
if(pkg.equals("")) {
NodeList nlist = doc.getElementsByTagName(TARGET);
if(nlist.getLength()> 0) {
System.out.println("There are translation items in the file. Please specify the package name using \"-p packageName\" in the command line.");
System.exit(0);
}
boolean b;
b = bundleLang.add(lg);
if(b==false){
throw new RuntimeException("Could not add "+lg+" to bundleLang");
}
int lastIndex = f.lastIndexOf('.', f.length());
b = bundleName.add(f.substring(0, lastIndex));
if(b==false){
throw new RuntimeException("Could not add "+f.substring(0, lastIndex)+" to bundleName");
}
b = bundleList.add(getFullPath(true,f));
if(b==false){
throw new RuntimeException("Could not add "+getFullPath(true,f)+" to bundleList");
}
} else {
NodeList nlist = doc.getElementsByTagName(TRANSUNIT);
for(int i = 0; i < nlist.getLength(); i++) {
String resType = "string";
Node n = nlist.item(i);
NamedNodeMap attributes = n.getAttributes();
int attrCount = attributes.getLength();
for (int k = 0; k < attrCount; k++) {
Node attribute = attributes.item(k);
if (attribute.getNodeName().equals(RESTYPE)) {
resType = attribute.getNodeValue();
}
}
if (resType.equals(STRINGS)) {
NodeList nlist2 = n.getChildNodes();
for(int j = 0; j < nlist2.getLength(); j++) {
Node n2 = nlist2.item(j);
if(n2.getNodeName().equals(TARGET)||n2.getNodeName().equals(SOURCE)) {
NamedNodeMap att = n2.getAttributes();
String lang = att.item(0).getNodeValue();
String name = pkg + "_" + lang;
boolean b;
b = bundleLang.add(lang);
if(b==false){
throw new RuntimeException("Could not add "+lang+" to bundleLang");
}
b = bundleName.add(name);
if(b==false){
throw new RuntimeException("Could not add "+name+" to bundleName");
}
b = bundleList.add(getFullPath(true, name + ".txt"));
if(b==false){
throw new RuntimeException("Could not add "+getFullPath(true, name + ".txt")+" to bundleList");
}
tag = true;
}
}
}
if(tag){
break;
}
}
}
}
catch (Throwable se) {
System.out.println("ERROR :" + se.toString());
}
}
private Document parse(String docsrc) {
String urls = filenameToURL(docsrc);
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
dfactory.setNamespaceAware(true);
ErrorHandler nullHandler = new ErrorHandler() {
public void warning(SAXParseException e) throws SAXException {/*System.err.println("Warning: " + e.getMessage());*/}
public void error(SAXParseException e) throws SAXException {System.err.println("Error: " + e.getMessage());}
public void fatalError(SAXParseException e) throws SAXException {
throw e;
}
};
try {
DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
docBuilder.setErrorHandler(nullHandler);
doc = docBuilder.parse(new InputSource(urls));
writeRB(doc);
}
catch (Throwable se) {
System.out.println("ERROR :" + se.toString());
}
return doc;
}
private static void writeTabs(){
int i=0;
for(;i<=tabCount;i++){
for(int s = 0; s < bundleLen; s++){
buf[s].add(" ");
}
}
}
private static void wirteAll() {
FileOutputStream file = null;
BufferedOutputStream buffer = null;
for(int s = 0; s < bundleLen; s++){
try {
file = new FileOutputStream((String)bundleList.get(s));
buffer = new BufferedOutputStream(file);
} catch (Exception ie) {
System.out.println("ERROR :" + ie.toString());
return;
}
writeBOM(buffer, "UTF-8");
for(int t = 0; t < buf[s].size(); t++){
WriteLine(buffer, (String)(buf[s].get(t)), "UTF-8");
}
try {
buffer.flush();
buffer.close();
file.close();
} catch (IOException ie) {
System.err.println(ie);
return;
}
}
}
private static void WriteLine(BufferedOutputStream buffer, String line, String charSet) {
try {
byte[] bytes = line.getBytes(charSet);
buffer.write(bytes, 0, bytes.length);
} catch (Exception e) {
System.err.println(e);
System.exit(1);
}
}
private static void writeBOM(BufferedOutputStream buffer, String charSet) {
try {
byte[] bytes = BOM.getBytes(charSet);
buffer.write(bytes, 0, bytes.length);
} catch(Exception e) {
System.err.println(e);
System.exit(1);
}
}
}