package com.box.l10n.mojito.android.strings; import org.springframework.stereotype.Component; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.FileWriter; import java.io.File; import java.io.StringWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import static com.box.l10n.mojito.android.strings.AndroidStringsXmlHelper.*; @Component public class AndroidStringsXmlWriter { private static String addEscape(String str) { String result = null; if (str != null) { result = str.replaceAll("\"", "\\\\\"").replaceAll("\n", "\\\\\n"); } return result; } private static String getPluralName(AndroidStringsTextUnit androidStringsTextUnit) { String result = null; if (androidStringsTextUnit.getPluralForm() != null) { result = androidStringsTextUnit.getName().substring(0, androidStringsTextUnit.getName().length() - androidStringsTextUnit.getPluralForm().length()); } return result; } private static void addSingularString(Document document, Node node, AndroidStringsTextUnit androidStringsTextUnit) { addComment(document, node, androidStringsTextUnit.getComment()); Element child = createChild(document, node, SINGULAR_ELEMENT_NAME); addText(child, addEscape(androidStringsTextUnit.getContent())); addAttribute(child, NAME_ATTRIBUTE_NAME, androidStringsTextUnit.getName()); addAttribute(child, ID_ATTRIBUTE_NAME, androidStringsTextUnit.getId()); } private static Node addPluralString(Document document, Node node, AndroidStringsTextUnit androidStringsTextUnit, String pluralNameSeparator) { addComment(document, node, androidStringsTextUnit.getComment()); Element child = createChild(document, node, PLURAL_ELEMENT_NAME); addAttribute(child, NAME_ATTRIBUTE_NAME, androidStringsTextUnit.getName().substring(0, androidStringsTextUnit.getName().length() - pluralNameSeparator.length() - androidStringsTextUnit.getPluralForm().length())); return child; } private static void addPluralList(Document document, Node node, List<AndroidStringsTextUnit> androidStringsTextUnitList) { for (AndroidStringsTextUnit androidStringsTextUnit : androidStringsTextUnitList) { Element child = createChild(document, node, PLURAL_ITEM_ELEMENT_NAME); addText(child, addEscape(androidStringsTextUnit.getContent())); addAttribute(child, QUANTITY_ATTRIBUTE_NAME, androidStringsTextUnit.getPluralForm()); addAttribute(child, ID_ATTRIBUTE_NAME, androidStringsTextUnit.getId()); } } private static Document toDocument(List<AndroidStringsTextUnit> androidStringsTextUnitList, String pluralNameSeparator) throws ParserConfigurationException { Document document = getDocumentBuilder().newDocument(); document.setXmlStandalone(true); Node node = document.createElement(ROOT_ELEMENT_NAME); document.appendChild(node); List<AndroidStringsTextUnit> sortedAndroidStringsTextUnitList = androidStringsTextUnitList.stream().sorted(Comparator.comparing(AndroidStringsTextUnit::getName)).collect(Collectors.toList()); for (int i = 0; i < sortedAndroidStringsTextUnitList.size(); i++) { if (sortedAndroidStringsTextUnitList.get(i).getPluralForm() == null) { addSingularString(document, node, sortedAndroidStringsTextUnitList.get(i)); } else { String pluralName = getPluralName(sortedAndroidStringsTextUnitList.get(i)); node = addPluralString(document, node, sortedAndroidStringsTextUnitList.get(i), pluralNameSeparator); List<AndroidStringsTextUnit> pluralList = new ArrayList<>(); for (; i < sortedAndroidStringsTextUnitList.size() && Objects.equals(pluralName, getPluralName(sortedAndroidStringsTextUnitList.get(i))); i++) { pluralList.add(sortedAndroidStringsTextUnitList.get(i)); } pluralList.sort(Comparator.comparingInt(item -> PluralItem.valueOf(item.getPluralForm()).ordinal())); addPluralList(document, node, pluralList); i -= 1; node = node.getParentNode(); } } return document; } private static <W extends java.io.Writer> W toWriter(Document document, W writer) throws TransformerException { TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.transform(new DOMSource(document), new StreamResult(writer)); return writer; } public static void toFile(List<AndroidStringsTextUnit> list, String fileName, String pluralNameSeparator) throws IOException, TransformerException, ParserConfigurationException { String text = toText(list, pluralNameSeparator); new FileWriter(new File(fileName)).write(text); } public static void toFile(List<AndroidStringsTextUnit> list, String fileName) throws IOException, TransformerException, ParserConfigurationException { String text = toText(list, DEFAULT_PLURAL_SEPARATOR); new FileWriter(new File(fileName)).write(text); } public static String toText(List<AndroidStringsTextUnit> list, String pluralNameSeparator) throws TransformerException, ParserConfigurationException { return toWriter(toDocument(list, pluralNameSeparator), new StringWriter()).toString(); } public static String toText(List<AndroidStringsTextUnit> list) throws TransformerException, ParserConfigurationException { return toWriter(toDocument(list, DEFAULT_PLURAL_SEPARATOR), new StringWriter()).toString(); } }