/* ***************************************************************************** * Copyright (C) 2000-2004, International Business Machines Corporation and * * others. All Rights Reserved. * ***************************************************************************** */ package com.ibm.rbm; import java.io.*; import java.util.*; import java.text.*; import javax.swing.*; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.*; import javax.xml.transform.stream.*; import org.w3c.dom.*; /** * This class is a plug-in to RBManager that allows the user to export Resource Bundles * along with some of the meta-data associated by RBManager to the XLIFF specification. * For more information on XLIFF visit the web site * http://www.lisa.org/xliff/ * * @author George Rhoten * @see com.ibm.rbm.RBManager */ public class RBxliffExporter extends RBExporter { private static final String VERSION = "0.7"; private static final String XLIFF_DTD = "http://www.oasis-open.org/committees/xliff/documents/xliff.dtd"; private static final String XLIFF_PUBLIC_NAME = "-//XLIFF//DTD XLIFF//EN"; private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); /** * Default constructor for the XLIFF exporter. */ public RBxliffExporter() { super(); // Initialize the file chooser if necessary if (chooser == null) { chooser = new JFileChooser(); chooser.setFileFilter(new javax.swing.filechooser.FileFilter(){ public String getDescription() { return "XLIFF Files"; } public boolean accept(File f) { return (f.isDirectory() || f.getName().endsWith(".xlf")); } }); } } private String convertToISO(Date d) { GregorianCalendar gc = new GregorianCalendar(); gc.setTime(d); return convertToISO(gc); } private String convertToISO(GregorianCalendar gc) { dateFormat.setCalendar(gc); return dateFormat.format(gc.getTime()); } private String getLocale(Bundle item) { String language = item.getLanguageEncoding(); if (language != null && !language.equals("")) { //language = language.toUpperCase(); String country = item.getCountryEncoding(); if (country != null && !country.equals("")) { //country = country.toUpperCase(); String variant = item.getVariantEncoding(); if (variant != null && !variant.equals("")) { //variant = variant.toUpperCase(); return language + "-" + country + "-" + variant; } return language + "-" + country; } return language; } return ""; } private String getParentLocale(String locale) { int truncIndex = locale.lastIndexOf('-'); if (truncIndex > 0) { locale = locale.substring(0, truncIndex); } else { locale = ""; } return locale; } private void addTransUnit(Document xml, Element groupElem, BundleItem item, BundleItem parent_item) { Element transUnit = xml.createElement("trans-unit"); transUnit.setAttribute("date",convertToISO(item.getModifiedDate())); transUnit.setAttribute("id",item.getKey()); String sourceOrTarget = "target"; if (parent_item == null) { sourceOrTarget = "source"; } else { Element source = xml.createElement("source"); source.setAttribute("xml:space","preserve"); source.appendChild(xml.createTextNode(parent_item.getTranslation())); transUnit.appendChild(source); } Element target = xml.createElement(sourceOrTarget); target.setAttribute("xml:space","preserve"); // This is different from the translate attribute if (item.isTranslated()) { // TODO Handle the other states in the future. transUnit.setAttribute("state", "translated"); } target.appendChild(xml.createTextNode(item.getTranslation())); transUnit.appendChild(target); if (item.getComment() != null && item.getComment().length() > 1) { Element comment_prop = xml.createElement("note"); comment_prop.setAttribute("xml:space","preserve"); comment_prop.appendChild(xml.createTextNode(item.getComment())); transUnit.appendChild(comment_prop); } if ((item.getCreator() != null && item.getCreator().length() > 1) || (item.getModifier() != null && item.getModifier().length() > 1)) { Element transUnit_prop_group_elem = xml.createElement("prop-group"); if (item.getCreator() != null && item.getCreator().length() > 1) { Element creator_prop = xml.createElement("prop"); creator_prop.setAttribute("prop-type","creator"); creator_prop.appendChild(xml.createTextNode(item.getCreator())); transUnit_prop_group_elem.appendChild(creator_prop); } if (item.getCreator() != null && item.getCreator().length() > 1) { Element created_prop = xml.createElement("prop"); created_prop.setAttribute("prop-type","created"); created_prop.appendChild(xml.createTextNode(convertToISO(item.getCreatedDate()))); transUnit_prop_group_elem.appendChild(created_prop); } if (item.getModifier() != null && item.getModifier().length() > 1) { Element modifier_prop = xml.createElement("prop"); modifier_prop.setAttribute("prop-type","modifier"); modifier_prop.appendChild(xml.createTextNode(item.getModifier())); transUnit_prop_group_elem.appendChild(modifier_prop); } transUnit.appendChild(transUnit_prop_group_elem); } groupElem.appendChild(transUnit); } public void export(RBManager rbm) throws IOException { if (rbm == null) return; // Open the Save Dialog int ret_val = chooser.showSaveDialog(null); if (ret_val != JFileChooser.APPROVE_OPTION) return; // Retrieve basic file information File file = chooser.getSelectedFile(); // The file(s) we will be working with File directory = new File(file.getParent()); // The directory we will be writing to String base_name = file.getName(); // The base name of the files we will write if (base_name == null || base_name.equals("")) base_name = rbm.getBaseClass(); if (base_name.endsWith(".xlf")) base_name = base_name.substring(0,base_name.length()-4); String file_name = base_name + ".xlf"; Vector bundle_v = rbm.getBundles(); Enumeration bundleIter = bundle_v.elements(); while (bundleIter.hasMoreElements()) { exportFile(rbm, directory, base_name, (Bundle)bundleIter.nextElement()); } } private void addHeaderProperties(Document xml, Element header, Bundle main_bundle) { if (main_bundle.comment != null && main_bundle.comment.length() > 0) { Element note = xml.createElement("note"); header.appendChild(note); note.appendChild(xml.createTextNode(main_bundle.comment)); note.setAttribute("xml:space","preserve"); } if ((main_bundle.name != null && main_bundle.name.length() > 0) || (main_bundle.manager != null && main_bundle.manager.length() > 0) || (main_bundle.language != null && main_bundle.language.length() > 0) || (main_bundle.country != null && main_bundle.country.length() > 0) || (main_bundle.variant != null && main_bundle.variant.length() > 0)) { Element prop_group = xml.createElement("prop-group"); header.appendChild(prop_group); if (main_bundle.name != null && main_bundle.name.length() > 0) { Element prop = xml.createElement("prop"); header.appendChild(prop); prop.setAttribute("xml:space","preserve"); prop.setAttribute("prop-type","name"); prop.appendChild(xml.createTextNode(main_bundle.name)); prop_group.appendChild(prop); } if (main_bundle.manager != null && main_bundle.manager.length() > 0) { Element prop = xml.createElement("prop"); header.appendChild(prop); prop.setAttribute("xml:space","preserve"); prop.setAttribute("prop-type","manager"); prop.appendChild(xml.createTextNode(main_bundle.manager)); prop_group.appendChild(prop); } if (main_bundle.language != null && main_bundle.language.length() > 0) { Element prop = xml.createElement("prop"); header.appendChild(prop); prop.setAttribute("xml:space","preserve"); prop.setAttribute("prop-type","language"); prop.appendChild(xml.createTextNode(main_bundle.language)); prop_group.appendChild(prop); } if (main_bundle.country != null && main_bundle.country.length() > 0) { Element prop = xml.createElement("prop"); header.appendChild(prop); prop.setAttribute("xml:space","preserve"); prop.setAttribute("prop-type","country"); prop.appendChild(xml.createTextNode(main_bundle.country)); prop_group.appendChild(prop); } if (main_bundle.variant != null && main_bundle.variant.length() > 0) { Element prop = xml.createElement("prop"); header.appendChild(prop); prop.setAttribute("xml:space","preserve"); prop.setAttribute("prop-type","variant"); prop.appendChild(xml.createTextNode(main_bundle.variant)); prop_group.appendChild(prop); } } } private void exportFile(RBManager rbm, File directory, String base_name, Bundle main_bundle) throws IOException { Bundle parent_bundle = null; String parent_bundle_name = null; if (!getLocale(main_bundle).equals("")) { // If this isn't the root locale, find the parent parent_bundle_name = getParentLocale(getLocale(main_bundle)); do { parent_bundle = rbm.getBundle(parent_bundle_name); if (parent_bundle != null) { break; } parent_bundle_name = getParentLocale(parent_bundle_name); } while (!parent_bundle_name.equals("")); } // Find the implementation DocumentBuilder builder; try { builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); } catch (ParserConfigurationException pce) { throw new IOException(pce.getMessage()); } // Create the document Document xml = builder.getDOMImplementation().createDocument(null, "xliff", null); // Fill the document Element root = xml.getDocumentElement(); root.setAttribute("version", "1.1"); //root.appendChild(root); Element file_elem = xml.createElement("file"); String mainLocale = getLocale(main_bundle); Bundle parentBundle = null; if (mainLocale.equals("")) { file_elem.setAttribute("source-language", getLocale(main_bundle)); } else { file_elem.setAttribute("source-language", parent_bundle_name); file_elem.setAttribute("target-language", getLocale(main_bundle)); } file_elem.setAttribute("datatype", "plaintext"); file_elem.setAttribute("date", convertToISO(new Date())); root.appendChild(file_elem); Element header = xml.createElement("header"); Element tool = xml.createElement("tool"); tool.setAttribute("tool-name", "RBManager"); tool.setAttribute("tool-id", "RBManager"); tool.setAttribute("tool-version", VERSION); // TODO Add file attribute //header.setAttribute("file", ""); header.appendChild(tool); addHeaderProperties(xml, header, main_bundle); file_elem.appendChild(header); Element body = xml.createElement("body"); file_elem.appendChild(body); Vector group_v = main_bundle.getGroupsAsVector(); Vector parent_group_v = null; if (parent_bundle != null) { parent_group_v = parent_bundle.getGroupsAsVector(); } // Loop through each bundle group in main_bundle for (int i=0; i < group_v.size(); i++) { BundleGroup curr_group = (BundleGroup)group_v.elementAt(i); BundleGroup parent_group = null; if (parent_group_v != null) { Enumeration parentGroupIter = parent_group_v.elements(); while (parentGroupIter.hasMoreElements()) { BundleGroup groupToFind = (BundleGroup)parentGroupIter.nextElement(); if (groupToFind.getName().equals(curr_group.getName())) { parent_group = groupToFind; break; } } } Element group_elem = xml.createElement("group"); group_elem.setAttribute("id", curr_group.getName()); if (curr_group.getComment() != null && curr_group.getComment().length() > 1) { Element comment_prop = xml.createElement("note"); comment_prop.setAttribute("xml:space","preserve"); comment_prop.appendChild(xml.createTextNode(curr_group.getComment())); group_elem.appendChild(comment_prop); } Vector group_items = curr_group.getItemsAsVector(); for (int j=0; j < group_items.size(); j++) { BundleItem main_item = (BundleItem)group_items.get(j); BundleItem parent_item = null; if (parent_group != null) { Enumeration parentIter = parent_group.getItemsAsVector().elements(); BundleItem itemToFind = null; while (parentIter.hasMoreElements()) { itemToFind = (BundleItem)parentIter.nextElement(); if (itemToFind.getKey().equals(main_item.getKey())) { parent_item = itemToFind; break; } } } addTransUnit(xml, group_elem, main_item, parent_item); //group_elem.appendChild(tu); } body.appendChild(group_elem); } // end for - i String suffix = mainLocale; if (!suffix.equals("")) { suffix = '_' + suffix; } char array[] = suffix.toCharArray(); for (int k=0; k < array.length; k++) { if (array[k] == '-') array[k] = '_'; } suffix = String.valueOf(array); // serialize document OutputStreamWriter osw = new OutputStreamWriter( new FileOutputStream(new File(directory, base_name + suffix + ".xlf")), "UTF-8"); try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, XLIFF_DTD); transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, XLIFF_PUBLIC_NAME); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.transform(new DOMSource(xml), new StreamResult(osw)); } catch (TransformerException te) { throw new IOException(te.getMessage()); } osw.close(); } }