2 * Copyright 2010 ZXing authors
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.google.zxing;
19 import java.io.BufferedReader;
20 import java.io.Closeable;
22 import java.io.FileFilter;
23 import java.io.FileInputStream;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.InputStreamReader;
27 import java.io.OutputStreamWriter;
28 import java.io.Reader;
29 import java.io.Writer;
31 import java.net.URLEncoder;
32 import java.nio.charset.Charset;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.HashMap;
37 import java.util.SortedMap;
38 import java.util.TreeMap;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
43 * <p>A utility which auto-translates English strings in Android string resources using
44 * Google Translate.</p>
46 * <p>Pass the Android client res/ directory as first argument, and optionally message keys
47 * who should be forced to retranslate.
48 * Usage: <code>StringsResourceTranslator android/res/ [key_1 ...]</p>
52 public final class StringsResourceTranslator {
54 private static final Charset UTF8 = Charset.forName("UTF-8");
55 private static final Pattern ENTRY_PATTERN = Pattern.compile("<string name=\"([^\"]+)\">([^<]+)</string>");
56 private static final Pattern STRINGS_FILE_NAME_PATTERN = Pattern.compile("values-(.+)");
57 private static final Pattern TRANSLATE_RESPONSE_PATTERN = Pattern.compile(
58 "\\{\"translatedText\":\"([^\"]+)\"\\}");
60 private static final String APACHE_2_LICENSE =
62 " Copyright (C) 2010 ZXing authors\n" +
64 " Licensed under the Apache License, Version 2.0 (the \"License\");\n" +
65 " you may not use this file except in compliance with the License.\n" +
66 " You may obtain a copy of the License at\n" +
68 " http://www.apache.org/licenses/LICENSE-2.0\n" +
70 " Unless required by applicable law or agreed to in writing, software\n" +
71 " distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
72 " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
73 " See the License for the specific language governing permissions and\n" +
74 " limitations under the License.\n" +
77 private static final Map<String,String> LANGUAGE_CODE_MASSAGINGS = new HashMap<String,String>(7);
79 LANGUAGE_CODE_MASSAGINGS.put("ja-rJP", "ja");
80 LANGUAGE_CODE_MASSAGINGS.put("zh-rCN", "zh-cn");
81 LANGUAGE_CODE_MASSAGINGS.put("zh-rTW", "zh-tw");
82 LANGUAGE_CODE_MASSAGINGS.put("kr", "ko");
85 private StringsResourceTranslator() {}
87 public static void main(String[] args) throws IOException {
89 File resDir = new File(args[0]);
90 File valueDir = new File(resDir, "values");
91 File stringsFile = new File(valueDir, "strings.xml");
92 Collection<String> forceRetranslation = Arrays.asList(args).subList(1, args.length);
94 File[] translatedValuesDirs = resDir.listFiles(new FileFilter() {
95 public boolean accept(File file) {
96 return file.isDirectory() && file.getName().startsWith("values-");
99 for (File translatedValuesDir : translatedValuesDirs) {
100 File translatedStringsFile = new File(translatedValuesDir, "strings.xml");
101 translate(stringsFile, translatedStringsFile, forceRetranslation);
106 private static void translate(File englishFile, File translatedFile, Collection<String> forceRetranslation)
109 SortedMap<String,String> english = readLines(englishFile);
110 SortedMap<String,String> translated = readLines(translatedFile);
111 String parentName = translatedFile.getParentFile().getName();
113 Matcher stringsFileNameMatcher = STRINGS_FILE_NAME_PATTERN.matcher(parentName);
114 stringsFileNameMatcher.find();
115 String language = stringsFileNameMatcher.group(1);
116 String massagedLanguage = LANGUAGE_CODE_MASSAGINGS.get(language);
117 if (massagedLanguage != null) {
118 language = massagedLanguage;
121 System.out.println("Translating " + language);
123 File resultTempFile = File.createTempFile(parentName, ".xml");
125 boolean anyChange = false;
128 out = new OutputStreamWriter(new FileOutputStream(resultTempFile), UTF8);
129 out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
130 out.write(APACHE_2_LICENSE);
131 out.write("<resources>\n");
133 for (Map.Entry<String,String> englishEntry : english.entrySet()) {
134 String key = englishEntry.getKey();
135 out.write(" <string name=\"");
139 String translatedString = translated.get(key);
140 if (translatedString == null || forceRetranslation.contains(key)) {
142 translatedString = translateString(englishEntry.getValue(), language);
144 out.write(translatedString);
146 out.write("</string>\n");
149 out.write("</resources>\n");
157 System.out.println(" Writing translations");
158 translatedFile.delete();
159 resultTempFile.renameTo(translatedFile);
163 private static String translateString(String english, String language) throws IOException {
164 System.out.println(" Need translation for " + english);
165 URL translateURL = new URL(
166 "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=" +
167 URLEncoder.encode(english, "UTF-8") +
168 "&langpair=en%7C" + language);
169 StringBuilder translateResult = new StringBuilder();
172 in = new InputStreamReader(translateURL.openStream(), UTF8);
173 char[] buffer = new char[1024];
175 while ((charsRead = in.read(buffer)) > 0) {
176 translateResult.append(buffer, 0, charsRead);
181 Matcher m = TRANSLATE_RESPONSE_PATTERN.matcher(translateResult);
183 throw new IOException("No translate result");
185 String translation = m.group(1);
186 System.out.println(" Got translation " + translation);
190 private static SortedMap<String,String> readLines(File file) throws IOException {
191 SortedMap<String,String> entries = new TreeMap<String,String>();
192 BufferedReader reader = null;
194 reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), UTF8));
196 while ((line = reader.readLine()) != null) {
197 Matcher m = ENTRY_PATTERN.matcher(line);
199 String key = m.group(1);
200 String value = m.group(2);
201 entries.put(key, value);
210 private static void quietClose(Closeable closeable) {
211 if (closeable != null) {
214 } catch (IOException ioe) {