/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import com.android.tools.layoutlib.annotations.Nullable; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.io.File; import java.io.FileWriter; import java.nio.charset.StandardCharsets; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; public class ResourceConverter { /** * Convert the Android strings.xml into generic Java strings.properties. */ public static void main(String[] args) throws Exception { System.out.println("Parsing input..."); Map map = loadStrings("./validator/resources/strings.xml"); System.out.println("Writing to output..."); writeStrings(map, "./validator/resources/strings.properties"); System.out.println("Finished converting."); } /** * Writes pair to outputPath. */ private static void writeStrings(Map map, String outputPath) throws Exception { File output = new File(outputPath); output.createNewFile(); try (FileWriter writer = new FileWriter(output, StandardCharsets.UTF_8)) { writer.write(getCopyRight()); writer.write("\n"); for (Entry entry : map.entrySet()) { String name = entry.getKey(); String value = entry.getValue(); writer.write(name + " = " + value + "\n"); } } } /** * Very hacky parser for Android-understood-values.xml. It parses * tags, and retrieve the name and the value associated. * * @param path to .xml containing android strings * @return Map containing name and values. */ @Nullable private static Map loadStrings(String path) throws Exception { // Use ordered map to minimize changes to strings.properties in git. Map toReturn = new LinkedHashMap<>(); File file = new File(path); if (!file.exists()) { System.err.println("The input file "+ path + " does not exist. Terminating."); return toReturn; } DocumentBuilder documentBuilder = DocumentBuilderFactory .newInstance().newDocumentBuilder(); Document document = documentBuilder.parse(file); NodeList nodeList = document.getElementsByTagName("string"); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); String name = node.getAttributes().getNamedItem("name").getNodeValue(); StringBuilder valueBuilder = new StringBuilder(); try { /* This is a very hacky way to bypass "ns1:g" tag in android's .xml. Ideally we'll read the tag from the parent and apply it here, but it being the deep node list I'm not currently sure how to parse it safely. Might need to look into IntelliJ PSI tree we have in Studio. But I didn't want to add unnecessary deps to LayoutLib. It also means resource namespaces are rendered useless after conversion. */ for (int j = 0; j < node.getChildNodes().getLength(); j++) { Node child = node.getChildNodes().item(j); String toAdd; if ("ns1:g".equals(child.getNodeName())) { toAdd = child.getFirstChild().getNodeValue(); } else if ("xliff:g".equals(child.getNodeName())) { toAdd = child.getFirstChild().getNodeValue(); } else { toAdd = child.getNodeValue(); } // Replace all tab, newline and multi indentations. toAdd = toAdd.replaceAll("[\n\t]", ""); toAdd = toAdd.replaceAll("[ ]+", " "); valueBuilder.append(toAdd); } String finalString = valueBuilder.toString().trim(); toReturn.put(name, finalString); } catch (Exception e) { e.printStackTrace(); } } return toReturn; } private static String getCopyRight() { return """ # # Copyright (C) 2020 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #"""; } }