From 443e2c7a6fd94693cd498a3e1e60fe864e0f492c Mon Sep 17 00:00:00 2001 From: Grishka Date: Mon, 25 Sep 2023 18:51:49 +0300 Subject: [PATCH] Add a tool to detect invalid formatting in localized strings --- tools/VerifyTranslatedStringFormatting.java | 116 ++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 tools/VerifyTranslatedStringFormatting.java diff --git a/tools/VerifyTranslatedStringFormatting.java b/tools/VerifyTranslatedStringFormatting.java new file mode 100644 index 000000000..2aeb22d19 --- /dev/null +++ b/tools/VerifyTranslatedStringFormatting.java @@ -0,0 +1,116 @@ +// run: java tools/VerifyTranslatedStringFormatting.java +// Reads all localized strings and makes sure they contain valid formatting placeholders matching the original English strings to avoid crashes. + +import org.w3c.dom.*; +import javax.xml.parsers.*; +import java.io.*; +import java.util.*; +import java.util.regex.*; + +public class VerifyTranslatedStringFormatting{ + // %[argument_index$][flags][width][.precision][t]conversion + private static final String formatSpecifier="%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])"; + private static final Pattern fsPattern=Pattern.compile(formatSpecifier); + + private static HashMap> placeholdersInStrings=new HashMap<>(); + private static int errorCount=0; + + public static void main(String[] args) throws Exception{ + DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(false); + DocumentBuilder builder=factory.newDocumentBuilder(); + Document doc; + try(FileInputStream in=new FileInputStream("mastodon/src/main/res/values/strings.xml")){ + doc=builder.parse(in); + } + NodeList list=doc.getDocumentElement().getChildNodes(); // why does this stupid NodeList thing exist at all? + for(int i=0;i placeholders=new ArrayList<>(); + Matcher matcher=fsPattern.matcher(value); + while(matcher.find()){ + placeholders.add(matcher.group()); + } + placeholdersInStrings.put(name, placeholders); + } + } + for(File file:new File("mastodon/src/main/res").listFiles()){ + if(file.getName().startsWith("values-")){ + File stringsXml=new File(file, "strings.xml"); + if(stringsXml.exists()){ + processFile(stringsXml); + } + } + } + if(errorCount>0){ + System.err.println("Found "+errorCount+" problems in localized strings"); + System.exit(1); + } + } + + private static void processFile(File file) throws Exception{ + DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(false); + DocumentBuilder builder=factory.newDocumentBuilder(); + Document doc; + try(FileInputStream in=new FileInputStream(file)){ + doc=builder.parse(in); + } + NodeList list=doc.getDocumentElement().getChildNodes(); + for(int i=0;i placeholders){ + for(String placeholder:placeholders){ + if(placeholder.equals("%,d")){ + // %,d and %d are interchangeable but %,d provides nicer formatting + if(!str.contains(placeholder) && !str.contains("%d")) + return false; + }else if(!str.contains(placeholder)){ + return false; + } + } + return true; + } +} \ No newline at end of file