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
This commit is contained in:
srowen 2011-09-12 17:30:21 +00:00
parent dddc36e3cc
commit 20a8a3a29f
11 changed files with 184 additions and 13 deletions

View file

@ -1,17 +1,17 @@
<html>
<head>
<title>About 1D barcodes</title>
<link rel="stylesheet" href="style.css" type="text/css"/>
<link rel="stylesheet" href="../style.css" type="text/css"/>
</head>
<body>
<p>Traditional barcodes, such as those printed on product packaging, are also known as <em>one
dimensional barcodes</em>. There are several types commonly used, including UPC and EAN. Most look
similar to this:</p>
<p style="text-align:center"><img src="../images/big-1d.png"></p>
<p style="text-align:center"><img src="../images/big-1d.png" alt="1D"></p>
<p>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.</p>
<p>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:</p>
<center><p><img src="../images/search-book-contents.jpg"></p></center>
<p style="text-align:center"><img src="../images/search-book-contents.jpg" alt="Search book contents"></p>
</body>
</html>

View file

@ -1,7 +1,7 @@
<html>
<head>
<title>About 2D barcodes</title>
<link rel="stylesheet" href="style.css" type="text/css"/>
<link rel="stylesheet" href="../style.css" type="text/css"/>
</head>
<body>
<p><b>Barcode Scanner</b> also understands how to read two dimensional barcodes, like <em>QR

View file

@ -1,7 +1,7 @@
<html>
<head>
<title>Barcode Scanner Help</title>
<link rel="stylesheet" href="style.css" type="text/css"/>
<link rel="stylesheet" href="../style.css" type="text/css"/>
</head>
<body>
<p><b>Barcode Scanner</b> uses the camera on your phone to read barcodes and look up product

View file

@ -1,7 +1,7 @@
<html>
<head>
<title>How to scan</title>
<link rel="stylesheet" href="style.css" type="text/css"/>
<link rel="stylesheet" href="../style.css" type="text/css"/>
</head>
<body>
<p>Barcode Scanner continuously scans a square region shown on your screen &mdash; just line up the

View file

@ -1,13 +1,13 @@
<html>
<head>
<title>How to create QR Codes</title>
<link rel="stylesheet" href="style.css" type="text/css"/>
<link rel="stylesheet" href="../style.css" type="text/css"/>
</head>
<body>
<p>In addition to <a href="about2d.html">scanning 2D barcodes</a>, <b>Barcode Scanner</b> 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:</p>
<center><p><img src="../images/scan-from-phone.png" alt="Scan from phone"></p></center>
<p style="text-align:center"><img src="../images/scan-from-phone.png" alt="Scan from phone"></p>
<p>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.</p>

View file

@ -1,7 +1,7 @@
<html>
<head>
<title>What's new in Barcode Scanner</title>
<link rel="stylesheet" href="style.css" type="text/css"/>
<link rel="stylesheet" href="../style.css" type="text/css"/>
</head>
<body>
<p><b>New in version 3.61:</b></p>

View file

@ -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;

View file

@ -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<String,String>();
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<String,String> GOOGLE_BOOK_SEARCH_COUNTRY_TLD = GOOGLE_COUNTRY_TLD;
private static final Collection<String> TRANSLATED_HELP_ASSET_LANGUAGES;
static {
TRANSLATED_HELP_ASSET_LANGUAGES = new HashSet<String>();
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<String,String> map) {
String tld = map.get(COUNTRY);
return tld == null ? DEFAULT_TLD : tld;

View file

@ -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;
/**
* <p>A utility which auto-translates the English-language text in a directory of HTML documents using
* Google Translate.</p>
*
* <p>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 ...]}</p>
*
* <p>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.</p>
*
* @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<String> fileNamesToTranslate = new ArrayList<String>();
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<Node> nodes = new LinkedList<Node>();
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());
}
}

View file

@ -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("<string name=\"([^\"]+)\".*>([^<]+)</string>");
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;
}