[tor-commits] [exonerator/master] Add lang parameter to explicitly select a language.

karsten at torproject.org karsten at torproject.org
Wed Apr 26 17:46:43 UTC 2017


commit 73915aa7ec94b2f87419a2f50cda202a5f8e6369
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Wed Apr 26 17:20:16 2017 +0200

    Add lang parameter to explicitly select a language.
    
    Language names and translations of "This page is also available in the
    following languages:" taken from https://www.debian.org/.
---
 .../torproject/exonerator/ExoneraTorServlet.java   | 105 +++++++++++++++------
 src/main/resources/ExoneraTor.properties           |   2 +
 src/main/resources/ExoneraTor_de.properties        |   2 +
 src/main/resources/ExoneraTor_fr.properties        |   3 +
 src/main/resources/ExoneraTor_ro.properties        |   2 +
 src/main/resources/ExoneraTor_sv.properties        |   2 +
 6 files changed, 85 insertions(+), 31 deletions(-)

diff --git a/src/main/java/org/torproject/exonerator/ExoneraTorServlet.java b/src/main/java/org/torproject/exonerator/ExoneraTorServlet.java
index 7a5d18b..2785bef 100644
--- a/src/main/java/org/torproject/exonerator/ExoneraTorServlet.java
+++ b/src/main/java/org/torproject/exonerator/ExoneraTorServlet.java
@@ -16,12 +16,16 @@ import java.sql.Statement;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.ResourceBundle;
+import java.util.SortedMap;
 import java.util.SortedSet;
 import java.util.TimeZone;
+import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -44,6 +48,11 @@ public class ExoneraTorServlet extends HttpServlet {
 
   private Logger logger;
 
+  private List<String> availableLanguages =
+      Arrays.asList("de", "en", "fr", "ro", "sv");
+
+  private SortedMap<String, String> availableLanguageNames;
+
   @Override
   public void init() {
 
@@ -58,6 +67,14 @@ public class ExoneraTorServlet extends HttpServlet {
     } catch (NamingException e) {
       this.logger.log(Level.WARNING, "Could not look up data source", e);
     }
+
+    this.availableLanguageNames = new TreeMap<>();
+    for (String locale : this.availableLanguages) {
+      ResourceBundle rb = ResourceBundle.getBundle("ExoneraTor",
+          Locale.forLanguageTag(locale));
+      this.availableLanguageNames.put(locale, rb.getString(
+          "footer.language.name"));
+    }
   }
 
   @Override
@@ -69,13 +86,19 @@ public class ExoneraTorServlet extends HttpServlet {
     response.setContentType("text/html");
     response.setCharacterEncoding("utf-8");
 
-    /* Find the right resource bundle for the user's locale. */
-    Locale locale = request.getLocale();
-    ResourceBundle rb = ResourceBundle.getBundle("ExoneraTor", locale);
+    /* Find the right resource bundle for the user's requested language. */
+    String langParameter = request.getParameter("lang");
+    String langStr = "en";
+    if (null != langParameter
+        && this.availableLanguages.contains(langParameter)) {
+      langStr = langParameter;
+    }
+    ResourceBundle rb = ResourceBundle.getBundle("ExoneraTor",
+        Locale.forLanguageTag(langStr));
 
     /* Start writing response. */
     PrintWriter out = response.getWriter();
-    this.writeHeader(out, rb);
+    this.writeHeader(out, rb, langStr);
 
     /* Open a database connection that we'll use to handle the whole
      * request. */
@@ -83,7 +106,7 @@ public class ExoneraTorServlet extends HttpServlet {
     Connection conn = this.connectToDatabase();
     if (conn == null) {
       this.writeSummaryUnableToConnectToDatabase(out, rb);
-      this.writeFooter(out, rb);
+      this.writeFooter(out, rb, null, null);
       return;
     }
 
@@ -92,7 +115,7 @@ public class ExoneraTorServlet extends HttpServlet {
         conn);
     if (firstAndLastDates == null) {
       this.writeSummaryNoData(out, rb);
-      this.writeFooter(out, rb);
+      this.writeFooter(out, rb, null, null);
       this.closeDatabaseConnection(conn, requestedConnection);
     }
     SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@@ -132,12 +155,12 @@ public class ExoneraTorServlet extends HttpServlet {
         !relayIpHasError
         && !("".equals(relayIp) && !"".equals(timestampStr))
         && (timestampHasError || timestampOutOfRange
-        || (!"".equals(relayIp) && "".equals(timestampStr))));
+        || (!"".equals(relayIp) && "".equals(timestampStr))), langStr);
 
     /* If both parameters are empty, don't print any summary and exit.
      * This is the start page. */
     if ("".equals(relayIp) && "".equals(timestampStr)) {
-      this.writeFooter(out, rb);
+      this.writeFooter(out, rb, null, null);
       this.closeDatabaseConnection(conn, requestedConnection);
       return;
     }
@@ -150,7 +173,7 @@ public class ExoneraTorServlet extends HttpServlet {
       } else {
         writeSummaryNoTimestamp(out, rb);
       }
-      this.writeFooter(out, rb);
+      this.writeFooter(out, rb, null, null);
       this.closeDatabaseConnection(conn, requestedConnection);
       return;
     }
@@ -166,7 +189,7 @@ public class ExoneraTorServlet extends HttpServlet {
         this.writeSummaryTimestampOutsideRange(out, rb, timestampStr,
             firstDate, lastDate);
       }
-      this.writeFooter(out, rb);
+      this.writeFooter(out, rb, relayIp, timestampStr);
       this.closeDatabaseConnection(conn, requestedConnection);
       return;
     }
@@ -185,7 +208,7 @@ public class ExoneraTorServlet extends HttpServlet {
         toValidAfter);
     if (relevantConsensuses == null || relevantConsensuses.isEmpty()) {
       this.writeSummaryNoDataForThisInterval(out, rb);
-      this.writeFooter(out, rb);
+      this.writeFooter(out, rb, relayIp, timestampStr);
       this.closeDatabaseConnection(conn, requestedConnection);
       return;
     }
@@ -226,15 +249,15 @@ public class ExoneraTorServlet extends HttpServlet {
     } else if (addressesInSameNetwork != null
         && !addressesInSameNetwork.isEmpty()) {
       this.writeSummaryAddressesInSameNetwork(out, rb, relayIp,
-          timestampStr, addressesInSameNetwork);
+          timestampStr, langStr, addressesInSameNetwork);
     } else {
       this.writeSummaryNegative(out, rb, relayIp, timestampStr);
     }
 
-    this.writePermanentLink(out, rb, relayIp, timestampStr);
+    this.writePermanentLink(out, rb, relayIp, timestampStr, langStr);
 
     this.closeDatabaseConnection(conn, requestedConnection);
-    this.writeFooter(out, rb);
+    this.writeFooter(out, rb, relayIp, timestampStr);
   }
 
   /* Helper methods for handling the request. */
@@ -555,7 +578,7 @@ public class ExoneraTorServlet extends HttpServlet {
 
   /* Helper methods for writing the response. */
 
-  private void writeHeader(PrintWriter out, ResourceBundle rb)
+  private void writeHeader(PrintWriter out, ResourceBundle rb, String langStr)
       throws IOException {
     out.printf("<!DOCTYPE html>\n"
         + "<html lang=\"%s\">\n"
@@ -578,7 +601,7 @@ public class ExoneraTorServlet extends HttpServlet {
         + "          <div class=\"page-header\">\n"
         + "            <h1>\n"
         + "              <div class=\"text-center\">\n"
-        + "                <a href=\"/\">"
+        + "                <a href=\"/?lang=%<s\">"
           + "<img src=\"images/exonerator-logo.png\" "
           + "width=\"334\" height=\"252\" alt=\"ExoneraTor logo\">"
           + "<img src=\"images/exonerator-wordmark.png\" width=\"428\" "
@@ -588,12 +611,12 @@ public class ExoneraTorServlet extends HttpServlet {
         + "          </div><!-- page-header -->\n"
         + "        </div><!-- col -->\n"
         + "      </div><!-- row -->\n",
-        rb.getLocale().getLanguage());
+        langStr);
   }
 
   private void writeForm(PrintWriter out, ResourceBundle rb,
       String relayIp, boolean relayIpHasError, String timestampStr,
-      boolean timestampHasError) throws IOException {
+      boolean timestampHasError, String langStr) throws IOException {
     String ipValue = "";
     if (relayIp != null && relayIp.length() > 0) {
       if (relayIp.contains(":")) {
@@ -623,6 +646,7 @@ public class ExoneraTorServlet extends HttpServlet {
           + "name=\"timestamp\" id=\"inputTimestamp\" "
           + "placeholder=\"2010-01-01\"%s required>\n"
         + "              </div><!-- form-group -->\n"
+        + "              <input type=\"hidden\" name=\"lang\" value=\"%s\">\n"
         + "              <button type=\"submit\" "
           + "class=\"btn btn-primary\">%s</button>\n"
         + "            </form>\n"
@@ -637,6 +661,7 @@ public class ExoneraTorServlet extends HttpServlet {
         rb.getString("form.timestamp.label"),
         timestampStr != null && timestampStr.length() > 0
             ? " value=\"" + timestampStr + "\"" : "",
+        langStr,
         rb.getString("form.search.label"));
   }
 
@@ -730,7 +755,7 @@ public class ExoneraTorServlet extends HttpServlet {
   }
 
   private void writeSummaryAddressesInSameNetwork(PrintWriter out,
-      ResourceBundle rb, String relayIp, String timestampStr,
+      ResourceBundle rb, String relayIp, String timestampStr, String langStr,
       List<String> addressesInSameNetwork) throws IOException {
     Object[][] panelItems = new Object[addressesInSameNetwork.size()][];
     for (int i = 0; i < addressesInSameNetwork.size(); i++) {
@@ -738,12 +763,13 @@ public class ExoneraTorServlet extends HttpServlet {
       String link;
       String address;
       if (addressInSameNetwork.contains(":")) {
-        link = String.format("/?ip=[%s]&timestamp=%s",
-            addressInSameNetwork.replaceAll(":", "%3A"), timestampStr);
+        link = String.format("/?ip=[%s]&timestamp=%s&lang=%s",
+            addressInSameNetwork.replaceAll(":", "%3A"), timestampStr,
+            langStr);
         address = "[" + addressInSameNetwork + "]";
       } else {
-        link = String.format("/?ip=%s&timestamp=%s",
-            addressInSameNetwork, timestampStr);
+        link = String.format("/?ip=%s&timestamp=%s&lang=%s",
+            addressInSameNetwork, timestampStr, langStr);
         address = addressInSameNetwork;
       }
       panelItems[i] = new Object[] { link, address };
@@ -861,22 +887,22 @@ public class ExoneraTorServlet extends HttpServlet {
   }
 
   private void writePermanentLink(PrintWriter out, ResourceBundle rb,
-      String relayIp, String timestampStr) throws IOException {
+      String relayIp, String timestampStr, String langStr) throws IOException {
     String encodedAddress = relayIp.contains(":")
         ? "[" + relayIp.replaceAll(":", "%3A") + "]" : relayIp;
     out.printf("      <div class=\"row\">\n"
         + "        <div class=\"col-xs-12\">\n"
         + "          <h2>%s</h2>\n"
         + "          <pre>https://exonerator.torproject.org/?ip=%s&"
-          + "timestamp=%s</pre>\n"
+          + "timestamp=%s&lang=%s</pre>\n"
         + "        </div><!-- col -->\n"
         + "      </div><!-- row -->\n",
         rb.getString("permanentlink.heading"),
-        encodedAddress, timestampStr);
+        encodedAddress, timestampStr, langStr);
   }
 
-  private void writeFooter(PrintWriter out, ResourceBundle rb)
-      throws IOException {
+  private void writeFooter(PrintWriter out, ResourceBundle rb, String relayIp,
+      String timestampStr) throws IOException {
     out.printf("    </div><!-- container -->\n"
         + "    <div class=\"footer\">\n"
         + "      <div class=\"container\">\n"
@@ -898,11 +924,28 @@ public class ExoneraTorServlet extends HttpServlet {
         + "            <h3>%s</h3>\n"
         + "            <p class=\"small\">%s</p>\n"
         + "          </div><!-- col -->\n"
-        + "        </div><!-- row -->\n"
-        + "        <div class=\"row\">\n",
+        + "        </div><!-- row -->\n",
         rb.getString("footer.aboutexonerator.heading"),
         rb.getString("footer.aboutexonerator.body"));
-    out.printf("          <div class=\"col-xs-12\">\n"
+    out.printf("        <div class=\"row\">\n"
+        + "          <div class=\"col-xs-12\">\n"
+        + "            <p class=\"text-center small\">%s",
+        rb.getString("footer.language.text"));
+    for (Map.Entry<String, String> entry
+        : this.availableLanguageNames.entrySet()) {
+      if (null != relayIp && null != timestampStr) {
+        out.printf(" <a href=\"/?ip=%s&timestamp=%s&lang=%s\">%s</a>",
+            relayIp, timestampStr, entry.getKey(), entry.getValue());
+      } else {
+        out.printf(" <a href=\"/?lang=%s\">%s</a>",
+            entry.getKey(), entry.getValue());
+      }
+    }
+    out.printf("</p>\n"
+        + "          </div><!-- col -->\n"
+        + "        </div><!-- row -->\n"
+        + "        <div class=\"row\">\n"
+        + "          <div class=\"col-xs-12\">\n"
         + "            <p class=\"text-center small\">%s</p>\n"
         + "          </div><!-- col -->\n"
         + "        </div><!-- row -->\n"
diff --git a/src/main/resources/ExoneraTor.properties b/src/main/resources/ExoneraTor.properties
index 6fa3081..03b8489 100644
--- a/src/main/resources/ExoneraTor.properties
+++ b/src/main/resources/ExoneraTor.properties
@@ -49,4 +49,6 @@ footer.aboutexonerator.heading=About ExoneraTor
 footer.aboutexonerator.body=The ExoneraTor service maintains a database of IP addresses that have been part of the Tor network.  It answers the question whether there was a Tor relay running on a given IP address on a given date.  ExoneraTor may store more than one IP address per relay if relays use a different IP address for exiting to the Internet than for registering in the Tor network, and it stores whether a relay permitted transit of Tor traffic to the open Internet at that time.
 footer.trademark.text="Tor" and the "Onion Logo" are %s of The Tor Project, Inc.
 footer.trademark.link=registered trademarks
+footer.language.name=English
+footer.language.text=This page is also available in the following languages:
 
diff --git a/src/main/resources/ExoneraTor_de.properties b/src/main/resources/ExoneraTor_de.properties
index 9a594d8..7484cae 100644
--- a/src/main/resources/ExoneraTor_de.properties
+++ b/src/main/resources/ExoneraTor_de.properties
@@ -49,4 +49,6 @@ footer.aboutexonerator.heading=\u00dcber ExoneraTor
 footer.aboutexonerator.body=Der ExoneraTor-Dienst basiert auf einer Datenbank von IP-Adressen, die Teil des Tor-Netzwerks sind oder waren. Dieser Dienst beantwortet die Frage, ob es an einem bestimmten Tag einen Tor-Server mit einer bestimmten IP-Adresse gegeben hat. ExoneraTor kann in einigen F\u00e4llen mehr als nur eine IP-Adresse pro Tor-Server speichern, falls ein Tor-Server eine andere IP-Adresse f\u00fcr ausgehende Verbindungen verwendet hat als die IP-Adresse um sich im Tor-Netzwerk zu registrieren. ExoneraTor speichert au\u00dferdem ob ein Tor-Server Verbindungen ins offene Internet zugelassen hat oder nicht.
 footer.trademark.text="Tor" und das "Onion Logo" sind %s von The Tor Project, Inc.
 footer.trademark.link=eingetragene Warenzeichen
+footer.language.name=Deutsch
+footer.language.text=Diese Seite gibt es auch in den folgenden Sprachen:
 
diff --git a/src/main/resources/ExoneraTor_fr.properties b/src/main/resources/ExoneraTor_fr.properties
index d28d6a6..09c8e65 100644
--- a/src/main/resources/ExoneraTor_fr.properties
+++ b/src/main/resources/ExoneraTor_fr.properties
@@ -49,3 +49,6 @@ footer.aboutexonerator.heading=\u00c0 propos d'ExoneraTor
 footer.aboutexonerator.body=Le service ExoneraTor g\u00e8re une base de donn\u00e9es d'adresses IP qui ont fait partie du r\u00e9seau Tor. Il permet de savoir si un relais Tor fonctionnait pour une adresse IP donn\u00e9e \u00e0 une date pr\u00e9cise. ExoneraTor peut enregistrer plus d'une adresse IP par relais si ces derniers utilisent une adresse IP diff\u00e9rente pour se connecter \u00e0 Internet de celle utilis\u00e9e pour s'enregistrer sur le r\u00e9seau Tor. ExoneraTor enregistre \u00e9galement les dates et heures auxquelles un relais a permis de faire transiter du trafic en provenance de Tor vers Internet.
 footer.trademark.text=\u00ab\u00a0Tor\u00a0\u00bb et le \u00ab\u00a0logo Oignon\u00a0\u00bb sont des %s de \u00ab\u00a0The Tor Project, Inc.\u00a0\u00bb
 footer.trademark.link=marques d\u00e9pos\u00e9es
+footer.language.name=fran\u00e7ais
+footer.language.text=Cette page est aussi disponible dans les langues suivantes :
+
diff --git a/src/main/resources/ExoneraTor_ro.properties b/src/main/resources/ExoneraTor_ro.properties
index fbf58d3..7ded64e 100644
--- a/src/main/resources/ExoneraTor_ro.properties
+++ b/src/main/resources/ExoneraTor_ro.properties
@@ -49,4 +49,6 @@ footer.aboutexonerator.heading=Despre ExoneraTor
 footer.aboutexonerator.body=Serviciul ExoneraTor opereaz\u0103 o baz\u0103 de date de adrese IP care au fost parte din re\u021belaua Tor la un anumit moment.  Acest serviciu r\u0103spunde la \u00eentrebarea dac\u0103 a existat un nod Tor care a func\u021bionat pe o anumit\u0103 adres\u0103 IP la o anumit\u0103 dat\u0103.   ExoneraTor poate stoca mai mult de o adresa IP per nod dac\u0103 nodurile folosesc o alt\u0103 adres\u0103 IP pentru a ie\u0219i pe internet dec\u00e2t cea folosit\u0103 pentru \u00eenregistrarea \u00een re\u021beaua Tor \u0219i stocheaz\u0103 dac\u0103 un nod a permis tranzitarea de trafic din re\u021beaua Tor catre internetul public la acea dat\u0103.
 footer.trademark.text="Tor" \u0219i "Onion Logo" sunt %s The Tor Project, Inc.
 footer.trademark.link=Marci \u00eenregistrate
+footer.language.name=rom\u00e2n\u0103
+footer.language.text=Aceast\u0103 pagin\u0103 mai este disponibil\u0103 \u00een urm\u0103toarele limbi:
 
diff --git a/src/main/resources/ExoneraTor_sv.properties b/src/main/resources/ExoneraTor_sv.properties
index 3e39c6b..5979e4d 100644
--- a/src/main/resources/ExoneraTor_sv.properties
+++ b/src/main/resources/ExoneraTor_sv.properties
@@ -49,4 +49,6 @@ footer.aboutexonerator.heading=Om ExoneraTor
 footer.aboutexonerator.body=Tj\u00e4nsten ExoneraTor uppr\u00e4tth\u00e5ller en databas \u00f6ver IP-adresser som har varit en del av Tor-n\u00e4tverket. Den ger svar p\u00e5 fr\u00e5gan om det var ett Tor-rel\u00e4 som anv\u00e4nde en viss IP-adress vid ett givet datum. ExoneraTor kan komma att lagra fler \u00e4n en IP-adress per rel\u00e4 f\u00f6r rel\u00e4n som anv\u00e4nder en annan IP-adress f\u00f6r att ansluta till internet \u00e4n den som anv\u00e4ndes f\u00f6r att registrera sig i Tor-n\u00e4tverket. Huruvida ett rel\u00e4 har till\u00e5tit Tor-trafik ut mot internet vid tidpunkten eller ej lagras ocks\u00e5.
 footer.trademark.text="Tor" och "Onion-loggan" \u00e4r %s av The Tor Project, Inc.
 footer.trademark.link=registrerade varum\u00e4rken
+footer.language.name=svenska
+footer.language.text=Denna sida finns \u00e4ven p\u00e5 f\u00f6ljande spr\u00e5k:
 





More information about the tor-commits mailing list