001: /*
002: *****************************************************************************
003: * Copyright (C) 2000-2004, International Business Machines Corporation and *
004: * others. All Rights Reserved. *
005: *****************************************************************************
006: */
007: package com.ibm.rbm;
008:
009: import java.io.*;
010: import java.util.*;
011: import java.text.*;
012:
013: import javax.swing.*;
014: import javax.xml.parsers.*;
015: import javax.xml.transform.*;
016: import javax.xml.transform.dom.*;
017: import javax.xml.transform.stream.*;
018:
019: import org.w3c.dom.*;
020:
021: /**
022: * This class is a plug-in to RBManager that allows the user to export Resource Bundles
023: * along with some of the meta-data associated by RBManager to the XLIFF specification.
024: * For more information on XLIFF visit the web site
025: * <a href="http://www.lisa.org/xliff/">http://www.lisa.org/xliff/</a>
026: *
027: * @author George Rhoten
028: * @see com.ibm.rbm.RBManager
029: */
030: public class RBxliffExporter extends RBExporter {
031: private static final String VERSION = "0.7";
032: private static final String XLIFF_DTD = "http://www.oasis-open.org/committees/xliff/documents/xliff.dtd";
033: private static final String XLIFF_PUBLIC_NAME = "-//XLIFF//DTD XLIFF//EN";
034: private SimpleDateFormat dateFormat = new SimpleDateFormat(
035: "yyyy-MM-dd");
036:
037: /**
038: * Default constructor for the XLIFF exporter.
039: */
040:
041: public RBxliffExporter() {
042: super ();
043:
044: // Initialize the file chooser if necessary
045: if (chooser == null) {
046: chooser = new JFileChooser();
047: chooser
048: .setFileFilter(new javax.swing.filechooser.FileFilter() {
049: public String getDescription() {
050: return "XLIFF Files";
051: }
052:
053: public boolean accept(File f) {
054: return (f.isDirectory() || f.getName()
055: .endsWith(".xlf"));
056: }
057: });
058: }
059: }
060:
061: private String convertToISO(Date d) {
062: GregorianCalendar gc = new GregorianCalendar();
063: gc.setTime(d);
064: return convertToISO(gc);
065: }
066:
067: private String convertToISO(GregorianCalendar gc) {
068: dateFormat.setCalendar(gc);
069: return dateFormat.format(gc.getTime());
070: }
071:
072: private String getLocale(Bundle item) {
073: String language = item.getLanguageEncoding();
074: if (language != null && !language.equals("")) {
075: //language = language.toUpperCase();
076: String country = item.getCountryEncoding();
077: if (country != null && !country.equals("")) {
078: //country = country.toUpperCase();
079: String variant = item.getVariantEncoding();
080: if (variant != null && !variant.equals("")) {
081: //variant = variant.toUpperCase();
082: return language + "-" + country + "-" + variant;
083: }
084: return language + "-" + country;
085: }
086: return language;
087: }
088: return "";
089: }
090:
091: private String getParentLocale(String locale) {
092:
093: int truncIndex = locale.lastIndexOf('-');
094: if (truncIndex > 0) {
095: locale = locale.substring(0, truncIndex);
096: } else {
097: locale = "";
098: }
099: return locale;
100: }
101:
102: private void addTransUnit(Document xml, Element groupElem,
103: BundleItem item, BundleItem parent_item) {
104: Element transUnit = xml.createElement("trans-unit");
105: transUnit.setAttribute("date", convertToISO(item
106: .getModifiedDate()));
107: transUnit.setAttribute("id", item.getKey());
108:
109: String sourceOrTarget = "target";
110: if (parent_item == null) {
111: sourceOrTarget = "source";
112: } else {
113: Element source = xml.createElement("source");
114: source.setAttribute("xml:space", "preserve");
115: source.appendChild(xml.createTextNode(parent_item
116: .getTranslation()));
117: transUnit.appendChild(source);
118: }
119: Element target = xml.createElement(sourceOrTarget);
120: target.setAttribute("xml:space", "preserve");
121: // This is different from the translate attribute
122: if (item.isTranslated()) {
123: // TODO Handle the other states in the future.
124: transUnit.setAttribute("state", "translated");
125: }
126: target.appendChild(xml.createTextNode(item.getTranslation()));
127: transUnit.appendChild(target);
128:
129: if (item.getComment() != null && item.getComment().length() > 1) {
130: Element comment_prop = xml.createElement("note");
131: comment_prop.setAttribute("xml:space", "preserve");
132: comment_prop.appendChild(xml.createTextNode(item
133: .getComment()));
134: transUnit.appendChild(comment_prop);
135: }
136:
137: if ((item.getCreator() != null && item.getCreator().length() > 1)
138: || (item.getModifier() != null && item.getModifier()
139: .length() > 1)) {
140: Element transUnit_prop_group_elem = xml
141: .createElement("prop-group");
142:
143: if (item.getCreator() != null
144: && item.getCreator().length() > 1) {
145: Element creator_prop = xml.createElement("prop");
146: creator_prop.setAttribute("prop-type", "creator");
147: creator_prop.appendChild(xml.createTextNode(item
148: .getCreator()));
149: transUnit_prop_group_elem.appendChild(creator_prop);
150: }
151:
152: if (item.getCreator() != null
153: && item.getCreator().length() > 1) {
154: Element created_prop = xml.createElement("prop");
155: created_prop.setAttribute("prop-type", "created");
156: created_prop.appendChild(xml
157: .createTextNode(convertToISO(item
158: .getCreatedDate())));
159: transUnit_prop_group_elem.appendChild(created_prop);
160: }
161:
162: if (item.getModifier() != null
163: && item.getModifier().length() > 1) {
164: Element modifier_prop = xml.createElement("prop");
165: modifier_prop.setAttribute("prop-type", "modifier");
166: modifier_prop.appendChild(xml.createTextNode(item
167: .getModifier()));
168: transUnit_prop_group_elem.appendChild(modifier_prop);
169: }
170:
171: transUnit.appendChild(transUnit_prop_group_elem);
172: }
173:
174: groupElem.appendChild(transUnit);
175: }
176:
177: public void export(RBManager rbm) throws IOException {
178: if (rbm == null)
179: return;
180: // Open the Save Dialog
181: int ret_val = chooser.showSaveDialog(null);
182: if (ret_val != JFileChooser.APPROVE_OPTION)
183: return;
184: // Retrieve basic file information
185: File file = chooser.getSelectedFile(); // The file(s) we will be working with
186: File directory = new File(file.getParent()); // The directory we will be writing to
187: String base_name = file.getName(); // The base name of the files we will write
188: if (base_name == null || base_name.equals(""))
189: base_name = rbm.getBaseClass();
190: if (base_name.endsWith(".xlf"))
191: base_name = base_name.substring(0, base_name.length() - 4);
192:
193: String file_name = base_name + ".xlf";
194:
195: Vector bundle_v = rbm.getBundles();
196: Enumeration bundleIter = bundle_v.elements();
197: while (bundleIter.hasMoreElements()) {
198: exportFile(rbm, directory, base_name, (Bundle) bundleIter
199: .nextElement());
200: }
201: }
202:
203: private void addHeaderProperties(Document xml, Element header,
204: Bundle main_bundle) {
205: if (main_bundle.comment != null
206: && main_bundle.comment.length() > 0) {
207: Element note = xml.createElement("note");
208: header.appendChild(note);
209: note.appendChild(xml.createTextNode(main_bundle.comment));
210: note.setAttribute("xml:space", "preserve");
211: }
212: if ((main_bundle.name != null && main_bundle.name.length() > 0)
213: || (main_bundle.manager != null && main_bundle.manager
214: .length() > 0)
215: || (main_bundle.language != null && main_bundle.language
216: .length() > 0)
217: || (main_bundle.country != null && main_bundle.country
218: .length() > 0)
219: || (main_bundle.variant != null && main_bundle.variant
220: .length() > 0)) {
221: Element prop_group = xml.createElement("prop-group");
222: header.appendChild(prop_group);
223: if (main_bundle.name != null
224: && main_bundle.name.length() > 0) {
225: Element prop = xml.createElement("prop");
226: header.appendChild(prop);
227: prop.setAttribute("xml:space", "preserve");
228: prop.setAttribute("prop-type", "name");
229: prop.appendChild(xml.createTextNode(main_bundle.name));
230: prop_group.appendChild(prop);
231: }
232: if (main_bundle.manager != null
233: && main_bundle.manager.length() > 0) {
234: Element prop = xml.createElement("prop");
235: header.appendChild(prop);
236: prop.setAttribute("xml:space", "preserve");
237: prop.setAttribute("prop-type", "manager");
238: prop.appendChild(xml
239: .createTextNode(main_bundle.manager));
240: prop_group.appendChild(prop);
241: }
242: if (main_bundle.language != null
243: && main_bundle.language.length() > 0) {
244: Element prop = xml.createElement("prop");
245: header.appendChild(prop);
246: prop.setAttribute("xml:space", "preserve");
247: prop.setAttribute("prop-type", "language");
248: prop.appendChild(xml
249: .createTextNode(main_bundle.language));
250: prop_group.appendChild(prop);
251: }
252: if (main_bundle.country != null
253: && main_bundle.country.length() > 0) {
254: Element prop = xml.createElement("prop");
255: header.appendChild(prop);
256: prop.setAttribute("xml:space", "preserve");
257: prop.setAttribute("prop-type", "country");
258: prop.appendChild(xml
259: .createTextNode(main_bundle.country));
260: prop_group.appendChild(prop);
261: }
262: if (main_bundle.variant != null
263: && main_bundle.variant.length() > 0) {
264: Element prop = xml.createElement("prop");
265: header.appendChild(prop);
266: prop.setAttribute("xml:space", "preserve");
267: prop.setAttribute("prop-type", "variant");
268: prop.appendChild(xml
269: .createTextNode(main_bundle.variant));
270: prop_group.appendChild(prop);
271: }
272: }
273: }
274:
275: private void exportFile(RBManager rbm, File directory,
276: String base_name, Bundle main_bundle) throws IOException {
277: Bundle parent_bundle = null;
278: String parent_bundle_name = null;
279: if (!getLocale(main_bundle).equals("")) {
280: // If this isn't the root locale, find the parent
281: parent_bundle_name = getParentLocale(getLocale(main_bundle));
282: do {
283: parent_bundle = rbm.getBundle(parent_bundle_name);
284: if (parent_bundle != null) {
285: break;
286: }
287: parent_bundle_name = getParentLocale(parent_bundle_name);
288: } while (!parent_bundle_name.equals(""));
289: }
290:
291: // Find the implementation
292: DocumentBuilder builder;
293: try {
294: builder = DocumentBuilderFactory.newInstance()
295: .newDocumentBuilder();
296: } catch (ParserConfigurationException pce) {
297: throw new IOException(pce.getMessage());
298: }
299:
300: // Create the document
301: Document xml = builder.getDOMImplementation().createDocument(
302: null, "xliff", null);
303:
304: // Fill the document
305: Element root = xml.getDocumentElement();
306: root.setAttribute("version", "1.1");
307: //root.appendChild(root);
308:
309: Element file_elem = xml.createElement("file");
310: String mainLocale = getLocale(main_bundle);
311: Bundle parentBundle = null;
312: if (mainLocale.equals("")) {
313: file_elem.setAttribute("source-language",
314: getLocale(main_bundle));
315: } else {
316: file_elem.setAttribute("source-language",
317: parent_bundle_name);
318: file_elem.setAttribute("target-language",
319: getLocale(main_bundle));
320: }
321: file_elem.setAttribute("datatype", "plaintext");
322: file_elem.setAttribute("date", convertToISO(new Date()));
323: root.appendChild(file_elem);
324:
325: Element header = xml.createElement("header");
326: Element tool = xml.createElement("tool");
327: tool.setAttribute("tool-name", "RBManager");
328: tool.setAttribute("tool-id", "RBManager");
329: tool.setAttribute("tool-version", VERSION);
330: // TODO Add file attribute
331: //header.setAttribute("file", "");
332: header.appendChild(tool);
333: addHeaderProperties(xml, header, main_bundle);
334: file_elem.appendChild(header);
335:
336: Element body = xml.createElement("body");
337: file_elem.appendChild(body);
338:
339: Vector group_v = main_bundle.getGroupsAsVector();
340: Vector parent_group_v = null;
341: if (parent_bundle != null) {
342: parent_group_v = parent_bundle.getGroupsAsVector();
343: }
344: // Loop through each bundle group in main_bundle
345: for (int i = 0; i < group_v.size(); i++) {
346: BundleGroup curr_group = (BundleGroup) group_v.elementAt(i);
347: BundleGroup parent_group = null;
348: if (parent_group_v != null) {
349: Enumeration parentGroupIter = parent_group_v.elements();
350:
351: while (parentGroupIter.hasMoreElements()) {
352: BundleGroup groupToFind = (BundleGroup) parentGroupIter
353: .nextElement();
354: if (groupToFind.getName().equals(
355: curr_group.getName())) {
356: parent_group = groupToFind;
357: break;
358: }
359: }
360: }
361: Element group_elem = xml.createElement("group");
362: group_elem.setAttribute("id", curr_group.getName());
363: if (curr_group.getComment() != null
364: && curr_group.getComment().length() > 1) {
365: Element comment_prop = xml.createElement("note");
366: comment_prop.setAttribute("xml:space", "preserve");
367: comment_prop.appendChild(xml.createTextNode(curr_group
368: .getComment()));
369: group_elem.appendChild(comment_prop);
370: }
371:
372: Vector group_items = curr_group.getItemsAsVector();
373: for (int j = 0; j < group_items.size(); j++) {
374: BundleItem main_item = (BundleItem) group_items.get(j);
375: BundleItem parent_item = null;
376: if (parent_group != null) {
377: Enumeration parentIter = parent_group
378: .getItemsAsVector().elements();
379: BundleItem itemToFind = null;
380: while (parentIter.hasMoreElements()) {
381: itemToFind = (BundleItem) parentIter
382: .nextElement();
383: if (itemToFind.getKey().equals(
384: main_item.getKey())) {
385: parent_item = itemToFind;
386: break;
387: }
388: }
389: }
390: addTransUnit(xml, group_elem, main_item, parent_item);
391: //group_elem.appendChild(tu);
392: }
393: body.appendChild(group_elem);
394: } // end for - i
395: String suffix = mainLocale;
396: if (!suffix.equals("")) {
397: suffix = '_' + suffix;
398: }
399: char array[] = suffix.toCharArray();
400: for (int k = 0; k < array.length; k++) {
401: if (array[k] == '-')
402: array[k] = '_';
403: }
404: suffix = String.valueOf(array);
405:
406: // serialize document
407: OutputStreamWriter osw = new OutputStreamWriter(
408: new FileOutputStream(new File(directory, base_name
409: + suffix + ".xlf")), "UTF-8");
410: try {
411: Transformer transformer = TransformerFactory.newInstance()
412: .newTransformer();
413: transformer.setOutputProperty(OutputKeys.METHOD, "xml");
414: transformer.setOutputProperty(OutputKeys.INDENT, "yes");
415: transformer.setOutputProperty(
416: "{http://xml.apache.org/xslt}indent-amount", "2");
417: transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
418: XLIFF_DTD);
419: transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
420: XLIFF_PUBLIC_NAME);
421: transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
422: transformer.transform(new DOMSource(xml), new StreamResult(
423: osw));
424: } catch (TransformerException te) {
425: throw new IOException(te.getMessage());
426: }
427:
428: osw.close();
429: }
430: }
|