[Android Software Development] ssuukk:
If your application has different language versions and a lot of changess to strings.xml (strings added, IDs renamed, strings deleted), the translations will soon become a mess and people won't know anymore what is there left to be translated or if particular string needs translation at all. To fix that I've created a simple java proggy, that

1) loads English strings as a golden source for all other strings

2) compares each values-xx/strings.xml to the above

3) adds a XML comment <!-- PLEASE TRANSLATE --> to each missing value

4) outputs modified to values-xx/strings.xml_obr, sorted by ID

Fast and easy. Here's the code (note: requires jdom-2.x.x.jar)

package pl.qus.utility.ash;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import org.jdom2.Comment;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

public class AndroidStringsHelper {
private class KeyVal {
String key;
String value;

public KeyVal(String k, String v)
{
key=k;
value=v;
}
}

String resDir = "";
ArrayList<File> listaJęzyków = new ArrayList<File>();
HashMap<String, String> wzorcowaMapa = new HashMap<String, String>();
HashMap<String, String> obrabianaMapa = new HashMap<String, String>();
private static String trKey="!#---TRANSLATE---#!";

public AndroidStringsHelper(String resourceDir) {
String[] listaPlików;
resDir = resourceDir;

File katalog = new File(resDir);
listaPlików = katalog.list();

for (int i = 0; i < listaPlików.length; i++) {
File obr = new File(resourceDir,listaPlików[i]);
if (obr.getName().startsWith("values")) {
File plik=new File(obr, "strings.xml");

if (plik.exists()) {
System.out.println("Dodaję:" + obr.getName());

if (obr.getName().equals("values"))
{

}
else
listaJęzyków.add(plik);
}
}
}

obróbJęzyki();
}

private void obróbJęzyki() {
zaczytajPlik(new File(resDir,"values\\strings.xml"),wzorcowaMapa);
List<KeyVal> sortowanaMapa = new ArrayList<KeyVal>();

for(File plik:listaJęzyków) {
sortowanaMapa.clear();
System.out.println("==================================");
System.out.println("Obrabiam:"+plik.getPath());
obrabianaMapa.clear();
zaczytajPlik(plik,obrabianaMapa);

SortedSet<String> sorted=new TreeSet<String>(wzorcowaMapa.keySet());
Iterator<String> it = sorted.iterator();

while(it.hasNext()) {
String klucz=it.next();

if(obrabianaMapa.containsKey(klucz))
{
sortowanaMapa.add(new KeyVal(klucz, obrabianaMapa.get(klucz)));
}
else
{
System.out.println("Brak ["+klucz+"]");
sortowanaMapa.add(new KeyVal(klucz, trKey+wzorcowaMapa.get(klucz)));
}

}

zapiszPlik(new File(plik.getPath()+"_obr"),sortowanaMapa);
}
}

private void zapiszPlik(File plik, List<KeyVal> docel) {
FileOutputStream os;

Document profileDoc = new Document();

Element root=new Element("resources");

Iterator<KeyVal> it = docel.iterator();
while(it.hasNext()) {
KeyVal nast=it.next();
String klucz=(String) nast.key;
String wart=(String) nast.value;

Element nowy=new Element("string");
if(wart.startsWith(trKey))
{
wart=wart.substring(trKey.length());
root.addContent(new Comment("PLEASE TRANSLATE!"));
}
nowy.addContent(wart);
nowy.setAttribute("name", klucz);
root.addContent(nowy);
}

profileDoc.addContent(root);

try {
os = new FileOutputStream(plik);
XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
outputter.output(profileDoc, os);
os.close();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

private void zaczytajPlik(File plik, HashMap<String, String> docel) {
SAXBuilder builder = new SAXBuilder();

try {
Document strings = builder.build(plik);

Element spis = strings.getRootElement();
List<Element> wszystkie = spis.getChildren();
for (Element e : wszystkie) {
docel.put(e.getAttributeValue("name"), e.getText());
}

} catch (JDOMException | IOException e) {
e.printStackTrace();
}
System.out.println("Zaczytane:"+docel.size());
}

}

To run it just pass a path to your resource directory:

public class Main {
public static void main(String arg[]) {
new AndroidStringsHelper("/path/to/your/workspace/project/res");

}
}