From 20a8a3a29f77843e1c49319aab2b8374fecadfb7 Mon Sep 17 00:00:00 2001 From: srowen Date: Mon, 12 Sep 2011 17:30:21 +0000 Subject: [PATCH] Fix Issue 978, bad Brazil/Bulgaria mapping. Also add a new framework for auto-translating HTML assets. git-svn-id: https://zxing.googlecode.com/svn/trunk@1905 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- android/assets/{html => html-en}/about1d.html | 6 +- android/assets/{html => html-en}/about2d.html | 2 +- android/assets/{html => html-en}/index.html | 2 +- .../assets/{html => html-en}/scanning.html | 2 +- android/assets/{html => html-en}/sharing.html | 4 +- .../assets/{html => html-en}/whatsnew.html | 2 +- android/assets/{html => }/style.css | 0 .../zxing/client/android/HelpActivity.java | 3 +- .../zxing/client/android/LocaleManager.java | 18 ++- .../com/google/zxing/HtmlAssetTranslator.java | 130 ++++++++++++++++++ .../zxing/StringsResourceTranslator.java | 28 +++- 11 files changed, 184 insertions(+), 13 deletions(-) rename android/assets/{html => html-en}/about1d.html (71%) rename android/assets/{html => html-en}/about2d.html (94%) rename android/assets/{html => html-en}/index.html (93%) rename android/assets/{html => html-en}/scanning.html (94%) rename android/assets/{html => html-en}/sharing.html (82%) rename android/assets/{html => html-en}/whatsnew.html (94%) rename android/assets/{html => }/style.css (100%) create mode 100644 javase/src/com/google/zxing/HtmlAssetTranslator.java diff --git a/android/assets/html/about1d.html b/android/assets/html-en/about1d.html similarity index 71% rename from android/assets/html/about1d.html rename to android/assets/html-en/about1d.html index a733fca4c..349f4039c 100644 --- a/android/assets/html/about1d.html +++ b/android/assets/html-en/about1d.html @@ -1,17 +1,17 @@ About 1D barcodes - +

Traditional barcodes, such as those printed on product packaging, are also known as one dimensional barcodes. There are several types commonly used, including UPC and EAN. Most look similar to this:

-

+

1D

These 1D barcodes contain a unique code which typically describes a product, like a CD or a book. You can look this code up on the internet to find prices, reviews, and more.

If you scan a book, you can also search the contents of the book for a word or phrase, and find all the pages where it appears:

-

+

Search book contents

\ No newline at end of file diff --git a/android/assets/html/about2d.html b/android/assets/html-en/about2d.html similarity index 94% rename from android/assets/html/about2d.html rename to android/assets/html-en/about2d.html index 979cb8a24..645aee0c6 100644 --- a/android/assets/html/about2d.html +++ b/android/assets/html-en/about2d.html @@ -1,7 +1,7 @@ About 2D barcodes - +

Barcode Scanner also understands how to read two dimensional barcodes, like QR diff --git a/android/assets/html/index.html b/android/assets/html-en/index.html similarity index 93% rename from android/assets/html/index.html rename to android/assets/html-en/index.html index 903aa63b8..0e87d3a97 100644 --- a/android/assets/html/index.html +++ b/android/assets/html-en/index.html @@ -1,7 +1,7 @@ Barcode Scanner Help - +

Barcode Scanner uses the camera on your phone to read barcodes and look up product diff --git a/android/assets/html/scanning.html b/android/assets/html-en/scanning.html similarity index 94% rename from android/assets/html/scanning.html rename to android/assets/html-en/scanning.html index 76d254a1d..2d7fd2bdf 100644 --- a/android/assets/html/scanning.html +++ b/android/assets/html-en/scanning.html @@ -1,7 +1,7 @@ How to scan - +

Barcode Scanner continuously scans a square region shown on your screen — just line up the diff --git a/android/assets/html/sharing.html b/android/assets/html-en/sharing.html similarity index 82% rename from android/assets/html/sharing.html rename to android/assets/html-en/sharing.html index fcbb6ba1d..11c16635b 100644 --- a/android/assets/html/sharing.html +++ b/android/assets/html-en/sharing.html @@ -1,13 +1,13 @@ How to create QR Codes - +

In addition to scanning 2D barcodes, Barcode Scanner can also generate a QR Code and display it on your screen. Then you can show it to a friend, and let them scan the barcode with their phone:

-

Scan from phone

+

Scan from phone

To use this feature, press the Menu button from the main scanning screen, and tap Share. Then choose whether you want to share a contact, a bookmark, an application, or the contents of the clipboard. A QR Code will be generated automatically. When you're done, press Back or Home.

diff --git a/android/assets/html/whatsnew.html b/android/assets/html-en/whatsnew.html similarity index 94% rename from android/assets/html/whatsnew.html rename to android/assets/html-en/whatsnew.html index c5c4264c1..7e0579187 100644 --- a/android/assets/html/whatsnew.html +++ b/android/assets/html-en/whatsnew.html @@ -1,7 +1,7 @@ What's new in Barcode Scanner - +

New in version 3.61:

diff --git a/android/assets/html/style.css b/android/assets/style.css similarity index 100% rename from android/assets/html/style.css rename to android/assets/style.css diff --git a/android/src/com/google/zxing/client/android/HelpActivity.java b/android/src/com/google/zxing/client/android/HelpActivity.java index 34d80ce37..0a5e691ea 100644 --- a/android/src/com/google/zxing/client/android/HelpActivity.java +++ b/android/src/com/google/zxing/client/android/HelpActivity.java @@ -55,7 +55,8 @@ public final class HelpActivity extends Activity { public static final String DEFAULT_PAGE = "index.html"; public static final String WHATS_NEW_PAGE = "whatsnew.html"; - private static final String BASE_URL = "file:///android_asset/html/"; + private static final String BASE_URL = + "file:///android_asset/html-" + LocaleManager.getTranslatedAssetLanguage() + '/'; private static final String WEBVIEW_STATE_PRESENT = "webview_state_present"; private static boolean initialized = false; diff --git a/android/src/com/google/zxing/client/android/LocaleManager.java b/android/src/com/google/zxing/client/android/LocaleManager.java index 4784a8b0e..b829ea10a 100644 --- a/android/src/com/google/zxing/client/android/LocaleManager.java +++ b/android/src/com/google/zxing/client/android/LocaleManager.java @@ -16,6 +16,8 @@ package com.google.zxing.client.android; +import java.util.Collection; +import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.HashMap; @@ -29,11 +31,14 @@ public final class LocaleManager { private static final String DEFAULT_TLD = "com"; private static final String DEFAULT_COUNTRY = "US"; + private static final String DEFAULT_LANGUAGE = "en"; private static final String COUNTRY; + private static final String LANGUAGE; static { Locale locale = Locale.getDefault(); COUNTRY = locale == null ? DEFAULT_COUNTRY : locale.getCountry(); + LANGUAGE = locale == null ? DEFAULT_LANGUAGE : locale.getLanguage(); } /** @@ -45,7 +50,8 @@ public final class LocaleManager { GOOGLE_COUNTRY_TLD = new HashMap(); GOOGLE_COUNTRY_TLD.put("AR", "com.ar"); // ARGENTINA GOOGLE_COUNTRY_TLD.put("AU", "com.au"); // AUSTRALIA - GOOGLE_COUNTRY_TLD.put("BG", "com.br"); // BULGARIA + GOOGLE_COUNTRY_TLD.put("BR", "com.br"); // BRAZIL + GOOGLE_COUNTRY_TLD.put("BG", "bg"); // BULGARIA GOOGLE_COUNTRY_TLD.put(Locale.CANADA.getCountry(), "ca"); GOOGLE_COUNTRY_TLD.put(Locale.CHINA.getCountry(), "cn"); GOOGLE_COUNTRY_TLD.put("CZ", "cz"); // CZECH REPUBLIC @@ -98,6 +104,12 @@ public final class LocaleManager { */ private static final Map GOOGLE_BOOK_SEARCH_COUNTRY_TLD = GOOGLE_COUNTRY_TLD; + private static final Collection TRANSLATED_HELP_ASSET_LANGUAGES; + static { + TRANSLATED_HELP_ASSET_LANGUAGES = new HashSet(); + TRANSLATED_HELP_ASSET_LANGUAGES.add("en"); + } + private LocaleManager() {} /** @@ -134,6 +146,10 @@ public final class LocaleManager { return url.startsWith("http://google.com/books") || url.startsWith("http://books.google."); } + public static String getTranslatedAssetLanguage() { + return TRANSLATED_HELP_ASSET_LANGUAGES.contains(LANGUAGE) ? LANGUAGE : DEFAULT_LANGUAGE; + } + private static String doGetTLD(Map map) { String tld = map.get(COUNTRY); return tld == null ? DEFAULT_TLD : tld; diff --git a/javase/src/com/google/zxing/HtmlAssetTranslator.java b/javase/src/com/google/zxing/HtmlAssetTranslator.java new file mode 100644 index 000000000..f4f69b12d --- /dev/null +++ b/javase/src/com/google/zxing/HtmlAssetTranslator.java @@ -0,0 +1,130 @@ +/* + * Copyright 2011 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 org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.bootstrap.DOMImplementationRegistry; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSSerializer; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.Queue; + +/** + *

A utility which auto-translates the English-language text in a directory of HTML documents using + * Google Translate.

+ * + *

Pass the Android client assets/ directory as first argument, and the language to translate to second. + * Optionally, you can specify the files to translate individually. + * Usage: {@code HtmlAssetTranslator android/assets/ es [file1.html file2.html ...]}

+ * + *

This will translate all .html files in subdirectory html-en to directory html-es, for example. + * Note that only text nodes in the HTML document are translated. Any text that is a child of a node + * with {@code class="notranslate"} will not be translated. It will also add a note at the end of + * the translated page that indicates it was automatically translated.

+ * + * @author Sean Owen + */ +public final class HtmlAssetTranslator { + + private HtmlAssetTranslator() {} + + public static void main(String[] args) throws Exception { + + File assetsDir = new File(args[0]); + File englishHtmlDir = new File(assetsDir, "html-en"); + String language = args[1]; + File targetHtmlDir = new File(assetsDir, "html-" + language); + targetHtmlDir.mkdirs(); + + final Collection fileNamesToTranslate = new ArrayList(); + for (int i = 2; i < args.length; i++) { + fileNamesToTranslate.add(args[i]); + } + + File[] sourceFiles = englishHtmlDir.listFiles(new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.endsWith(".html") && (fileNamesToTranslate.isEmpty() || fileNamesToTranslate.contains(name)); + } + }); + + for (File sourceFile : sourceFiles) { + + File destFile = new File(targetHtmlDir, sourceFile.getName()); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(sourceFile); + + Element rootElement = document.getDocumentElement(); + rootElement.normalize(); + + Queue nodes = new LinkedList(); + nodes.add(rootElement); + + while (!nodes.isEmpty()) { + Node node = nodes.poll(); + if (shouldTranslate(node)) { + NodeList children = node.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + nodes.add(children.item(i)); + } + } + if (node.getNodeType() == Node.TEXT_NODE) { + String text = node.getTextContent(); + if (text.trim().length() > 0) { + text = StringsResourceTranslator.translateString(text, language); + node.setTextContent(' ' + text + ' '); + } + } + } + + String translationTextTranslated = + StringsResourceTranslator.translateString("Translated by Google Translate.", language); + Node translateText = document.createTextNode(translationTextTranslated); + Node paragraph = document.createElement("p"); + paragraph.appendChild(translateText); + Node body = rootElement.getElementsByTagName("body").item(0); + body.appendChild(paragraph); + + DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance(); + DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS"); + LSSerializer writer = impl.createLSSerializer(); + writer.writeToURI(document, destFile.toURI().toString()); + } + } + + private static boolean shouldTranslate(Node node) { + NamedNodeMap attributes = node.getAttributes(); + if (attributes == null) { + return true; + } + Node classAttribute = attributes.getNamedItem("class"); + return classAttribute == null || !"notranslate".equals(classAttribute.getTextContent()); + } + +} diff --git a/javase/src/com/google/zxing/StringsResourceTranslator.java b/javase/src/com/google/zxing/StringsResourceTranslator.java index 4dcfdbc9b..ffabd2a47 100644 --- a/javase/src/com/google/zxing/StringsResourceTranslator.java +++ b/javase/src/com/google/zxing/StringsResourceTranslator.java @@ -51,6 +51,8 @@ import java.util.regex.Pattern; */ public final class StringsResourceTranslator { + private static final long MIN_API_CALL_INTERVAL_MS = 5 * 1000L; + private static final Charset UTF8 = Charset.forName("UTF-8"); private static final Pattern ENTRY_PATTERN = Pattern.compile("([^<]+)"); private static final Pattern STRINGS_FILE_NAME_PATTERN = Pattern.compile("values-(.+)"); @@ -82,6 +84,8 @@ public final class StringsResourceTranslator { LANGUAGE_CODE_MASSAGINGS.put("kr", "ko"); } + private static long nextAllowedAPICallTime = System.currentTimeMillis(); + private StringsResourceTranslator() {} public static void main(String[] args) throws IOException { @@ -166,8 +170,22 @@ public final class StringsResourceTranslator { } } - private static String translateString(String english, String language) throws IOException { + static String translateString(String english, String language) throws IOException { + if ("en".equals(language)) { + return english; + } System.out.println(" Need translation for " + english); + + long now = System.currentTimeMillis(); + if (now < nextAllowedAPICallTime) { + try { + Thread.sleep(nextAllowedAPICallTime - now); + } catch (InterruptedException ie) { + // continue + } + } + nextAllowedAPICallTime = now + MIN_API_CALL_INTERVAL_MS; + URL translateURL = new URL( "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=" + URLEncoder.encode(english, "UTF-8") + @@ -186,10 +204,16 @@ public final class StringsResourceTranslator { } Matcher m = TRANSLATE_RESPONSE_PATTERN.matcher(translateResult); if (!m.find()) { - throw new IOException("No translate result"); + System.err.println("No translate result"); + return english; } String translation = m.group(1); System.out.println(" Got translation " + translation); + + // This is a little crude; unescape some common escapes in the raw response + translation = translation.replaceAll("\\\\u0026quot;", "\""); + translation = translation.replaceAll("\\\\u0026#39;", "'"); + return translation; }