/* * Copyright 2010 ZXing authors * * 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. */ package com.google.zxing; import java.io.BufferedReader; import java.io.Closeable; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * <p>A utility which auto-translates English strings in Android string resources using * Google Translate.</p> * * <p>Pass the Android client res/ directory as first argument, and optionally message keys * who should be forced to retranslate. * Usage: <code>StringsResourceTranslator android/res/ [key_1 ...]</p> * * @author Sean Owen */ public final class StringsResourceTranslator { private static final Charset UTF8 = Charset.forName("UTF-8"); private static final Pattern ENTRY_PATTERN = Pattern.compile("<string name=\"([^\"]+)\">([^<]+)</string>"); private static final Pattern STRINGS_FILE_NAME_PATTERN = Pattern.compile("values-(.+)"); private static final Pattern TRANSLATE_RESPONSE_PATTERN = Pattern.compile( "\\{\"translatedText\":\"([^\"]+)\"\\}"); private static final String APACHE_2_LICENSE = "<!--\n" + " Copyright (C) 2010 ZXing authors\n" + '\n' + " Licensed under the Apache License, Version 2.0 (the \"License\");\n" + " you may not use this file except in compliance with the License.\n" + " You may obtain a copy of the License at\n" + '\n' + " http://www.apache.org/licenses/LICENSE-2.0\n" + '\n' + " Unless required by applicable law or agreed to in writing, software\n" + " distributed under the License is distributed on an \"AS IS\" BASIS,\n" + " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" + " See the License for the specific language governing permissions and\n" + " limitations under the License.\n" + " -->\n"; private static final Map<String,String> LANGUAGE_CODE_MASSAGINGS = new HashMap<String,String>(4); static { LANGUAGE_CODE_MASSAGINGS.put("ja-rJP", "ja"); LANGUAGE_CODE_MASSAGINGS.put("zh-rCN", "zh-cn"); LANGUAGE_CODE_MASSAGINGS.put("zh-rTW", "zh-tw"); } private StringsResourceTranslator() {} public static void main(String[] args) throws IOException { File resDir = new File(args[0]); File valueDir = new File(resDir, "values"); File stringsFile = new File(valueDir, "strings.xml"); Collection<String> forceRetranslation = Arrays.asList(args).subList(1, args.length); File[] translatedValuesDirs = resDir.listFiles(new FileFilter() { public boolean accept(File file) { return file.isDirectory() && file.getName().startsWith("values-"); } }); for (File translatedValuesDir : translatedValuesDirs) { File translatedStringsFile = new File(translatedValuesDir, "strings.xml"); translate(stringsFile, translatedStringsFile, forceRetranslation); } } private static void translate(File englishFile, File translatedFile, Collection<String> forceRetranslation) throws IOException { SortedMap<String,String> english = readLines(englishFile); SortedMap<String,String> translated = readLines(translatedFile); String parentName = translatedFile.getParentFile().getName(); Matcher stringsFileNameMatcher = STRINGS_FILE_NAME_PATTERN.matcher(parentName); stringsFileNameMatcher.find(); String language = stringsFileNameMatcher.group(1); String massagedLanguage = LANGUAGE_CODE_MASSAGINGS.get(language); if (massagedLanguage != null) { language = massagedLanguage; } System.out.println("Translating " + language); File resultTempFile = File.createTempFile(parentName, ".xml"); boolean anyChange = false; Writer out = null; try { out = new OutputStreamWriter(new FileOutputStream(resultTempFile), UTF8); out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); out.write(APACHE_2_LICENSE); out.write("<resources>\n"); for (Map.Entry<String,String> englishEntry : english.entrySet()) { String key = englishEntry.getKey(); out.write(" <string name=\""); out.write(key); out.write("\">"); String translatedString = translated.get(key); if (translatedString == null || forceRetranslation.contains(key)) { anyChange = true; translatedString = translateString(englishEntry.getValue(), language); } out.write(translatedString); out.write("</string>\n"); } out.write("</resources>\n"); out.flush(); } finally { quietClose(out); } if (anyChange) { System.out.println(" Writing translations"); translatedFile.delete(); resultTempFile.renameTo(translatedFile); } } private static String translateString(String english, String language) throws IOException { System.out.println(" Need translation for " + english); URL translateURL = new URL( "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=" + URLEncoder.encode(english, "UTF-8") + "&langpair=en%7C" + language); StringBuilder translateResult = new StringBuilder(); Reader in = null; try { in = new InputStreamReader(translateURL.openStream(), UTF8); char[] buffer = new char[1024]; int charsRead; while ((charsRead = in.read(buffer)) > 0) { translateResult.append(buffer, 0, charsRead); } } finally { quietClose(in); } Matcher m = TRANSLATE_RESPONSE_PATTERN.matcher(translateResult); if (!m.find()) { throw new IOException("No translate result"); } String translation = m.group(1); System.out.println(" Got translation " + translation); return translation; } private static SortedMap<String,String> readLines(File file) throws IOException { SortedMap<String,String> entries = new TreeMap<String,String>(); BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), UTF8)); String line; while ((line = reader.readLine()) != null) { Matcher m = ENTRY_PATTERN.matcher(line); if (m.find()) { String key = m.group(1); String value = m.group(2); entries.put(key, value); } } return entries; } finally { quietClose(reader); } } private static void quietClose(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (IOException ioe) { // continue } } } }