diff --git a/INSTALL.txt b/INSTALL.txt index 15a962df2..adbbc5ad5 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -1,10 +1,17 @@ I2P source installation instructions +Prerequisites to build from source: + Java SDK (preferably Sun) 1.5.0 or higher (1.6 recommended) + Apache Ant 1.7.0 or higher + Optional, For multilanguage support: The xgettext, msgfmt, and msgmerge tools installed + from the GNU gettext package http://www.gnu.org/software/gettext/ + To build and install I2P from source, you must first build and package up the appropriate installer by running: ant pkg + This will produce a few key files: * install.jar: the GUI and console installer * i2pinstall.exe: the GUI and console installer wrapped for cross-platform execution @@ -18,9 +25,6 @@ Or run the GUI installer: Or move the update file into an existing installation directory and restart. -You will need to have ant installed from http://ant.apache.org/ -(1.7.0 or newer) - Supported JVMs: Windows: Latest available from http://java.sun.com/ (1.5+ supported) Linux: Latest available from http://java.sun.com/ (1.5+ supported) diff --git a/README.txt b/README.txt index 3aa2141bb..c5ddc12bd 100644 --- a/README.txt +++ b/README.txt @@ -1,11 +1,13 @@ Prerequisites to build from source: Java SDK (preferably Sun) 1.5.0 or higher (1.6 recommended) Apache Ant 1.7.0 or higher + Optional, For multilanguage support: The xgettext, msgfmt, and msgmerge tools installed + from the GNU gettext package http://www.gnu.org/software/gettext/ To build: ant pkg Run 'ant' with no arguments to see other build options. - See http://www.i2p2.de/download.html for installation instructions. + See INSTALL.txt or http://www.i2p2.de/download.html for installation instructions. Documentation: http://www.i2p2.de/ diff --git a/apps/BOB/nbproject/private/private.xml b/apps/BOB/nbproject/private/private.xml index 685ecc5a1..653e554c3 100644 --- a/apps/BOB/nbproject/private/private.xml +++ b/apps/BOB/nbproject/private/private.xml @@ -2,6 +2,6 @@ - file:/usblv/NetBeansProjects/wi2p.i2p/apps/BOB/src/net/i2p/BOB/BOB.java + file:/usblv/NetBeansProjects/i2p.i2p/apps/BOB/src/net/i2p/BOB/TCPio.java diff --git a/apps/BOB/src/net/i2p/BOB/DoCMDS.java b/apps/BOB/src/net/i2p/BOB/DoCMDS.java index 8e4afb143..dcb0a195d 100644 --- a/apps/BOB/src/net/i2p/BOB/DoCMDS.java +++ b/apps/BOB/src/net/i2p/BOB/DoCMDS.java @@ -50,7 +50,7 @@ public class DoCMDS implements Runnable { // FIX ME // I need a better way to do versioning, but this will do for now. - public static final String BMAJ = "00", BMIN = "00", BREV = "08", BEXT = ""; + public static final String BMAJ = "00", BMIN = "00", BREV = "0A", BEXT = ""; public static final String BOBversion = BMAJ + "." + BMIN + "." + BREV + BEXT; private Socket server; private Properties props; diff --git a/apps/BOB/src/net/i2p/BOB/I2Plistener.java b/apps/BOB/src/net/i2p/BOB/I2Plistener.java index e55e54b9d..fc6dde603 100644 --- a/apps/BOB/src/net/i2p/BOB/I2Plistener.java +++ b/apps/BOB/src/net/i2p/BOB/I2Plistener.java @@ -60,20 +60,9 @@ public class I2Plistener implements Runnable { this._log = _log; this.socketManager = S; this.serverSocket = SS; -// tgwatch = 1; this.lives = lives; } - private void rlock() throws Exception { - database.getReadLock(); - info.getReadLock(); - } - - private void runlock() throws Exception { - database.releaseReadLock(); - info.releaseReadLock(); - } - /** * Simply listen on I2P port, and thread connections * @@ -83,34 +72,31 @@ public class I2Plistener implements Runnable { I2PSocket sessSocket = null; int conn = 0; try { - die: - { - try { - serverSocket.setSoTimeout(50); - - while (lives.get()) { - try { - sessSocket = serverSocket.accept(); - g = true; - } catch (ConnectException ce) { - g = false; - } catch (SocketTimeoutException ste) { - g = false; - } - if (g) { - g = false; - conn++; - // toss the connection to a new thread. - I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info, database, lives); - Thread t = new Thread(conn_c, Thread.currentThread().getName() + " I2PtoTCP " + conn); - t.start(); - } + try { + serverSocket.setSoTimeout(50); + while (lives.get()) { + try { + sessSocket = serverSocket.accept(); + g = true; + } catch (ConnectException ce) { + g = false; + } catch (SocketTimeoutException ste) { + g = false; } - } catch (I2PException e) { - // bad shit - System.out.println("Exception " + e); + if (g) { + g = false; + conn++; + // toss the connection to a new thread. + I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info, database, lives); + Thread t = new Thread(conn_c, Thread.currentThread().getName() + " I2PtoTCP " + conn); + t.start(); + } + } + } catch (I2PException e) { + // bad shit + System.out.println("Exception " + e); } } finally { try { diff --git a/apps/BOB/src/net/i2p/BOB/MUXlisten.java b/apps/BOB/src/net/i2p/BOB/MUXlisten.java index c91a8743c..671fffa95 100644 --- a/apps/BOB/src/net/i2p/BOB/MUXlisten.java +++ b/apps/BOB/src/net/i2p/BOB/MUXlisten.java @@ -104,10 +104,10 @@ public class MUXlisten implements Runnable { this.database.releaseReadLock(); this.info.releaseReadLock(); - socketManager = I2PSocketManagerFactory.createManager(prikey, Q); if (this.come_in) { this.listener = new ServerSocket(port, backlog, host); } + socketManager = I2PSocketManagerFactory.createManager(prikey, Q); // I2PException, IOException, RuntimeException // To bad we can't just catch and enumerate.... // } catch (I2PException e) { @@ -141,8 +141,6 @@ public class MUXlisten implements Runnable { this.info.add("STARTING", new Boolean(false)); this.info.releaseWriteLock(); this.database.releaseWriteLock(); - // throw new Exception(e); - // Debugging, I guess. e.printStackTrace(); throw new RuntimeException(e); } diff --git a/apps/BOB/src/net/i2p/BOB/TCPio.java b/apps/BOB/src/net/i2p/BOB/TCPio.java index d501759ef..5e99637dd 100644 --- a/apps/BOB/src/net/i2p/BOB/TCPio.java +++ b/apps/BOB/src/net/i2p/BOB/TCPio.java @@ -78,16 +78,20 @@ public class TCPio implements Runnable { * --Sponge * * Tested with 128 bytes, and there was no performance gain. + * 8192 bytes did lower load average across many connections. + * Should I raise it higer? The correct thing to do would be to + * override... perhaps use NTCP, but I2P's streaming lib lacks + * anything NTCP compatable. * * --Sponge */ int b; - byte a[] = new byte[1]; + byte a[] = new byte[8192]; try { try { while (lives.get()) { - b = Ain.read(a, 0, 1); + b = Ain.read(a, 0, 8192); if (b > 0) { Aout.write(a, 0, b); } else if (b == 0) { diff --git a/apps/BOB/src/net/i2p/BOB/TCPlistener.java b/apps/BOB/src/net/i2p/BOB/TCPlistener.java index b5addc27b..714ee1e7f 100644 --- a/apps/BOB/src/net/i2p/BOB/TCPlistener.java +++ b/apps/BOB/src/net/i2p/BOB/TCPlistener.java @@ -64,16 +64,6 @@ public class TCPlistener implements Runnable { this.lives = lives; } - private void rlock() throws Exception { - database.getReadLock(); - info.getReadLock(); - } - - private void runlock() throws Exception { - database.releaseReadLock(); - info.releaseReadLock(); - } - /** * Simply listen on TCP port, and thread connections * @@ -81,30 +71,27 @@ public class TCPlistener implements Runnable { public void run() { boolean g = false; int conn = 0; + Socket server = null; try { - die: - { - try { - Socket server = new Socket(); - listener.setSoTimeout(50); // We don't block, we cycle and check. - while (lives.get()) { - try { - server = listener.accept(); - g = true; - } catch (SocketTimeoutException ste) { - g = false; - } - if (g) { - conn++; - // toss the connection to a new thread. - TCPtoI2P conn_c = new TCPtoI2P(socketManager, server, info, database, lives); - Thread t = new Thread(conn_c, Thread.currentThread().getName() + " TCPtoI2P " + conn); - t.start(); - g = false; - } + try { + listener.setSoTimeout(50); // We don't block, we cycle and check. + while (lives.get()) { + try { + server = listener.accept(); + g = true; + } catch (SocketTimeoutException ste) { + g = false; + } + if (g) { + conn++; + // toss the connection to a new thread. + TCPtoI2P conn_c = new TCPtoI2P(socketManager, server, info, database, lives); + Thread t = new Thread(conn_c, Thread.currentThread().getName() + " TCPtoI2P " + conn); + t.start(); + g = false; } - } catch (IOException ioe) { } + } catch (IOException ioe) { } } finally { try { diff --git a/apps/addressbook/java/src/net/i2p/addressbook/Servlet.java b/apps/addressbook/java/src/net/i2p/addressbook/Servlet.java index 8f26788e4..fceecfe53 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/Servlet.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/Servlet.java @@ -21,24 +21,48 @@ package net.i2p.addressbook; -import javax.servlet.GenericServlet; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Random; + import javax.servlet.ServletConfig; import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; /** * A wrapper for addressbook to allow it to be started as a web application. * + * This was a GenericServlet, we make it an HttpServlet solely to provide a hook + * for SusiDNS to wake us up when the subscription list changes. + * * @author Ragnarok * */ -public class Servlet extends GenericServlet { +public class Servlet extends HttpServlet { + private Thread thread; + private String nonce; + private static final String PROP_NONCE = "addressbook.nonce"; - /* (non-Javadoc) - * @see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse) + /** + * Hack to allow susidns to kick the daemon when the subscription list changes. + * URL must be /addressbook/ with wakeup param set, and nonce param set from system property. + * + * (non-Javadoc) + * see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse) */ - public void service(ServletRequest request, ServletResponse response) { + public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { + //System.err.println("Got request nonce = " + request.getParameter("nonce")); + if (this.thread != null && request.getParameter("wakeup") != null && + this.nonce != null && this.nonce.equals(request.getParameter("nonce"))) { + //System.err.println("Sending interrupt"); + this.thread.interrupt(); + // no output + } else { + PrintWriter out = response.getWriter(); + out.write("I2P addressbook OK"); + } } /* (non-Javadoc) @@ -49,15 +73,19 @@ public class Servlet extends GenericServlet { try { super.init(config); } catch (ServletException exp) { + System.err.println("Addressbook init exception: " + exp); } + this.nonce = "" + Math.abs((new Random()).nextLong()); + // put the nonce where susidns can get it + System.setProperty(PROP_NONCE, this.nonce); String[] args = new String[1]; args[0] = config.getInitParameter("home"); - DaemonThread thread = new DaemonThread(args); - thread.setDaemon(true); - thread.setName("Addressbook"); - thread.start(); + this.thread = new DaemonThread(args); + this.thread.setDaemon(true); + this.thread.setName("Addressbook"); + this.thread.start(); System.out.println("INFO: Starting Addressbook " + Daemon.VERSION); - System.out.println("INFO: config root under " + args[0]); + //System.out.println("INFO: config root under " + args[0]); } } diff --git a/apps/addressbook/web.xml b/apps/addressbook/web.xml index 0c3548c68..b791b4ea0 100644 --- a/apps/addressbook/web.xml +++ b/apps/addressbook/web.xml @@ -13,4 +13,10 @@ 1 + + + addressbook + /* + + diff --git a/apps/i2psnark/java/bmsg.sh b/apps/i2psnark/java/bmsg.sh new file mode 100644 index 000000000..b9d294b32 --- /dev/null +++ b/apps/i2psnark/java/bmsg.sh @@ -0,0 +1,17 @@ +# +# Update messages_xx.po and messages_xx.class files, +# from both java and jsp sources. +# Requires installed programs xgettext, msgfmt, msgmerge, and find. +# zzz - public domain +# + +## launching sh.exe with -login parameter will open a shell with the current path always pointing to \bin\ +## need to cd into our orignal path - where we call sh.exe from. + +cd $CALLFROM +## echo $PWD + +## except this everything is the same with bundle-message.sh +## walking - public domain :-D + +source bundle-messages.sh $PARAS \ No newline at end of file diff --git a/apps/i2psnark/java/build.xml b/apps/i2psnark/java/build.xml index 59f0421e7..8323d57f6 100644 --- a/apps/i2psnark/java/build.xml +++ b/apps/i2psnark/java/build.xml @@ -37,7 +37,7 @@ - + @@ -51,12 +51,44 @@ - So we must continue to duplicate everything in the war. --> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -95,9 +127,7 @@ - - diff --git a/apps/i2psnark/java/bundle-messages.bat b/apps/i2psnark/java/bundle-messages.bat new file mode 100644 index 000000000..90feca972 --- /dev/null +++ b/apps/i2psnark/java/bundle-messages.bat @@ -0,0 +1,26 @@ +@echo off +set Callfrom=%cd% +set Paras=%1 + +rem before calling make sure you have msys and mingw 's "bin" path +rem in your current searching path +rem type "set path" to check +if not exist ..\locale\*.only goto updateALL + +rem put a messages_xx.only(eg messages_zh.only) into locale folder +rem this script will only touch the po file(eg zh) you specified, leaving other po files untact. + +for %%i in (..\locale\*.only) do set PO=%%~ni +echo [Notice] Yu choose to Ony update the choosen file: %PO%.po +for %%i in (..\locale\*.po) do if not %%~ni==%PO% ren %%i %%~ni.po- + +call sh --login %cd%\bmsg.sh + +for %%i in (..\locale\*.po-) do if not %%~ni==%PO% ren %%i %%~ni.po +goto end + +:updateALL +call sh --login %cd%\bmsg.sh + +:end +echo End of Message Bundling \ No newline at end of file diff --git a/apps/i2psnark/java/bundle-messages.sh b/apps/i2psnark/java/bundle-messages.sh new file mode 100755 index 000000000..01aa5b1c7 --- /dev/null +++ b/apps/i2psnark/java/bundle-messages.sh @@ -0,0 +1,85 @@ +# +# Update messages_xx.po and messages_xx.class files, +# from both java and jsp sources. +# Requires installed programs xgettext, msgfmt, msgmerge, and find. +# +# usage: +# bundle-messages.sh (generates the resource bundle from the .po file) +# bundle-messages.sh -p (updates the .po file from the source tags, then generates the resource bundle) +# +# zzz - public domain +# +CLASS=org.klomp.snark.web.messages +TMPFILE=build/javafiles.txt +export TZ=UTC + +if [ "$1" = "-p" ] +then + POUPDATE=1 +fi + +# add ../java/ so the refs will work in the po file +JPATHS="../java/src" +for i in ../locale/messages_*.po +do + # get language + LG=${i#../locale/messages_} + LG=${LG%.po} + + if [ "$POUPDATE" = "1" ] + then + # make list of java files newer than the .po file + find $JPATHS -name *.java -newer $i > $TMPFILE + fi + + if [ -s build/obj/org/klomp/snark/web/messages_$LG.class -a \ + build/obj/org/klomp/snark/web/messages_$LG.class -nt $i -a \ + ! -s $TMPFILE ] + then + continue + fi + + if [ "$POUPDATE" = "1" ] + then + echo "Updating the $i file from the tags..." + # extract strings from java and jsp files, and update messages.po files + # translate calls must be one of the forms: + # _("foo") + # _x("foo") + # To start a new translation, copy the header from an old translation to the new .po file, + # then ant distclean poupdate. + find $JPATHS -name *.java > $TMPFILE + xgettext -f $TMPFILE -F -L java --from-code=UTF-8 \ + --keyword=_ --keyword=_x \ + -o ${i}t + if [ $? -ne 0 ] + then + echo 'Warning - xgettext failed, not updating translations' + rm -f ${i}t + break + fi + msgmerge -U --backup=none $i ${i}t + if [ $? -ne 0 ] + then + echo 'Warning - msgmerge failed, not updating translations' + rm -f ${i}t + break + fi + rm -f ${i}t + # so we don't do this again + touch $i + fi + + echo "Generating ${CLASS}_$LG ResourceBundle..." + + # convert to class files in build/obj + msgfmt --java --statistics -r $CLASS -l $LG -d build/obj $i + if [ $? -ne 0 ] + then + echo 'Warning - msgfmt failed, not updating translations' + break + fi +done +rm -f $TMPFILE +# todo: return failure +exit 0 diff --git a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java index cbb1d1714..4cea2ae81 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java +++ b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java @@ -28,6 +28,7 @@ import net.i2p.util.FileUtil; import net.i2p.util.Log; import net.i2p.util.SimpleScheduler; import net.i2p.util.SimpleTimer; +import net.i2p.util.Translate; /** * I2P specific helpers for I2PSnark @@ -402,4 +403,32 @@ public class I2PSnarkUtil { break; } } + + private static final String BUNDLE_NAME = "org.klomp.snark.web.messages"; + + /** lang in routerconsole.lang property, else current locale */ + public String getString(String key) { + return Translate.getString(key, _context, BUNDLE_NAME); + } + + /** + * translate a string with a parameter + * This is a lot more expensive than getString(s, ctx), so use sparingly. + * + * @param s string to be translated containing {0} + * The {0} will be replaced by the parameter. + * Single quotes must be doubled, i.e. ' -> '' in the string. + * @param o parameter, not translated. + * To tranlslate parameter also, use _("foo {0} bar", _("baz")) + * Do not double the single quotes in the parameter. + * Use autoboxing to call with ints, longs, floats, etc. + */ + public String getString(String s, Object o) { + return Translate.getString(s, o, _context, BUNDLE_NAME); + } + + /** {0} and {1} */ + public String getString(String s, Object o, Object o2) { + return Translate.getString(s, o, o2, _context, BUNDLE_NAME); + } } diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index d83b54060..655282922 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -20,6 +20,7 @@ import net.i2p.data.Base64; import net.i2p.data.DataHelper; import net.i2p.util.I2PAppThread; import net.i2p.util.Log; +import net.i2p.util.OrderedProperties; /** * Manage multiple snarks @@ -80,7 +81,7 @@ public class SnarkManager implements Snark.CompleteListener { _peerCoordinatorSet = new PeerCoordinatorSet(); _connectionAcceptor = new ConnectionAcceptor(_util); int minutes = getStartupDelayMinutes(); - _messages.add("Adding torrents in " + minutes + (minutes == 1 ? " minute" : " minutes")); + _messages.add(_("Adding torrents in {0} minutes", minutes)); I2PAppThread monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor"); monitor.setDaemon(true); monitor.start(); @@ -126,7 +127,7 @@ public class SnarkManager implements Snark.CompleteListener { /** null to set initial defaults */ public void loadConfig(String filename) { if (_config == null) - _config = new Properties(); + _config = new OrderedProperties(); if (filename != null) { File cfg = new File(filename); if (!cfg.isAbsolute()) @@ -216,6 +217,7 @@ public class SnarkManager implements Snark.CompleteListener { String upLimit, String upBW, boolean useOpenTrackers, String openTrackers) { boolean changed = false; if (eepHost != null) { + // unused, we use socket eepget int port = _util.getEepProxyPort(); try { port = Integer.parseInt(eepPort); } catch (NumberFormatException nfe) {} String host = _util.getEepProxyHost(); @@ -236,9 +238,9 @@ public class SnarkManager implements Snark.CompleteListener { _util.setMaxUploaders(limit); changed = true; _config.setProperty(PROP_UPLOADERS_TOTAL, "" + limit); - addMessage("Total uploaders limit changed to " + limit); + addMessage(_("Total uploaders limit changed to {0}", limit)); } else { - addMessage("Minimum total uploaders limit is " + Snark.MIN_TOTAL_UPLOADERS); + addMessage(_("Minimum total uploaders limit is {0}", Snark.MIN_TOTAL_UPLOADERS)); } } } @@ -250,9 +252,9 @@ public class SnarkManager implements Snark.CompleteListener { _util.setMaxUpBW(limit); changed = true; _config.setProperty(PROP_UPBW_MAX, "" + limit); - addMessage("Up BW limit changed to " + limit + "KBps"); + addMessage(_("Up BW limit changed to {0}KBps", limit)); } else { - addMessage("Minimum Up BW limit is " + MIN_UP_BW + "KBps"); + addMessage(_("Minimum up bandwidth limit is {0}KBps", MIN_UP_BW)); } } } @@ -296,27 +298,27 @@ public class SnarkManager implements Snark.CompleteListener { } } if (snarksActive) { - addMessage("Cannot change the I2CP settings while torrents are active"); + addMessage(_("Cannot change the I2CP settings while torrents are active")); _log.debug("i2cp host [" + i2cpHost + "] i2cp port " + port + " opts [" + opts + "] oldOpts [" + oldOpts + "]"); } else { if (_util.connected()) { _util.disconnect(); - addMessage("Disconnecting old I2CP destination"); + addMessage(_("Disconnecting old I2CP destination")); } Properties p = new Properties(); p.putAll(opts); - addMessage("I2CP settings changed to " + i2cpHost + ":" + port + " (" + i2cpOpts.trim() + ")"); + addMessage(_("I2CP settings changed to {0}", i2cpHost + ":" + port + " (" + i2cpOpts.trim() + ")")); _util.setI2CPConfig(i2cpHost, port, p); boolean ok = _util.connect(); if (!ok) { - addMessage("Unable to connect with the new settings, reverting to the old I2CP settings"); + addMessage(_("Unable to connect with the new settings, reverting to the old I2CP settings")); _util.setI2CPConfig(oldI2CPHost, oldI2CPPort, oldOpts); ok = _util.connect(); if (!ok) - addMessage("Unable to reconnect with the old settings!"); + addMessage(_("Unable to reconnect with the old settings!")); } else { - addMessage("Reconnected on the new I2CP destination"); + addMessage(_("Reconnected on the new I2CP destination")); _config.setProperty(PROP_I2CP_HOST, i2cpHost.trim()); _config.setProperty(PROP_I2CP_PORT, "" + port); _config.setProperty(PROP_I2CP_OPTS, i2cpOpts.trim()); @@ -327,7 +329,7 @@ public class SnarkManager implements Snark.CompleteListener { Snark snark = getTorrent(name); if ( (snark != null) && (snark.acceptor != null) ) { snark.acceptor.restart(); - addMessage("I2CP listener restarted for " + snark.meta.getName()); + addMessage(_("I2CP listener restarted for \"{0}\"", snark.meta.getName())); } } } @@ -337,26 +339,32 @@ public class SnarkManager implements Snark.CompleteListener { } if (shouldAutoStart() != autoStart) { _config.setProperty(PROP_AUTO_START, autoStart + ""); - addMessage("Adjusted autostart to " + autoStart); + if (autoStart) + addMessage(_("Enabled autostart")); + else + addMessage(_("Disabled autostart")); changed = true; } if (_util.shouldUseOpenTrackers() != useOpenTrackers) { _config.setProperty(I2PSnarkUtil.PROP_USE_OPENTRACKERS, useOpenTrackers + ""); - addMessage((useOpenTrackers ? "En" : "Dis") + "abled open trackers - torrent restart required to take effect."); + if (useOpenTrackers) + addMessage(_("Enabled open trackers - torrent restart required to take effect.")); + else + addMessage(_("Disabled open trackers - torrent restart required to take effect.")); changed = true; } if (openTrackers != null) { if (openTrackers.trim().length() > 0 && !openTrackers.trim().equals(_util.getOpenTrackerString())) { _config.setProperty(I2PSnarkUtil.PROP_OPENTRACKERS, openTrackers.trim()); _util.setOpenTrackerString(openTrackers); - addMessage("Open Tracker list changed - torrent restart required to take effect."); + addMessage(_("Open Tracker list changed - torrent restart required to take effect.")); changed = true; } } if (changed) { saveConfig(); } else { - addMessage("Configuration unchanged."); + addMessage(_("Configuration unchanged.")); } } @@ -366,7 +374,7 @@ public class SnarkManager implements Snark.CompleteListener { DataHelper.storeProps(_config, _configFile); } } catch (IOException ioe) { - addMessage("Unable to save the config to '" + _configFile.getAbsolutePath() + "'."); + addMessage(_("Unable to save the config to {0}", _configFile.getAbsolutePath())); } } @@ -384,10 +392,10 @@ public class SnarkManager implements Snark.CompleteListener { public void addTorrent(String filename) { addTorrent(filename, false); } public void addTorrent(String filename, boolean dontAutoStart) { if ((!dontAutoStart) && !_util.connected()) { - addMessage("Connecting to I2P"); + addMessage(_("Connecting to I2P")); boolean ok = _util.connect(); if (!ok) { - addMessage("Error connecting to I2P - check your I2CP settings!"); + addMessage(_("Error connecting to I2P - check your I2CP settings!")); return; } } @@ -396,7 +404,7 @@ public class SnarkManager implements Snark.CompleteListener { filename = sfile.getCanonicalPath(); } catch (IOException ioe) { _log.error("Unable to add the torrent " + filename, ioe); - addMessage("ERR: Could not add the torrent '" + filename + "': " + ioe.getMessage()); + addMessage(_("Error: Could not add the torrent {0}", filename) + ": " + ioe.getMessage()); return; } File dataDir = getDataDir(); @@ -435,7 +443,7 @@ public class SnarkManager implements Snark.CompleteListener { } } } catch (IOException ioe) { - addMessage("Torrent in " + sfile.getName() + " is invalid: " + ioe.getMessage()); + addMessage(_("Torrent in \"{0}\" is invalid", sfile.getName()) + ": " + ioe.getMessage()); if (sfile.exists()) sfile.delete(); return; @@ -450,9 +458,9 @@ public class SnarkManager implements Snark.CompleteListener { File f = new File(filename); if (!dontAutoStart && shouldAutoStart()) { torrent.startTorrent(); - addMessage("Torrent added and started: '" + f.getName() + "'."); + addMessage(_("Torrent added and started: \"{0}\"", f.getName())); } else { - addMessage("Torrent added: '" + f.getName() + "'."); + addMessage(_("Torrent added: \"{0}\"", f.getName())); } } @@ -548,19 +556,19 @@ public class SnarkManager implements Snark.CompleteListener { // basic validation of url if ((!announce.startsWith("http://")) || (announce.indexOf(".i2p/") < 0)) // need to do better than this - return "Non-i2p tracker in " + info.getName() + ", deleting it from our list of trackers!"; + return _("Non-i2p tracker in \"{0}\", deleting it from our list of trackers!", info.getName()); List files = info.getFiles(); if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) { - return "Too many files in " + info.getName() + " (" + files.size() + "), deleting it!"; + return _("Too many files in \"{0}\" ({1}), deleting it!", info.getName(), files.size()); } else if ( (files == null) && (info.getName().endsWith(".torrent")) ) { - return "Torrent file " + info.getName() + " cannot end in '.torrent', deleting it!"; + return _("Torrent file \"{0}\" cannot end in '.torrent', deleting it!", info.getName()); } else if (info.getPieces() <= 0) { - return "No pieces in " + info.getName() + "? deleting it!"; + return _("No pieces in \"{0}\", deleting it!", info.getName()); } else if (info.getPieces() > Storage.MAX_PIECES) { - return "Too many pieces in " + info.getName() + ", limit is " + Storage.MAX_PIECES + ", deleting it!"; + return _("Too many pieces in \"{0}\", limit is {1}, deleting it!", info.getName(), Storage.MAX_PIECES); } else if (info.getPieceLength(0) > Storage.MAX_PIECE_SIZE) { - return "Pieces are too large in " + info.getName() + " (" + DataHelper.formatSize(info.getPieceLength(0)) + - "B, limit is " + DataHelper.formatSize(Storage.MAX_PIECE_SIZE) + "B), deleting it."; + return _("Pieces are too large in \"{0}\" ({1}B), deleting it.", info.getName(), DataHelper.formatSize(info.getPieceLength(0))) + ' ' + + _("Limit is {0}B", DataHelper.formatSize(Storage.MAX_PIECE_SIZE)); } else if (info.getTotalLength() > Storage.MAX_TOTAL_SIZE) { System.out.println("torrent info: " + info.toString()); List lengths = info.getLengths(); @@ -568,8 +576,7 @@ public class SnarkManager implements Snark.CompleteListener { for (int i = 0; i < lengths.size(); i++) System.out.println("File " + i + " is " + lengths.get(i) + " long."); - return "Torrents larger than " + DataHelper.formatSize(Storage.MAX_TOTAL_SIZE) + - "B are not supported yet (because we're paranoid): " + info.getName() + ", deleting it!"; + return _("Torrents larger than {0}B are not supported yet, deleting \"{1}\"", Storage.MAX_TOTAL_SIZE, info.getName()); } else { // ok return null; @@ -585,7 +592,7 @@ public class SnarkManager implements Snark.CompleteListener { filename = sfile.getCanonicalPath(); } catch (IOException ioe) { _log.error("Unable to remove the torrent " + filename, ioe); - addMessage("ERR: Could not remove the torrent '" + filename + "': " + ioe.getMessage()); + addMessage(_("Error: Could not remove the torrent {0}", filename) + ": " + ioe.getMessage()); return null; } int remaining = 0; @@ -606,7 +613,7 @@ public class SnarkManager implements Snark.CompleteListener { ////_util. } if (!wasStopped) - addMessage("Torrent stopped: '" + sfile.getName() + "'."); + addMessage(_("Torrent stopped: \"{0}\"", sfile.getName())); } return torrent; } @@ -621,7 +628,7 @@ public class SnarkManager implements Snark.CompleteListener { torrentFile.delete(); if (torrent.storage != null) removeTorrentStatus(torrent.storage.getMetaInfo()); - addMessage("Torrent removed: '" + torrentFile.getName() + "'."); + addMessage(_("Torrent removed: \"{0}\"", torrentFile.getName())); } } @@ -654,7 +661,7 @@ public class SnarkManager implements Snark.CompleteListener { public void torrentComplete(Snark snark) { File f = new File(snark.torrent); long len = snark.meta.getTotalLength(); - addMessage("Download finished: " + f.getName() + " (size: " + DataHelper.formatSize(len) + "B)"); + addMessage(_("Download finished: \"{0}\"", f.getName()) + " (" + _("size: {0}B", DataHelper.formatSize(len)) + ')'); updateStatus(snark); } @@ -682,7 +689,7 @@ public class SnarkManager implements Snark.CompleteListener { // already known. noop } else { if (shouldAutoStart() && !_util.connect()) - addMessage("Unable to connect to I2P!"); + addMessage(_("Unable to connect to I2P!")); addTorrent((String)foundNames.get(i), !shouldAutoStart()); } } @@ -698,6 +705,21 @@ public class SnarkManager implements Snark.CompleteListener { } } + /** translate */ + private String _(String s) { + return _util.getString(s); + } + + /** translate */ + private String _(String s, Object o) { + return _util.getString(s, o); + } + + /** translate */ + private String _(String s, Object o, Object o2) { + return _util.getString(s, o, o2); + } + /** * "name", "announceURL=websiteURL" pairs */ diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index a4ac23b43..2fbf10462 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -80,13 +80,25 @@ public class I2PSnarkServlet extends HttpServlet { } PrintWriter out = resp.getWriter(); - out.write(HEADER_BEGIN); + out.write("\n" + + "\n" + + ""); + out.write(_("I2PSnark - Anonymous BitTorrent Client")); + out.write("\n"); + // we want it to go to the base URI so we don't refresh with some funky action= value out.write("\n"); out.write(HEADER); out.write(""); out.write("
"); - out.write("
I2PSnark Forum\n"); + out.write("
"); + out.write(_("I2PSnark")); + out.write(" "); + out.write(_("Forum")); + out.write("\n"); + Map trackers = _manager.getTrackers(); for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) { Map.Entry entry = (Map.Entry)iter.next(); @@ -110,22 +122,51 @@ public class I2PSnarkServlet extends HttpServlet { List snarks = getSortedSnarks(req); String uri = req.getRequestURI(); out.write(TABLE_HEADER); + out.write(_("Status")); if (_manager.util().connected() && snarks.size() > 0) { - if (peerParam != null) - out.write("(Hide Peers)
\n"); - else - out.write("(Show Peers)
\n"); + out.write(" ("); + out.write(_("Hide Peers")); + } else { + out.write("?p=1\">"); + out.write(_("Show Peers")); + } + out.write(")
\n"); } - out.write(TABLE_HEADER2); + out.write("\n"); + out.write(_("Torrent")); + out.write("\n"); + out.write(_("ETA")); + out.write("\n"); + out.write(_("Downloaded")); + out.write("\n"); + out.write(_("Uploaded")); + out.write("\n"); + out.write(_("Down Rate")); + out.write("\n"); + out.write(_("Up Rate")); + out.write("\n"); + out.write(""); - if (_manager.util().connected()) + if (_manager.util().connected()) { out.write("Stop All"); - else if (snarks.size() > 0) + "\" title=\""); + out.write(_("Stop all torrents and the I2P tunnel")); + out.write("\">"); + out.write(_("Stop All")); + out.write(""); + } else if (snarks.size() > 0) { out.write("Start All"); - else + "\" title=\""); + out.write(_("Start all torrents and the I2P tunnel")); + out.write("\">"); + out.write(_("Start All")); + out.write(""); + } else { out.write(" "); + } out.write("\n"); for (int i = 0; i < snarks.size(); i++) { Snark snark = (Snark)snarks.get(i); @@ -133,14 +174,23 @@ public class I2PSnarkServlet extends HttpServlet { boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam); displaySnark(out, snark, uri, i, stats, showPeers, showDebug); } + if (snarks.size() <= 0) { - out.write(TABLE_EMPTY); + out.write("" + + ""); + out.write(_("No torrents loaded.")); + out.write("\n"); } else if (snarks.size() > 1) { out.write("\n" + - " Totals (" + - snarks.size() + " torrents, " + - DataHelper.formatSize(stats[5]) + "B, " + - stats[4] + " connected peers)\n" + + " "); + out.write(_("Totals")); + out.write(" ("); + out.write(_("{0} torrents", snarks.size())); + out.write(", "); + out.write(DataHelper.formatSize(stats[5]) + "B, "); + out.write(_("{0} connected peers", stats[4])); + out.write(")\n" + "  \n" + " " + formatSize(stats[0]) + "\n" + " " + formatSize(stats[1]) + "\n" + @@ -166,7 +216,7 @@ public class I2PSnarkServlet extends HttpServlet { String action = req.getParameter("action"); if (action == null) { // noop - } else if ("Add torrent".equals(action)) { + } else if ("Add".equals(action)) { String newFile = req.getParameter("newFile"); String newURL = req.getParameter("newURL"); // NOTE - newFile currently disabled in HTML form - see below @@ -174,7 +224,7 @@ public class I2PSnarkServlet extends HttpServlet { if ( (newFile != null) && (newFile.trim().length() > 0) ) f = new File(newFile.trim()); if ( (f != null) && (!f.exists()) ) { - _manager.addMessage("Torrent file " + newFile +" does not exist"); + _manager.addMessage(_("Torrent file {0} does not exist", newFile)); } if ( (f != null) && (f.exists()) ) { File local = new File(_manager.getDataDir(), f.getName()); @@ -184,16 +234,16 @@ public class I2PSnarkServlet extends HttpServlet { if (local.exists()) { if (_manager.getTorrent(canonical) != null) - _manager.addMessage("Torrent already running: " + newFile); + _manager.addMessage(_("Torrent already running: {0}", newFile)); else - _manager.addMessage("Torrent already in the queue: " + newFile); + _manager.addMessage(_("Torrent already in the queue: {0}", newFile)); } else { boolean ok = FileUtil.copy(f.getAbsolutePath(), local.getAbsolutePath(), true); if (ok) { - _manager.addMessage("Copying torrent to " + local.getAbsolutePath()); + _manager.addMessage(_("Copying torrent to {0}", local.getAbsolutePath())); _manager.addTorrent(canonical); } else { - _manager.addMessage("Unable to copy the torrent to " + local.getAbsolutePath() + " from " + f.getAbsolutePath()); + _manager.addMessage(_("Unable to copy the torrent to {0}", local.getAbsolutePath()) + ' ' + _("from {0}", f.getAbsolutePath())); } } } catch (IOException ioe) { @@ -201,11 +251,11 @@ public class I2PSnarkServlet extends HttpServlet { } } else if (newURL != null) { if (newURL.startsWith("http://")) { - _manager.addMessage("Fetching " + newURL); + _manager.addMessage(_("Fetching {0}", newURL)); I2PAppThread fetch = new I2PAppThread(new FetchAndAdd(_manager, newURL), "Fetch and add"); fetch.start(); } else { - _manager.addMessage("Invalid URL - must start with http://"); + _manager.addMessage(_("Invalid URL - must start with http://")); } } else { // no file or URL specified @@ -235,7 +285,7 @@ public class I2PSnarkServlet extends HttpServlet { Snark snark = _manager.getTorrent(name); if ( (snark != null) && (DataHelper.eq(infoHash, snark.meta.getInfoHash())) ) { snark.startTorrent(); - _manager.addMessage("Starting up torrent " + name); + _manager.addMessage(_("Starting up torrent {0}", name)); break; } } @@ -255,7 +305,7 @@ public class I2PSnarkServlet extends HttpServlet { // yeah, need to, otherwise it'll get autoadded again (at the moment File f = new File(name); f.delete(); - _manager.addMessage("Torrent file deleted: " + f.getAbsolutePath()); + _manager.addMessage(_("Torrent file deleted: {0}", f.getAbsolutePath())); break; } } @@ -273,15 +323,15 @@ public class I2PSnarkServlet extends HttpServlet { _manager.stopTorrent(name, true); File f = new File(name); f.delete(); - _manager.addMessage("Torrent file deleted: " + f.getAbsolutePath()); + _manager.addMessage(_("Torrent file deleted: {0}", f.getAbsolutePath())); List files = snark.meta.getFiles(); String dataFile = snark.meta.getName(); f = new File(_manager.getDataDir(), dataFile); if (files == null) { // single file torrent if (f.delete()) - _manager.addMessage("Data file deleted: " + f.getAbsolutePath()); + _manager.addMessage(_("Data file deleted: {0}", f.getAbsolutePath())); else - _manager.addMessage("Data file could not be deleted: " + f.getAbsolutePath()); + _manager.addMessage(_("Data file could not be deleted: {0}", f.getAbsolutePath())); break; } for (int i = 0; i < files.size(); i++) { // pass 1 delete files @@ -289,9 +339,9 @@ public class I2PSnarkServlet extends HttpServlet { // each of those lists just contain a single file afaict... File df = Storage.getFileFromNames(f, (List) files.get(i)); if (df.delete()) - _manager.addMessage("Data file deleted: " + df.getAbsolutePath()); + _manager.addMessage(_("Data file deleted: {0}", df.getAbsolutePath())); else - _manager.addMessage("Data file could not be deleted: " + df.getAbsolutePath()); + _manager.addMessage(_("Data file could not be deleted: {0}", df.getAbsolutePath())); } for (int i = files.size() - 1; i >= 0; i--) { // pass 2 delete dirs - not foolproof, // we could sort and do a strict bottom-up @@ -300,14 +350,14 @@ public class I2PSnarkServlet extends HttpServlet { if (df == null || !df.exists()) continue; if(df.delete()) - _manager.addMessage("Data dir deleted: " + df.getAbsolutePath()); + _manager.addMessage(_("Data dir deleted: {0}", df.getAbsolutePath())); } break; } } } } - } else if ("Save configuration".equals(action)) { + } else if ("Save".equals(action)) { String dataDir = req.getParameter("dataDir"); boolean autoStart = req.getParameter("autoStart") != null; String seedPct = req.getParameter("seedPct"); @@ -321,7 +371,7 @@ public class I2PSnarkServlet extends HttpServlet { boolean useOpenTrackers = req.getParameter("useOpenTrackers") != null; String openTrackers = req.getParameter("openTrackers"); _manager.updateConfig(dataDir, autoStart, seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts, upLimit, upBW, useOpenTrackers, openTrackers); - } else if ("Create torrent".equals(action)) { + } else if ("Create".equals(action)) { String baseData = req.getParameter("baseFile"); if (baseData != null && baseData.trim().length() > 0) { File baseFile = new File(_manager.getDataDir(), baseData); @@ -331,7 +381,7 @@ public class I2PSnarkServlet extends HttpServlet { announceURL = announceURLOther; if (announceURL == null || announceURL.length() <= 0) - _manager.addMessage("Error creating torrent - you must select a tracker"); + _manager.addMessage(_("Error creating torrent - you must select a tracker")); else if (baseFile.exists()) { try { Storage s = new Storage(_manager.util(), baseFile, announceURL, null); @@ -346,21 +396,21 @@ public class I2PSnarkServlet extends HttpServlet { FileOutputStream out = new FileOutputStream(torrentFile); out.write(info.getTorrentData()); out.close(); - _manager.addMessage("Torrent created for " + baseFile.getName() + ": " + torrentFile.getAbsolutePath()); + _manager.addMessage(_("Torrent created for \"{0}\"", baseFile.getName()) + ": " + torrentFile.getAbsolutePath()); // now fire it up, but don't automatically seed it _manager.addTorrent(torrentFile.getCanonicalPath(), true); - _manager.addMessage("Many I2P trackers require you to register new torrents before seeding - please do so before starting " + baseFile.getName()); + _manager.addMessage(_("Many I2P trackers require you to register new torrents before seeding - please do so before starting \"{0}\"", baseFile.getName())); } catch (IOException ioe) { - _manager.addMessage("Error creating a torrent for " + baseFile.getAbsolutePath() + ": " + ioe.getMessage()); + _manager.addMessage(_("Error creating a torrent for \"{0}\"", baseFile.getAbsolutePath()) + ": " + ioe.getMessage()); } } else { - _manager.addMessage("Cannot create a torrent for the nonexistent data: " + baseFile.getAbsolutePath()); + _manager.addMessage(_("Cannot create a torrent for the nonexistent data: {0}", baseFile.getAbsolutePath())); } } else { - _manager.addMessage("Error creating torrent - you must enter a file or directory"); + _manager.addMessage(_("Error creating torrent - you must enter a file or directory")); } } else if ("StopAll".equals(action)) { - _manager.addMessage("Stopping all torrents and closing the I2P tunnel."); + _manager.addMessage(_("Stopping all torrents and closing the I2P tunnel.")); List snarks = getSortedSnarks(req); for (int i = 0; i < snarks.size(); i++) { Snark snark = (Snark)snarks.get(i); @@ -369,10 +419,10 @@ public class I2PSnarkServlet extends HttpServlet { } if (_manager.util().connected()) { _manager.util().disconnect(); - _manager.addMessage("I2P tunnel closed."); + _manager.addMessage(_("I2P tunnel closed.")); } } else if ("StartAll".equals(action)) { - _manager.addMessage("Opening the I2P tunnel and starting all torrents."); + _manager.addMessage(_("Opening the I2P tunnel and starting all torrents.")); List snarks = getSortedSnarks(req); for (int i = 0; i < snarks.size(); i++) { Snark snark = (Snark)snarks.get(i); @@ -449,45 +499,45 @@ public class I2PSnarkServlet extends HttpServlet { knownPeers = snark.coordinator.trackerSeenPeers; } - String statusString = "Unknown"; + String statusString = _("Unknown"); if (err != null) { if (isRunning && curPeers > 0 && !showPeers) - statusString = "TrackerErr (" + + statusString = "" + _("TrackerErr") + " (" + curPeers + "/" + knownPeers + - " peers)"; + " " + _("peers") + ")"; else if (isRunning) - statusString = "TrackerErr (" + curPeers + "/" + knownPeers + " peers)"; + statusString = "" + _("TrackerErr") + " (" + curPeers + '/' + knownPeers + ' ' + _("peers") + ')'; else { if (err.length() > MAX_DISPLAYED_ERROR_LENGTH) err = err.substring(0, MAX_DISPLAYED_ERROR_LENGTH) + "…"; - statusString = "TrackerErr
(" + err + ")"; + statusString = _("TrackerErr") + "
(" + err + ")"; } } else if (remaining <= 0) { if (isRunning && curPeers > 0 && !showPeers) - statusString = "Seeding (" + - curPeers + "/" + knownPeers + - "
peers)"; + statusString = _("Seeding") + " (" + + curPeers + '/' + knownPeers + + " " + _("peers") + ")"; else if (isRunning) - statusString = "Seeding (" + curPeers + "/" + knownPeers + " peers)"; + statusString = _("Seeding") + " (" + curPeers + "/" + knownPeers + ' ' + _("peers") + ')'; else - statusString = "Complete"; + statusString = _("Complete"); } else { if (isRunning && curPeers > 0 && downBps > 0 && !showPeers) - statusString = "OK (" + + statusString = _("OK") + " (" + curPeers + "/" + knownPeers + - " peers)"; + " " + _("peers") + ")"; else if (isRunning && curPeers > 0 && downBps > 0) - statusString = "OK (" + curPeers + "/" + knownPeers + " peers)"; + statusString = _("OK") + " (" + curPeers + "/" + knownPeers + ' ' + _("peers") + ')'; else if (isRunning && curPeers > 0 && !showPeers) - statusString = "Stalled (" + - curPeers + "/" + knownPeers + - " peers)"; + statusString = _("Stalled") + " (" + + curPeers + '/' + knownPeers + + " " + _("peers") + ")"; else if (isRunning && curPeers > 0) - statusString = "Stalled (" + curPeers + "/" + knownPeers + " peers)"; + statusString = _("Stalled") + " (" + curPeers + '/' + knownPeers + ' ' + _("peers") + ')'; else if (isRunning) - statusString = "No Peers (0/" + knownPeers + ")"; + statusString = _("No Peers") + " (0/" + knownPeers + ')'; else - statusString = "Stopped"; + statusString = _("Stopped"); } String rowClass = (row % 2 == 0 ? "snarkTorrentEven" : "snarkTorrentOdd"); @@ -496,9 +546,15 @@ public class I2PSnarkServlet extends HttpServlet { out.write(statusString + "\n\t"); out.write(""); - if (remaining == 0) + if (remaining == 0) { out.write(""); + + "\" title=\""); + if (snark.meta.getFiles() != null) + out.write(_("View files")); + else + out.write(_("Open file")); + out.write("\">"); + } out.write(filename); if (remaining == 0) out.write(""); @@ -520,7 +576,9 @@ public class I2PSnarkServlet extends HttpServlet { baseURL = baseURL.substring(e + 1); out.write("   [Details]"); + out.write("\" title=\"" + name + ' ' + _("Tracker") + "\">"); + out.write(_("Details")); + out.write("]"); break; } } @@ -552,17 +610,35 @@ public class I2PSnarkServlet extends HttpServlet { parameters = parameters + "&p=1"; if (isRunning) { out.write("Stop"); + + "\" title=\""); + out.write(_("Stop the torrent")); + out.write("\">"); + out.write(_("Stop")); + out.write(""); } else { - if (isValid) + if (isValid) { out.write("Start "); + + "\" title=\""); + out.write(_("Start the torrent")); + out.write("\">"); + out.write(_("Start")); + out.write("\n"); + } out.write("Remove
"); + + "\" title=\""); + out.write(_("Remove the torrent from the active list, deleting the .torrent file")); + out.write("\">"); + out.write(_("Remove")); + out.write("
"); out.write("Delete "); + + "\" title=\""); + out.write(_("Delete the .torrent file and the associated data file(s)")); + out.write("\">"); + out.write(_("Delete")); + out.write(""); } out.write("\n\n"); + if(showPeers && isRunning && curPeers > 0) { List peers = snark.coordinator.peerList(); Iterator it = peers.iterator(); @@ -573,11 +649,11 @@ public class I2PSnarkServlet extends HttpServlet { out.write(""); out.write(""); out.write("\n\t"); - out.write(""); + out.write(""); String ch = peer.toString().substring(0, 4); String client; if ("AwMD".equals(ch)) - client = "I2PSnark"; + client = _("I2PSnark"); else if ("BFJT".equals(ch)) client = "I2PRufus"; else if ("TTMt".equals(ch)) @@ -591,7 +667,7 @@ public class I2PSnarkServlet extends HttpServlet { else if ("VUZP".equals(ch)) client = "Robert"; else - client = "Unknown (" + ch + ')'; + client = _("Unknown") + " (" + ch + ')'; out.write(client + "  " + peer.toString().substring(5, 9)); if (showDebug) out.write(" inactive " + (peer.getInactiveTime() / 1000) + "s"); @@ -601,7 +677,7 @@ public class I2PSnarkServlet extends HttpServlet { out.write(""); float pct = (float) (100.0 * (float) peer.completed() / snark.meta.getPieces()); if (pct == 100.0) - out.write("Seed"); + out.write(_("Seed")); else { String ps = String.valueOf(pct); if (ps.length() > 5) @@ -619,9 +695,10 @@ public class I2PSnarkServlet extends HttpServlet { } else { out.write(""); + out.write(_("Uninteresting (The peer has no pieces we need)")); else - out.write("Choked\">"); + out.write(_("Choked (The peer is not allowing us to request pieces)")); + out.write("\">"); out.write(formatSize(peer.getDownloadRate()) + "ps"); } } @@ -634,9 +711,10 @@ public class I2PSnarkServlet extends HttpServlet { } else { out.write(""); + out.write(_("Uninterested (We have no pieces the peer needs)")); else - out.write("Choking\">"); + out.write(_("Choking (We are not allowing the peer to request pieces)")); + out.write("\">"); out.write(formatSize(peer.getUploadRate()) + "ps"); } } @@ -659,14 +737,23 @@ public class I2PSnarkServlet extends HttpServlet { out.write("\n"); // *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file out.write("
\n"); - out.write("\n"); - out.write("
Add Torrent:
\n"); - out.write("From URL : \n"); + out.write("\n"); + out.write("\n"); + out.write("
"); + out.write(_("Add Torrent")); + out.write("
\n
"); + out.write(_("From URL")); + out.write(": \n"); // not supporting from file at the moment, since the file name passed isn't always absolute (so it may not resolve) //out.write("From file:
\n"); - out.write("
\n"); - out.write("Alternately, you can copy .torrent files to " + _manager.getDataDir().getAbsolutePath() + "
\n"); - out.write("Removing that .torrent file will cause the torrent to stop.
\n"); + out.write("
 
\n"); + out.write("
 "); + out.write(_("Alternately, you can copy .torrent files to the directory {0}.", _manager.getDataDir().getAbsolutePath())); + out.write("\n"); + out.write(_("Removing a .torrent file will cause the torrent to stop.")); + out.write("
\n"); out.write("\n
"); } @@ -679,13 +766,22 @@ public class I2PSnarkServlet extends HttpServlet { out.write("
\n"); // *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file out.write("
\n"); - out.write("\n"); - out.write("Create Torrent:
\n"); + out.write("\n"); + out.write("\n"); + out.write(""); + out.write(_("Create Torrent")); + out.write("
\n
"); //out.write("From file:
\n"); - out.write("Data to seed: " + _manager.getDataDir().getAbsolutePath() + File.separatorChar + out.write(_("Data to seed")); + out.write(":
" + _manager.getDataDir().getAbsolutePath() + File.separatorChar + "
\n"); - out.write("Tracker:
\n"); + out.write(_("Tracker")); + out.write(":\n"); - out.write("or "); - out.write("\n"); + out.write(_("or")); + out.write("
  "); + out.write("
 
\n"); out.write("
\n
"); } @@ -713,13 +814,28 @@ public class I2PSnarkServlet extends HttpServlet { out.write("
\n"); out.write("
\n"); - out.write("\n"); - out.write("Configuration:
\n"); - out.write("Data directory: (Edit i2psnark.config and restart to change)
\n"); - out.write("Auto start: \n"); + out.write("\n"); + out.write(""); + out.write(_("Configuration")); + out.write("
\n"); + out.write("
"); + out.write(_("Data directory")); + out.write(":
("); + out.write(_("Edit i2psnark.config and restart to change")); + out.write(")
\n"); + + out.write("
"); + out.write(_("Auto start")); + out.write(": "); + + "title=\""); + out.write(_("If checked, automatically start torrents that are added")); + out.write("\" >"); + //Auto add: //Auto stop: //out.write("
\n"); @@ -739,26 +855,51 @@ public class I2PSnarkServlet extends HttpServlet { out.write("\n\t"); out.write("
\n"); */ - out.write("Total uploader limit: peers
\n"); - out.write("Up bandwidth limit: KBps (Half available bandwidth recommended.)
\n"); + out.write("
"); + out.write(_("Total uploader limit")); + out.write(": "); + out.write(_("peers")); + out.write("
\n"); + + out.write("
"); + out.write(_("Up bandwidth limit")); + out.write(": KBps ("); + out.write(_("Half available bandwidth recommended.")); + out.write(" "); + out.write(_("View or change router bandwidth")); + out.write(")
\n"); - out.write("Use open trackers also:
"); + out.write(_("Use open trackers also")); + out.write(": "); - out.write("Announce URLs:
\n"); + + "title=\""); + out.write(_("If checked, announce torrents to open trackers as well as the tracker listed in the torrent file")); + out.write("\" > "); + + out.write("
"); + out.write(_("Open tracker announce URLs")); + out.write(":
\n"); //out.write("\n"); //out.write("EepProxy host: "); //out.write("port:
\n"); - out.write("I2CP host: "); - out.write("port:
\n"); + + out.write("
"); + out.write(_("I2CP host")); + out.write(": "); + + out.write("
"); + out.write(_("I2CP port")); + out.write(":
\n"); + StringBuilder opts = new StringBuilder(64); Map options = new TreeMap(_manager.util().getI2CPOptions()); for (Iterator iter = options.entrySet().iterator(); iter.hasNext(); ) { @@ -767,13 +908,28 @@ public class I2PSnarkServlet extends HttpServlet { String val = (String)entry.getValue(); opts.append(key).append('=').append(val).append(' '); } - out.write("I2CP opts:
\n"); - out.write("\n"); - out.write("\n"); + out.write("
"); + out.write(_("I2CP options")); + out.write(":
\n"); + + out.write("
 \n"); + out.write("
\n"); out.write("
"); } + /** translate */ + private String _(String s) { + return _manager.util().getString(s); + } + + /** translate */ + private String _(String s, Object o) { + return _manager.util().getString(s, o); + } + // rounding makes us look faster :) private String formatSize(long bytes) { if (bytes < 5*1024) @@ -786,28 +942,12 @@ public class I2PSnarkServlet extends HttpServlet { return ((bytes + 512*1024*1024)/(1024*1024*1024)) + "GB"; } - private static final String HEADER_BEGIN = "\n" + - "\n" + - "I2PSnark - Anonymous BitTorrent Client\n"; - - private static final String HEADER = ""; + private static final String HEADER = ""; private static final String TABLE_HEADER = "\n" + "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n"; - - private static final String TABLE_EMPTY = "" + - "\n"; + "
Status \n"; - - private static final String TABLE_HEADER2 = "TorrentETADownloadedUploadedDown RateUp Rate
No torrents loaded.
"; private static final String TABLE_FOOTER = "
\n"; @@ -827,12 +967,13 @@ private static class FetchAndAdd implements Runnable { File file = _manager.util().get(_url, false, 3); try { if ( (file != null) && (file.exists()) && (file.length() > 0) ) { - _manager.addMessage("Torrent fetched from " + _url); + _manager.addMessage(_("Torrent fetched from {0}", _url)); FileInputStream in = null; try { in = new FileInputStream(file); MetaInfo info = new MetaInfo(in); String name = info.getName(); + name = DataHelper.stripHTML(name); // XSS name = name.replace('/', '_'); name = name.replace('\\', '_'); name = name.replace('&', '+'); @@ -846,25 +987,30 @@ private static class FetchAndAdd implements Runnable { if (torrentFile.exists()) { if (_manager.getTorrent(canonical) != null) - _manager.addMessage("Torrent already running: " + name); + _manager.addMessage(_("Torrent already running: {0}", name)); else - _manager.addMessage("Torrent already in the queue: " + name); + _manager.addMessage(_("Torrent already in the queue: {0}", name)); } else { FileUtil.copy(file.getAbsolutePath(), canonical, true); _manager.addTorrent(canonical); } } catch (IOException ioe) { - _manager.addMessage("Torrent at " + _url + " was not valid: " + ioe.getMessage()); + _manager.addMessage(_("Torrent at {0} was not valid", _url) + ": " + ioe.getMessage()); } finally { try { in.close(); } catch (IOException ioe) {} } } else { - _manager.addMessage("Torrent was not retrieved from " + _url); + _manager.addMessage(_("Torrent was not retrieved from {0}", _url)); } } finally { if (file != null) file.delete(); } } + + private String _(String s, String o) { + return _manager.util().getString(s, o); + } + } } diff --git a/apps/i2psnark/locale/messages_de.po b/apps/i2psnark/locale/messages_de.po new file mode 100644 index 000000000..e238b3cf6 --- /dev/null +++ b/apps/i2psnark/locale/messages_de.po @@ -0,0 +1,655 @@ +# I2P +# Copyright (C) 2009 The I2P Project +# This file is distributed under the same license as the i2psnark package. +# To contribute translations, see http://www.i2p2.de/newdevelopers +# foo , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: I2P i2psnark\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-12-10 17:41+0000\n" +"PO-Revision-Date: 2009-10-19 12:50+0000\n" +"Last-Translator: foo \n" +"Language-Team: foo \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: German\n" + +#: ../java/src/org/klomp/snark/SnarkManager.java:84 +#, java-format +msgid "Adding torrents in {0} minutes" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:241 +#, java-format +msgid "Total uploaders limit changed to {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:243 +#, java-format +msgid "Minimum total uploaders limit is {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:255 +#, java-format +msgid "Up BW limit changed to {0}KBps" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:257 +#, java-format +msgid "Minimum up bandwidth limit is {0}KBps" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:301 +msgid "Cannot change the I2CP settings while torrents are active" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:307 +msgid "Disconnecting old I2CP destination" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:311 +#, java-format +msgid "I2CP settings changed to {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:315 +msgid "" +"Unable to connect with the new settings, reverting to the old I2CP settings" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:319 +msgid "Unable to reconnect with the old settings!" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:321 +msgid "Reconnected on the new I2CP destination" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:332 +#, java-format +msgid "I2CP listener restarted for \"{0}\"" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:343 +msgid "Enabled autostart" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:345 +msgid "Disabled autostart" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:351 +msgid "Enabled open trackers - torrent restart required to take effect." +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:353 +msgid "Disabled open trackers - torrent restart required to take effect." +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:360 +msgid "Open Tracker list changed - torrent restart required to take effect." +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:367 +msgid "Configuration unchanged." +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:377 +#, java-format +msgid "Unable to save the config to {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:395 +msgid "Connecting to I2P" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:398 +msgid "Error connecting to I2P - check your I2CP settings!" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:407 +#, java-format +msgid "Error: Could not add the torrent {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:446 +#, java-format +msgid "Torrent in \"{0}\" is invalid" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:461 +#, java-format +msgid "Torrent added and started: \"{0}\"" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:463 +#, java-format +msgid "Torrent added: \"{0}\"" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:559 +#, java-format +msgid "Non-i2p tracker in \"{0}\", deleting it from our list of trackers!" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:562 +#, java-format +msgid "Too many files in \"{0}\" ({1}), deleting it!" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:564 +#, java-format +msgid "Torrent file \"{0}\" cannot end in '.torrent', deleting it!" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:566 +#, java-format +msgid "No pieces in \"{0}\", deleting it!" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:568 +#, java-format +msgid "Too many pieces in \"{0}\", limit is {1}, deleting it!" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:570 +#, java-format +msgid "Pieces are too large in \"{0}\" ({1}B), deleting it." +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:571 +#, java-format +msgid "Limit is {0}B" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:579 +#, java-format +msgid "Torrents larger than {0}B are not supported yet, deleting \"{1}\"" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:595 +#, java-format +msgid "Error: Could not remove the torrent {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:616 +#, java-format +msgid "Torrent stopped: \"{0}\"" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:631 +#, java-format +msgid "Torrent removed: \"{0}\"" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:664 +#, java-format +msgid "Download finished: \"{0}\"" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:664 +#, java-format +msgid "size: {0}B" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:692 +msgid "Unable to connect to I2P!" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:86 +msgid "I2PSnark - Anonymous BitTorrent Client" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:95 +msgid "Refresh page" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:97 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:655 +msgid "I2PSnark" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:99 +msgid "Forum" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:125 +msgid "Status" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:132 +msgid "Hide Peers" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:134 +msgid "Show Peers" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:138 +msgid "Torrent" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:140 +msgid "ETA" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:142 +msgid "Downloaded" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:144 +msgid "Uploaded" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:146 +msgid "Down Rate" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:148 +msgid "Up Rate" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:155 +msgid "Stop all torrents and the I2P tunnel" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:157 +msgid "Stop All" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:162 +msgid "Start all torrents and the I2P tunnel" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:164 +msgid "Start All" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:181 +msgid "No torrents loaded." +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:186 +msgid "Totals" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:188 +#, java-format +msgid "{0} torrents" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:191 +#, java-format +msgid "{0} connected peers" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:218 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:748 +msgid "Add torrent" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:226 +#, java-format +msgid "Torrent file {0} does not exist" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:236 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:985 +#, java-format +msgid "Torrent already running: {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:238 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:987 +#, java-format +msgid "Torrent already in the queue: {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:242 +#, java-format +msgid "Copying torrent to {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:245 +#, java-format +msgid "Unable to copy the torrent to {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:245 +#, java-format +msgid "from {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:253 +#, java-format +msgid "Fetching {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:257 +msgid "Invalid URL - must start with http://" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:262 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:615 +msgid "Stop" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:277 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:623 +msgid "Start" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:287 +#, java-format +msgid "Starting up torrent {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:307 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:325 +#, java-format +msgid "Torrent file deleted: {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:331 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:341 +#, java-format +msgid "Data file deleted: {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:333 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:343 +#, java-format +msgid "Data file could not be deleted: {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:352 +#, java-format +msgid "Data dir deleted: {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:359 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:913 +msgid "Save configuration" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:373 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:799 +msgid "Create torrent" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:383 +msgid "Error creating torrent - you must select a tracker" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:398 +#, java-format +msgid "Torrent created for \"{0}\"" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:401 +#, java-format +msgid "" +"Many I2P trackers require you to register new torrents before seeding - " +"please do so before starting \"{0}\"" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:403 +#, java-format +msgid "Error creating a torrent for \"{0}\"" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:406 +#, java-format +msgid "Cannot create a torrent for the nonexistent data: {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:409 +msgid "Error creating torrent - you must enter a file or directory" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:412 +msgid "Stopping all torrents and closing the I2P tunnel." +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:421 +msgid "I2P tunnel closed." +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:424 +msgid "Opening the I2P tunnel and starting all torrents." +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:501 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:669 +msgid "Unknown" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:504 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:508 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:512 +msgid "TrackerErr" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:506 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:508 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:518 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:527 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:529 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:533 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:535 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:858 +msgid "peers" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:516 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:520 +msgid "Seeding" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:522 +msgid "Complete" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:525 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:529 +msgid "OK" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:531 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:535 +msgid "Stalled" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:537 +msgid "No Peers" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:539 +msgid "Stopped" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:552 +msgid "View files" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:554 +msgid "Open file" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:578 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:778 +msgid "Tracker" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:579 +msgid "Details" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:613 +msgid "Stop the torrent" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:621 +msgid "Start the torrent" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:628 +msgid "Remove the torrent from the active list, deleting the .torrent file" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:630 +msgid "Remove" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:634 +msgid "Delete the .torrent file and the associated data file(s)" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:636 +msgid "Delete" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:679 +msgid "Seed" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:697 +msgid "Uninteresting" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:699 +msgid "Choked" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:713 +msgid "Uninterested" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:715 +msgid "Choking" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:741 +msgid "Add Torrent" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:743 +msgid "From URL" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:751 +#, java-format +msgid "Alternately, you can copy .torrent files to {0} ." +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:753 +msgid "Removing a .torrent file will cause the torrent to stop." +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:769 +msgid "Create Torrent" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:772 +msgid "Data to seed" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:776 +msgid "File to seed (must be within the specified path)" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:780 +msgid "Select a tracker" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:793 +msgid "or" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:796 +msgid "Custom tracker URL" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:816 +msgid "Configuration" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:819 +msgid "Data directory" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:822 +msgid "Directory to store torrents and data" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:824 +msgid "Edit i2psnark.config and restart to change" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:828 +msgid "Auto start" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:832 +msgid "If checked, automatically start torrents that are added" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:855 +msgid "Total uploader limit" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:862 +msgid "Up bandwidth limit" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:865 +msgid "Half available bandwidth< recommended." +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:867 +msgid "Configure" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:871 +msgid "Use open trackers also" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:875 +msgid "" +"If checked, announce torrents to open trackers as well as the tracker listed " +"in the torrent file" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:879 +msgid "Open tracker announce URLs" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:890 +msgid "I2CP host" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:895 +msgid "I2CP port" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:908 +msgid "I2CP options" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:966 +#, java-format +msgid "Torrent fetched from {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:993 +#, java-format +msgid "Torrent at {0} was not valid" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:998 +#, java-format +msgid "Torrent was not retrieved from {0}" +msgstr "" diff --git a/apps/i2psnark/locale/messages_ru.po b/apps/i2psnark/locale/messages_ru.po new file mode 100644 index 000000000..3e7ab41b1 --- /dev/null +++ b/apps/i2psnark/locale/messages_ru.po @@ -0,0 +1,648 @@ +# I2P +# Copyright (C) 2009 The I2P Project +# This file is distributed under the same license as the i2psnark package. +# To contribute translations, see http://www.i2p2.de/newdevelopers +# foo , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: I2P i2psnark\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-12-14 03:19+0000\n" +"PO-Revision-Date: 2009-12-20 07:03+0000\n" +"Last-Translator: 4get \n" +"Language-Team: foo \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Russian\n" + +#: ../java/src/org/klomp/snark/SnarkManager.java:84 +#, java-format +msgid "Adding torrents in {0} minutes" +msgstr "Торренты будут подгружены через {0} минут(ы)" + +#: ../java/src/org/klomp/snark/SnarkManager.java:241 +#, java-format +msgid "Total uploaders limit changed to {0}" +msgstr "Новое значение лимита количества слотов отдачи: {0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:243 +#, java-format +msgid "Minimum total uploaders limit is {0}" +msgstr "Минимально допустимое значение для количества слотов: {0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:255 +#, java-format +msgid "Up BW limit changed to {0}KBps" +msgstr "Новое значение лимита скорости отдачи: {0} KBps" + +#: ../java/src/org/klomp/snark/SnarkManager.java:257 +#, java-format +msgid "Minimum up bandwidth limit is {0}KBps" +msgstr "Минимально допустимое значение для лимита скорости отдачи: {0} KBps" + +#: ../java/src/org/klomp/snark/SnarkManager.java:301 +msgid "Cannot change the I2CP settings while torrents are active" +msgstr "Невозможно изменить настройки I2CP пока есть активные торренты" + +#: ../java/src/org/klomp/snark/SnarkManager.java:307 +msgid "Disconnecting old I2CP destination" +msgstr "Рассоединяемся по старому адресу I2CP" + +#: ../java/src/org/klomp/snark/SnarkManager.java:311 +#, java-format +msgid "I2CP settings changed to {0}" +msgstr "Новые параметры I2CP: {0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:315 +msgid "Unable to connect with the new settings, reverting to the old I2CP settings" +msgstr "Не удалось соединиться с использованием новых настроек I2CP, возвращаемся к старым настройкам" + +#: ../java/src/org/klomp/snark/SnarkManager.java:319 +msgid "Unable to reconnect with the old settings!" +msgstr "Не удалось пересоединиться с использованием старых настроек I2CP!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:321 +msgid "Reconnected on the new I2CP destination" +msgstr "Пересоединились по новому адресу I2CP" + +#: ../java/src/org/klomp/snark/SnarkManager.java:332 +#, java-format +msgid "I2CP listener restarted for \"{0}\"" +msgstr "I2CP-приёмник перезапущен для \"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:343 +msgid "Enabled autostart" +msgstr "Автостарт включен" + +#: ../java/src/org/klomp/snark/SnarkManager.java:345 +msgid "Disabled autostart" +msgstr "Автостарт выключен" + +#: ../java/src/org/klomp/snark/SnarkManager.java:351 +msgid "Enabled open trackers - torrent restart required to take effect." +msgstr "Включено использование открытых трекеров. Требуется перезапуск торрента, чтобы изменения вступили в силу." + +#: ../java/src/org/klomp/snark/SnarkManager.java:353 +msgid "Disabled open trackers - torrent restart required to take effect." +msgstr "Отключено использование открытых трекеров. Требуется перезапуск торрента, чтобы изменения вступили в силу." + +#: ../java/src/org/klomp/snark/SnarkManager.java:360 +msgid "Open Tracker list changed - torrent restart required to take effect." +msgstr "Изменен список открытых трекеров. Требуется перезапуск торрента, чтобы изменения вступили в силу." + +#: ../java/src/org/klomp/snark/SnarkManager.java:367 +msgid "Configuration unchanged." +msgstr "Настройки не изменились." + +#: ../java/src/org/klomp/snark/SnarkManager.java:377 +#, java-format +msgid "Unable to save the config to {0}" +msgstr "Не удалось сохранить настройки в {0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:395 +msgid "Connecting to I2P" +msgstr "Устанавливается соединение с I2P" + +#: ../java/src/org/klomp/snark/SnarkManager.java:398 +msgid "Error connecting to I2P - check your I2CP settings!" +msgstr "Ошибка соединения с I2P, проверьте настройки I2CP!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:407 +#, java-format +msgid "Error: Could not add the torrent {0}" +msgstr "Ошибка: Не удалось добавить торрент {0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:446 +#, java-format +msgid "Torrent in \"{0}\" is invalid" +msgstr "Торрент в \"{0}\" некорректен" + +#: ../java/src/org/klomp/snark/SnarkManager.java:461 +#, java-format +msgid "Torrent added and started: \"{0}\"" +msgstr "Торрент добавлен и запущен: \"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:463 +#, java-format +msgid "Torrent added: \"{0}\"" +msgstr "Торрент добавлен: \"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:559 +#, java-format +msgid "Non-i2p tracker in \"{0}\", deleting it from our list of trackers!" +msgstr "Обнаружен не-I2P трекер в торренте \"{0}\", удаляем его из нашего списка трекеров!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:562 +#, java-format +msgid "Too many files in \"{0}\" ({1}), deleting it!" +msgstr "Слишком много файлов в торренте \"{0}\" ({1}), удаляем его!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:564 +#, java-format +msgid "Torrent file \"{0}\" cannot end in '.torrent', deleting it!" +msgstr "Торрент \"{0}\" содержит единственный файл заканчивающийся на '.torrent', удаляем его!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:566 +#, java-format +msgid "No pieces in \"{0}\", deleting it!" +msgstr "В торренте \"{0}\" не оказалось ни одной части, удаляем его!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:568 +#, java-format +msgid "Too many pieces in \"{0}\", limit is {1}, deleting it!" +msgstr "Слишком много частей в торренте \"{0}\" (наш предел {1}), удаляем его!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:570 +#, java-format +msgid "Pieces are too large in \"{0}\" ({1}B), deleting it." +msgstr "Слишком крупные части в торренте \"{0}\" ({1}B), удаляем его." + +#: ../java/src/org/klomp/snark/SnarkManager.java:571 +#, java-format +msgid "Limit is {0}B" +msgstr "Наш предел {0}B" + +#: ../java/src/org/klomp/snark/SnarkManager.java:579 +#, java-format +msgid "Torrents larger than {0}B are not supported yet, deleting \"{1}\"" +msgstr "Торренты крупнее чем {0}B пока не поддерживается, удаляем \"{1}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:595 +#, java-format +msgid "Error: Could not remove the torrent {0}" +msgstr "Ошибка: Невозможно удалить торрент {0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:616 +#, java-format +msgid "Torrent stopped: \"{0}\"" +msgstr "Торрент остановлен: \"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:631 +#, java-format +msgid "Torrent removed: \"{0}\"" +msgstr "Торрент удален: \"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:664 +#, java-format +msgid "Download finished: \"{0}\"" +msgstr "Завершена загрузка: \"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:664 +#, java-format +msgid "size: {0}B" +msgstr "размер: {0}B" + +#: ../java/src/org/klomp/snark/SnarkManager.java:692 +msgid "Unable to connect to I2P!" +msgstr "Не удалось установить соединение с I2P!" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:86 +msgid "I2PSnark - Anonymous BitTorrent Client" +msgstr "I2PSnark — Анонимный BitTorrent Клиент" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:95 +msgid "Refresh page" +msgstr "Обновить страницу" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:97 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:656 +msgid "I2PSnark" +msgstr "I2PSnark" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:99 +msgid "Forum" +msgstr "Форум" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:125 +msgid "Status" +msgstr "Статус" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:131 +msgid "Hide Peers" +msgstr "спрятать список пиров" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:134 +msgid "Show Peers" +msgstr "показать список пиров" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:139 +msgid "Torrent" +msgstr "Торрент" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:141 +msgid "ETA" +msgstr "Осталось" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:143 +msgid "Downloaded" +msgstr "Получено" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:145 +msgid "Uploaded" +msgstr "Отдано" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:147 +msgid "Down Rate" +msgstr "Скорость загрузки" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:149 +msgid "Up Rate" +msgstr "Скорость отдачи" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:156 +msgid "Stop all torrents and the I2P tunnel" +msgstr "Остановить все торренты и закрыть соединение с I2P" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:158 +msgid "Stop All" +msgstr "Остановить все" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:163 +msgid "Start all torrents and the I2P tunnel" +msgstr "Запустить все торренты и открыть соединение с I2P" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:165 +msgid "Start All" +msgstr "Запустить все" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:182 +msgid "No torrents loaded." +msgstr "Нет загруженных торрентов." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:187 +msgid "Totals" +msgstr "Всего" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:189 +#, java-format +msgid "{0} torrents" +msgstr "{0} торрентов" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:192 +#, java-format +msgid "{0} connected peers" +msgstr "{0} подсоединенных пиров" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:227 +#, java-format +msgid "Torrent file {0} does not exist" +msgstr "Торрент {0} не существует" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:237 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:986 +#, java-format +msgid "Torrent already running: {0}" +msgstr "Торрент уже запущен: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:239 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:988 +#, java-format +msgid "Torrent already in the queue: {0}" +msgstr "Торрент уже в очереди: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:243 +#, java-format +msgid "Copying torrent to {0}" +msgstr "Копируем торрент в: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:246 +#, java-format +msgid "Unable to copy the torrent to {0}" +msgstr "Не удалось скопировать торрент в: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:246 +#, java-format +msgid "from {0}" +msgstr "из: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:254 +#, java-format +msgid "Fetching {0}" +msgstr "Получение торрента: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:258 +msgid "Invalid URL - must start with http://" +msgstr "Некорректный URL, должен начинаться с http://" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:288 +#, java-format +msgid "Starting up torrent {0}" +msgstr "Запускаем торрент: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:308 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:326 +#, java-format +msgid "Torrent file deleted: {0}" +msgstr "Удален торрент: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:332 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:342 +#, java-format +msgid "Data file deleted: {0}" +msgstr "Файл удален: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:334 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:344 +#, java-format +msgid "Data file could not be deleted: {0}" +msgstr "Не удалось удалить файл: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:353 +#, java-format +msgid "Data dir deleted: {0}" +msgstr "Директория удалена: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:384 +msgid "Error creating torrent - you must select a tracker" +msgstr "Торрент не создан — вы должны указать трекер" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:399 +#, java-format +msgid "Torrent created for \"{0}\"" +msgstr "Создан торрент для \"{0}\"" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:402 +#, java-format +msgid "Many I2P trackers require you to register new torrents before seeding - please do so before starting \"{0}\"" +msgstr "Многие I2P трекеры требуют зарегистрировать на них торрент перед началом раздачи — пожалуйста проверьте требуется ли это перед запуском \"{0}\"" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:404 +#, java-format +msgid "Error creating a torrent for \"{0}\"" +msgstr "Ошибка при создании торрента для: \"{0}\"" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:407 +#, java-format +msgid "Cannot create a torrent for the nonexistent data: {0}" +msgstr "Невозможно создать торрент для несуществующего файла или директории: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:410 +msgid "Error creating torrent - you must enter a file or directory" +msgstr "Торрент не создан — вы должны указать файл или директорию" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:413 +msgid "Stopping all torrents and closing the I2P tunnel." +msgstr "Останавливаем все торренты и закрываем соединение с I2P" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:422 +msgid "I2P tunnel closed." +msgstr "Соединение с I2P закрыто." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:425 +msgid "Opening the I2P tunnel and starting all torrents." +msgstr "Соединяемся с I2P и запускаем все торренты." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:502 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:670 +msgid "Unknown" +msgstr "Неизвестный" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:505 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:509 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:513 +msgid "TrackerErr" +msgstr "ОшибкаТрекера" + +# TODO should replace "uploader limit NN peers" with "global number of upload slots: NN" +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:507 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:509 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:519 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:521 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:528 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:530 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:534 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:536 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:859 +msgid "peers" +msgstr "пир." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:517 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:521 +msgid "Seeding" +msgstr "Раздается" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:523 +msgid "Complete" +msgstr "Завершен" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:526 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:530 +msgid "OK" +msgstr "Загружается" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:532 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:536 +msgid "Stalled" +msgstr "Простаивает" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:538 +msgid "No Peers" +msgstr "Нет Пиров" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:540 +msgid "Stopped" +msgstr "Остановлен" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:553 +msgid "View files" +msgstr "Открыть директорию" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:555 +msgid "Open file" +msgstr "Открыть файл" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:579 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:779 +msgid "Tracker" +msgstr "Трекер" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:580 +msgid "Details" +msgstr "Подробнее" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:614 +msgid "Stop the torrent" +msgstr "Остановить торрент" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:616 +msgid "Stop" +msgstr "Остановить" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:622 +msgid "Start the torrent" +msgstr "Запустить торрент" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:624 +msgid "Start" +msgstr "Запустить" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:629 +msgid "Remove the torrent from the active list, deleting the .torrent file" +msgstr "Удалить торрент из списка и с диска" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:631 +msgid "Remove" +msgstr "Удалить" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:635 +msgid "Delete the .torrent file and the associated data file(s)" +msgstr "Удалить торрент и стереть загруженные файлы" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:637 +msgid "Delete" +msgstr "Стереть" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:680 +msgid "Seed" +msgstr "Сид" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:698 +msgid "Uninteresting (The peer has no pieces we need)" +msgstr "Uninteresting (У пира нет нужных нам частей торрента)" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:700 +msgid "Choked (The peer is not allowing us to request pieces)" +msgstr "Choked (Этот пир не позволяет нам запрашивать части торрента)" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:714 +msgid "Uninterested (We have no pieces the peer needs)" +msgstr "Uninterested (У нас нужных этому пиру частей торрента)" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:716 +msgid "Choking (We are not allowing the peer to request pieces)" +msgstr "Choking (Мы не позволяем этому пиру запрашивать у нас части торрента)" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:742 +msgid "Add Torrent" +msgstr "Добавить Торрент" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:744 +msgid "From URL" +msgstr "Из URL" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:749 +msgid "Add torrent" +msgstr "Добавить торрент" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:752 +#, java-format +msgid "Alternately, you can copy .torrent files to the directory {0}." +msgstr "Ну или вы можете скопировать .torrent-файлы в директорию {0}." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:754 +msgid "Removing a .torrent file will cause the torrent to stop." +msgstr "Удаление .torrent-файла приведет к остановке торрента." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:770 +msgid "Create Torrent" +msgstr "Создать Торрент" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:773 +msgid "Data to seed" +msgstr "Файлы для раздачи" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:777 +msgid "File or directory to seed (must be within the specified path)" +msgstr "Файл или директория для раздачи (вводите только название файла или директории, указание абсолютных путей не поддерживается)" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:781 +msgid "Select a tracker" +msgstr "Выбрать трекер" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:794 +msgid "or" +msgstr "или" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:797 +msgid "Specify custom tracker announce URL" +msgstr "Задать URL анонсера вручную" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:800 +msgid "Create torrent" +msgstr "Создать торрент" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:817 +msgid "Configuration" +msgstr "Настройки" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:820 +msgid "Data directory" +msgstr "Директория для файлов" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:823 +msgid "Directory to store torrents and data" +msgstr "Директория, где будут храниться торренты и загружаемые файлы" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:825 +msgid "Edit i2psnark.config and restart to change" +msgstr "Для изменения отредактируйте файл i2psnark.config и перезагрузите I2PSnark" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:829 +msgid "Auto start" +msgstr "Автозапуск" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:833 +msgid "If checked, automatically start torrents that are added" +msgstr "Автоматически запускать торренты после добавления" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:856 +msgid "Total uploader limit" +msgstr "Ограничение количества слотов отдачи" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:863 +msgid "Up bandwidth limit" +msgstr "Ограничение скорости отдачи" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:866 +msgid "Half available bandwidth recommended." +msgstr "Рекомендуется использовать половину от доступной пропускной способности." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:868 +msgid "View or change router bandwidth" +msgstr "Посмотреть/настроить ограничения скорости в маршрутизаторе I2P" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:872 +msgid "Use open trackers also" +msgstr "Дополнительно использовать открытые трекеры" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:876 +msgid "If checked, announce torrents to open trackers as well as the tracker listed in the torrent file" +msgstr "Анонсировать торренты на открытых трекерах, дополнительно к тем, что указаны внутри торрента" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:880 +msgid "Open tracker announce URLs" +msgstr "URL открытых трекеров" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:891 +msgid "I2CP host" +msgstr "Адрес I2CP" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:896 +msgid "I2CP port" +msgstr "Порт I2CP" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:909 +msgid "I2CP options" +msgstr "Параметры I2CP" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:914 +msgid "Save configuration" +msgstr "Сохранить настройки" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:967 +#, java-format +msgid "Torrent fetched from {0}" +msgstr "Получен торрент из: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:994 +#, java-format +msgid "Torrent at {0} was not valid" +msgstr "Торрент полученный из {0} некорректен" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:999 +#, java-format +msgid "Torrent was not retrieved from {0}" +msgstr "Не удалось получить торрент из: {0}" + diff --git a/apps/i2psnark/locale/messages_zh.po b/apps/i2psnark/locale/messages_zh.po new file mode 100644 index 000000000..ec2e6f8bd --- /dev/null +++ b/apps/i2psnark/locale/messages_zh.po @@ -0,0 +1,652 @@ +# I2P +# Copyright (C) 2009 The I2P Project +# This file is distributed under the same license as the i2psnark package. +# To contribute translations, see http://www.i2p2.de/newdevelopers +# foo , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: I2P i2psnark\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-12-18 06:45+0000\n" +"PO-Revision-Date: 2009-12-18 15:57+0800\n" +"Last-Translator: walking \n" +"Language-Team: foo \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Chinese\n" + +#: ../java/src/org/klomp/snark/SnarkManager.java:84 +#, java-format +msgid "Adding torrents in {0} minutes" +msgstr "{0}分钟内完成添加" + +#: ../java/src/org/klomp/snark/SnarkManager.java:241 +#, java-format +msgid "Total uploaders limit changed to {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:243 +#, java-format +msgid "Minimum total uploaders limit is {0}" +msgstr "" + +#: ../java/src/org/klomp/snark/SnarkManager.java:255 +#, java-format +msgid "Up BW limit changed to {0}KBps" +msgstr "上传带宽限制改为 {0} KBps" + +#: ../java/src/org/klomp/snark/SnarkManager.java:257 +#, java-format +msgid "Minimum up bandwidth limit is {0}KBps" +msgstr "最小上传带宽限制为 {0} KBps" + +#: ../java/src/org/klomp/snark/SnarkManager.java:301 +msgid "Cannot change the I2CP settings while torrents are active" +msgstr "正在下载/上传,无法更改I2CP设置" + +#: ../java/src/org/klomp/snark/SnarkManager.java:307 +msgid "Disconnecting old I2CP destination" +msgstr "正在断开旧的I2CP目标" + +#: ../java/src/org/klomp/snark/SnarkManager.java:311 +#, java-format +msgid "I2CP settings changed to {0}" +msgstr "I2CP设置改为{0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:315 +msgid "Unable to connect with the new settings, reverting to the old I2CP settings" +msgstr "无法通过新设置连接,恢复I2CP的旧设置" + +#: ../java/src/org/klomp/snark/SnarkManager.java:319 +msgid "Unable to reconnect with the old settings!" +msgstr "旧设置也无法连接!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:321 +msgid "Reconnected on the new I2CP destination" +msgstr "重新连接新I2CP目标" + +#: ../java/src/org/klomp/snark/SnarkManager.java:332 +#, java-format +msgid "I2CP listener restarted for \"{0}\"" +msgstr "\"{0}\"的I2CP监听端口已启动" + +#: ../java/src/org/klomp/snark/SnarkManager.java:343 +msgid "Enabled autostart" +msgstr "启用自动启动" + +#: ../java/src/org/klomp/snark/SnarkManager.java:345 +msgid "Disabled autostart" +msgstr "禁用自动启动" + +#: ../java/src/org/klomp/snark/SnarkManager.java:351 +msgid "Enabled open trackers - torrent restart required to take effect." +msgstr "启用OpenTracker-重新启动种子后生效" + +#: ../java/src/org/klomp/snark/SnarkManager.java:353 +msgid "Disabled open trackers - torrent restart required to take effect." +msgstr "禁用OpenTracker - 重新启动种子后生效" + +#: ../java/src/org/klomp/snark/SnarkManager.java:360 +msgid "Open Tracker list changed - torrent restart required to take effect." +msgstr "OpenTracker列表已改变 - 重新启动种子后生效" + +#: ../java/src/org/klomp/snark/SnarkManager.java:367 +msgid "Configuration unchanged." +msgstr "设置未改变" + +#: ../java/src/org/klomp/snark/SnarkManager.java:377 +#, java-format +msgid "Unable to save the config to {0}" +msgstr "无法保存设置到{0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:395 +msgid "Connecting to I2P" +msgstr "正在连接到I2P" + +#: ../java/src/org/klomp/snark/SnarkManager.java:398 +msgid "Error connecting to I2P - check your I2CP settings!" +msgstr "连接I2P时发生错误 - 请检查I2CP设置!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:407 +#, java-format +msgid "Error: Could not add the torrent {0}" +msgstr "错误:无法添加种子{0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:446 +#, java-format +msgid "Torrent in \"{0}\" is invalid" +msgstr "无效种子 \"{0}\" " + +#: ../java/src/org/klomp/snark/SnarkManager.java:461 +#, java-format +msgid "Torrent added and started: \"{0}\"" +msgstr "已添加并启动种子:\"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:463 +#, java-format +msgid "Torrent added: \"{0}\"" +msgstr "已添加种子:\"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:559 +#, java-format +msgid "Non-i2p tracker in \"{0}\", deleting it from our list of trackers!" +msgstr "【匿名性警告】\"{0}\" 中含有非I2P Tracker,程序将从Tracker列表中将其删除。" + +#: ../java/src/org/klomp/snark/SnarkManager.java:562 +#, java-format +msgid "Too many files in \"{0}\" ({1}), deleting it!" +msgstr "\"{0}\" ({1}) 含有太多文件,删除之!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:564 +#, java-format +msgid "Torrent file \"{0}\" cannot end in '.torrent', deleting it!" +msgstr "种子文件 \"{0}\" 不以 \".torrent\"结尾,删除之!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:566 +#, java-format +msgid "No pieces in \"{0}\", deleting it!" +msgstr "\"{0}\" 中没有数据片,删除之!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:568 +#, java-format +msgid "Too many pieces in \"{0}\", limit is {1}, deleting it!" +msgstr "\"{0}\" 中文件分片太多,限额为{1},删除之!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:570 +#, java-format +msgid "Pieces are too large in \"{0}\" ({1}B), deleting it." +msgstr "\"{0}\" ({1}B) 中文件分片过大,删除之。" + +#: ../java/src/org/klomp/snark/SnarkManager.java:571 +#, java-format +msgid "Limit is {0}B" +msgstr "限额为 {0}B" + +#: ../java/src/org/klomp/snark/SnarkManager.java:579 +#, java-format +msgid "Torrents larger than {0}B are not supported yet, deleting \"{1}\"" +msgstr "目前不支持大于{0}B 的种子,正在删除\"{1}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:595 +#, java-format +msgid "Error: Could not remove the torrent {0}" +msgstr "错误:无法删除种子{0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:616 +#, java-format +msgid "Torrent stopped: \"{0}\"" +msgstr "种子已停止:\"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:631 +#, java-format +msgid "Torrent removed: \"{0}\"" +msgstr "种子已删除:\"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:664 +#, java-format +msgid "Download finished: \"{0}\"" +msgstr "下载已完成:\"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:664 +#, java-format +msgid "size: {0}B" +msgstr "大小:{0}B" + +#: ../java/src/org/klomp/snark/SnarkManager.java:692 +msgid "Unable to connect to I2P!" +msgstr "无法连接至I2P!" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:86 +msgid "I2PSnark - Anonymous BitTorrent Client" +msgstr "I2PSnark - 匿名BitTorrent客户端" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:95 +msgid "Refresh page" +msgstr "刷新页面" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:97 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:656 +msgid "I2PSnark" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:99 +msgid "Forum" +msgstr "论坛" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:125 +msgid "Status" +msgstr "状态" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:131 +msgid "Hide Peers" +msgstr "隐藏用户" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:134 +msgid "Show Peers" +msgstr "显示用户" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:139 +msgid "Torrent" +msgstr "种子" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:141 +msgid "ETA" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:143 +msgid "Downloaded" +msgstr "已下载" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:145 +msgid "Uploaded" +msgstr "已上传" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:147 +msgid "Down Rate" +msgstr "下载速度" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:149 +msgid "Up Rate" +msgstr "上传速度" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:156 +msgid "Stop all torrents and the I2P tunnel" +msgstr "停止全部种子及I2P隧道" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:158 +msgid "Stop All" +msgstr "停止全部" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:163 +msgid "Start all torrents and the I2P tunnel" +msgstr "启动全部种子及I2P隧道" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:165 +msgid "Start All" +msgstr "启动全部" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:182 +msgid "No torrents loaded." +msgstr "未载入任何种子" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:187 +msgid "Totals" +msgstr "总计" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:189 +#, java-format +msgid "{0} torrents" +msgstr "{0} 个种子" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:192 +#, java-format +msgid "{0} connected peers" +msgstr "{0} 已连接用户" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:227 +#, java-format +msgid "Torrent file {0} does not exist" +msgstr "种子文件{0}不存在" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:237 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:990 +#, java-format +msgid "Torrent already running: {0}" +msgstr "种子已启动:{0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:239 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:992 +#, java-format +msgid "Torrent already in the queue: {0}" +msgstr "种子排队中:{0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:243 +#, java-format +msgid "Copying torrent to {0}" +msgstr "正在复制种子到{0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:246 +#, java-format +msgid "Unable to copy the torrent to {0}" +msgstr "无法复制种子文件到{0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:246 +#, java-format +msgid "from {0}" +msgstr "来源{0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:254 +#, java-format +msgid "Fetching {0}" +msgstr "正在获取{0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:258 +msgid "Invalid URL - must start with http://" +msgstr "无效链接 - 必须以http:// 开头" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:288 +#, java-format +msgid "Starting up torrent {0}" +msgstr "正在启动种子{0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:308 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:326 +#, java-format +msgid "Torrent file deleted: {0}" +msgstr "种子文件已删除:{0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:332 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:342 +#, java-format +msgid "Data file deleted: {0}" +msgstr "数据文件已删除:{0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:334 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:344 +#, java-format +msgid "Data file could not be deleted: {0}" +msgstr "无法删除数据文件:{0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:353 +#, java-format +msgid "Data dir deleted: {0}" +msgstr "数据文件夹已删除:{0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:384 +msgid "Error creating torrent - you must select a tracker" +msgstr "创建种子时发生错误 - 您必须选择一个Tracker" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:399 +#, java-format +msgid "Torrent created for \"{0}\"" +msgstr "种子创建成功\"{0}\"" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:402 +#, java-format +msgid "Many I2P trackers require you to register new torrents before seeding - please do so before starting \"{0}\"" +msgstr "多数I2PTracker需要用户在做种前注册新种子 - 请在启动 \"{0}\"前到所使用的Tracker进行注册。" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:404 +#, java-format +msgid "Error creating a torrent for \"{0}\"" +msgstr "创建种子时发生错误 \"{0}\"" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:407 +#, java-format +msgid "Cannot create a torrent for the nonexistent data: {0}" +msgstr "无法为不存在的数据文件创建种子:{0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:410 +msgid "Error creating torrent - you must enter a file or directory" +msgstr "创建种子时发生错误 - 必须指定文件或文件夹" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:413 +msgid "Stopping all torrents and closing the I2P tunnel." +msgstr "正在停用所有种子并关闭I2P隧道。" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:422 +msgid "I2P tunnel closed." +msgstr "I2P隧道已关闭" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:425 +msgid "Opening the I2P tunnel and starting all torrents." +msgstr "正在打开I2P隧道并启动所有种子" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:502 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:670 +msgid "Unknown" +msgstr "未知" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:505 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:509 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:513 +msgid "TrackerErr" +msgstr "Tracker错误" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:507 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:509 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:519 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:521 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:528 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:530 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:534 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:536 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:862 +msgid "peers" +msgstr "用户" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:517 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:521 +msgid "Seeding" +msgstr "正做种" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:523 +msgid "Complete" +msgstr "完成" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:526 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:530 +msgid "OK" +msgstr "确定" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:532 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:536 +msgid "Stalled" +msgstr "等待" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:538 +msgid "No Peers" +msgstr "没有用户" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:540 +msgid "Stopped" +msgstr "已停用" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:553 +msgid "View files" +msgstr "浏览文件" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:555 +msgid "Open file" +msgstr "打开文件" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:579 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:781 +msgid "Tracker" +msgstr "Tracker服务器" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:580 +msgid "Details" +msgstr "详情" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:614 +msgid "Stop the torrent" +msgstr "停止种子" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:616 +msgid "Stop" +msgstr "停止" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:622 +msgid "Start the torrent" +msgstr "启动种子" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:624 +msgid "Start" +msgstr "启动" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:629 +msgid "Remove the torrent from the active list, deleting the .torrent file" +msgstr "取消下载任务并删除对应种子文件。" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:631 +msgid "Remove" +msgstr "移除" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:635 +msgid "Delete the .torrent file and the associated data file(s)" +msgstr "删除种子及所下载的文件" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:637 +msgid "Delete" +msgstr "删除" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:680 +msgid "Seed" +msgstr "种子" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:698 +msgid "Uninteresting (The peer has no pieces we need)" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:700 +msgid "Choked (The peer is not allowing us to request pieces)" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:714 +msgid "Uninterested (We have no pieces the peer needs)" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:716 +msgid "Choking (We are not allowing the peer to request pieces)" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:743 +msgid "Add Torrent" +msgstr "添加种子" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:745 +msgid "From URL" +msgstr "从URL" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:750 +msgid "Add torrent" +msgstr "添加种子" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:753 +#, java-format +msgid "Alternately, you can copy .torrent files to the directory {0}." +msgstr "或者您可以将.torrent文件复制到以下目录{0}." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:755 +msgid "Removing a .torrent file will cause the torrent to stop." +msgstr "删除种子文件将导致中止该下载任务。" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:772 +msgid "Create Torrent" +msgstr "创建种子" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:775 +msgid "Data to seed" +msgstr "做种数据" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:779 +msgid "File or directory to seed (must be within the specified path)" +msgstr "做种文件或文件夹(必须下面为Snark指定的文件夹中)" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:783 +msgid "Select a tracker" +msgstr "选择一个Tracker" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:796 +msgid "or" +msgstr "或" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:799 +msgid "Specify custom tracker announce URL" +msgstr "指定Open Tracker发布链接" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:802 +msgid "Create torrent" +msgstr "创建种子" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:820 +msgid "Configuration" +msgstr "设置" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:823 +msgid "Data directory" +msgstr "数据文件夹" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:826 +msgid "Directory to store torrents and data" +msgstr "种子及被做种文件的保存位置。" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:828 +msgid "Edit i2psnark.config and restart to change" +msgstr "编辑 i2psnark.config 并重启Snark后生效" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:832 +msgid "Auto start" +msgstr "自动启动" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:836 +msgid "If checked, automatically start torrents that are added" +msgstr "选中后Snark将自动启动已添加的所有种子。" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:859 +msgid "Total uploader limit" +msgstr "" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:866 +msgid "Up bandwidth limit" +msgstr "上传带宽限制" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:869 +msgid "Half available bandwidth recommended." +msgstr "推荐设置为可用带宽的一半。" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:871 +msgid "View or change router bandwidth" +msgstr "浏览或修改路由器带宽" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:875 +msgid "Use open trackers also" +msgstr "同时使用OpenTracker" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:879 +msgid "If checked, announce torrents to open trackers as well as the tracker listed in the torrent file" +msgstr "选择后在OpenTracker及种子文件中的Tracker上同时发布。" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:883 +msgid "Open tracker announce URLs" +msgstr "Open Tracker发布链接" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:894 +msgid "I2CP host" +msgstr "I2CP主机" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:899 +msgid "I2CP port" +msgstr "I2CP端口" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:912 +msgid "I2CP options" +msgstr "I2CP选项" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:917 +msgid "Save configuration" +msgstr "保存设置" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:970 +#, java-format +msgid "Torrent fetched from {0}" +msgstr "从{0}获取种子成功" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:998 +#, java-format +msgid "Torrent at {0} was not valid" +msgstr "{0}的种子中有错误" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1003 +#, java-format +msgid "Torrent was not retrieved from {0}" +msgstr "从{0}获得种子失败" + +#~ msgid "Custom tracker URL" +#~ msgstr "自定义TrackerURL" +#~ msgid "Configure" +#~ msgstr "设置" + diff --git a/apps/i2ptunnel/java/bmsg.sh b/apps/i2ptunnel/java/bmsg.sh new file mode 100644 index 000000000..b9d294b32 --- /dev/null +++ b/apps/i2ptunnel/java/bmsg.sh @@ -0,0 +1,17 @@ +# +# Update messages_xx.po and messages_xx.class files, +# from both java and jsp sources. +# Requires installed programs xgettext, msgfmt, msgmerge, and find. +# zzz - public domain +# + +## launching sh.exe with -login parameter will open a shell with the current path always pointing to \bin\ +## need to cd into our orignal path - where we call sh.exe from. + +cd $CALLFROM +## echo $PWD + +## except this everything is the same with bundle-message.sh +## walking - public domain :-D + +source bundle-messages.sh $PARAS \ No newline at end of file diff --git a/apps/i2ptunnel/java/build.xml b/apps/i2ptunnel/java/build.xml index a74e328cc..9647fa8d1 100644 --- a/apps/i2ptunnel/java/build.xml +++ b/apps/i2ptunnel/java/build.xml @@ -41,13 +41,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -113,11 +148,7 @@ - - - - diff --git a/apps/i2ptunnel/java/bundle-messages.bat b/apps/i2ptunnel/java/bundle-messages.bat new file mode 100644 index 000000000..90feca972 --- /dev/null +++ b/apps/i2ptunnel/java/bundle-messages.bat @@ -0,0 +1,26 @@ +@echo off +set Callfrom=%cd% +set Paras=%1 + +rem before calling make sure you have msys and mingw 's "bin" path +rem in your current searching path +rem type "set path" to check +if not exist ..\locale\*.only goto updateALL + +rem put a messages_xx.only(eg messages_zh.only) into locale folder +rem this script will only touch the po file(eg zh) you specified, leaving other po files untact. + +for %%i in (..\locale\*.only) do set PO=%%~ni +echo [Notice] Yu choose to Ony update the choosen file: %PO%.po +for %%i in (..\locale\*.po) do if not %%~ni==%PO% ren %%i %%~ni.po- + +call sh --login %cd%\bmsg.sh + +for %%i in (..\locale\*.po-) do if not %%~ni==%PO% ren %%i %%~ni.po +goto end + +:updateALL +call sh --login %cd%\bmsg.sh + +:end +echo End of Message Bundling \ No newline at end of file diff --git a/apps/i2ptunnel/java/bundle-messages.sh b/apps/i2ptunnel/java/bundle-messages.sh new file mode 100755 index 000000000..8e9375d20 --- /dev/null +++ b/apps/i2ptunnel/java/bundle-messages.sh @@ -0,0 +1,87 @@ +# +# Update messages_xx.po and messages_xx.class files, +# from both java and jsp sources. +# Requires installed programs xgettext, msgfmt, msgmerge, and find. +# +# usage: +# bundle-messages.sh (generates the resource bundle from the .po file) +# bundle-messages.sh -p (updates the .po file from the source tags, then generates the resource bundle) +# +# zzz - public domain +# +CLASS=net.i2p.i2ptunnel.web.messages +TMPFILE=build/javafiles.txt +export TZ=UTC + +if [ "$1" = "-p" ] +then + POUPDATE=1 +fi + +# add ../java/ so the refs will work in the po file +JPATHS="../java/src ../jsp/WEB-INF" +for i in ../locale/messages_*.po +do + # get language + LG=${i#../locale/messages_} + LG=${LG%.po} + + if [ "$POUPDATE" = "1" ] + then + # make list of java files newer than the .po file + find $JPATHS -name *.java -newer $i > $TMPFILE + fi + if [ -s ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/web/messages_$LG.class -a \ + ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/web/messages_$LG.class -nt $i -a \ + ! -s $TMPFILE ] + then + continue + fi + + if [ "$POUPDATE" = "1" ] + then + echo "Updating the $i file from the tags..." + # extract strings from java and jsp files, and update messages.po files + # translate calls must be one of the forms: + # _("foo") + # _x("foo") + # intl._("foo") + # intl.title("foo") + # In a jsp, you must use a helper or handler that has the context set. + # To start a new translation, copy the header from an old translation to the new .po file, + # then ant distclean updater. + find $JPATHS -name *.java > $TMPFILE + xgettext -f $TMPFILE -F -L java --from-code=UTF-8 \ + --keyword=_ --keyword=_x --keyword=intl._ --keyword=intl.title \ + -o ${i}t + if [ $? -ne 0 ] + then + echo 'Warning - xgettext failed, not updating translations' + rm -f ${i}t + break + fi + msgmerge -U --backup=none $i ${i}t + if [ $? -ne 0 ] + then + echo 'Warning - msgmerge failed, not updating translations' + rm -f ${i}t + break + fi + rm -f ${i}t + # so we don't do this again + touch $i + fi + + echo "Generating ${CLASS}_$LG ResourceBundle..." + + # convert to class files in build/obj + msgfmt --java --statistics -r $CLASS -l $LG -d ../jsp/WEB-INF/classes $i + if [ $? -ne 0 ] + then + echo 'Warning - msgfmt failed, not updating translations' + break + fi +done +rm -f $TMPFILE +# todo: return failure +exit 0 diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java index 12940a81b..de71ff3b2 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java @@ -20,7 +20,7 @@ import java.util.zip.GZIPInputStream; import net.i2p.I2PAppContext; import net.i2p.data.ByteArray; import net.i2p.util.ByteCache; -import net.i2p.util.I2PThread; +import net.i2p.util.I2PAppThread; import net.i2p.util.Log; /** @@ -219,7 +219,7 @@ class HTTPResponseOutputStream extends FilterOutputStream { //out.flush(); PipedInputStream pi = new PipedInputStream(); PipedOutputStream po = new PipedOutputStream(pi); - new I2PThread(new Pusher(pi, out), "HTTP decompresser").start(); + new I2PAppThread(new Pusher(pi, out), "HTTP decompresser").start(); out = po; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java index 6a6c83883..a7197a006 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java @@ -27,7 +27,7 @@ import net.i2p.client.streaming.I2PSocketManagerFactory; import net.i2p.client.streaming.I2PSocketOptions; import net.i2p.data.Destination; import net.i2p.util.EventDispatcher; -import net.i2p.util.I2PThread; +import net.i2p.util.I2PAppThread; import net.i2p.util.Log; import net.i2p.util.SimpleScheduler; import net.i2p.util.SimpleTimer; @@ -153,7 +153,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna } // else delay creating session until createI2PSocket() is called - Thread t = new I2PThread(this); + Thread t = new I2PAppThread(this); t.setName("Client " + _clientId); listenerReady = false; t.start(); @@ -207,7 +207,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna for (int i = 0; i < _numConnectionBuilders; i++) { String name = "ClientBuilder" + _clientId + '.' + i; - I2PThread b = new I2PThread(new TunnelConnectionBuilder(), name); + I2PAppThread b = new I2PAppThread(new TunnelConnectionBuilder(), name); b.setDaemon(true); b.start(); } @@ -350,7 +350,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna * called by derived classes after initialization. * */ - public final void startRunning() { + public void startRunning() { synchronized (startLock) { startRunning = true; startLock.notify(); @@ -490,7 +490,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna protected void manageConnection(Socket s) { if (s == null) return; if (_numConnectionBuilders <= 0) { - new I2PThread(new BlockingRunner(s), "Clinet run").start(); + new I2PAppThread(new BlockingRunner(s), "Clinet run").start(); return; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index b729b659b..42fb39549 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -233,11 +233,35 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable return opts; } + private InternalSocketRunner isr; + + /** + * Actually start working on incoming connections. + * Overridden to start an internal socket too. + * + */ + @Override + public void startRunning() { + super.startRunning(); + this.isr = new InternalSocketRunner(this); + } + + /** + * Overridden to close internal socket too. + */ + public boolean close(boolean forced) { + boolean rv = super.close(forced); + if (this.isr != null) + this.isr.stopRunning(); + return rv; + } + private static final boolean DEFAULT_GZIP = true; // all default to false public static final String PROP_REFERER = "i2ptunnel.httpclient.sendReferer"; public static final String PROP_USER_AGENT = "i2ptunnel.httpclient.sendUserAgent"; public static final String PROP_VIA = "i2ptunnel.httpclient.sendVia"; + public static final String PROP_JUMP_SERVERS = "i2ptunnel.httpclient.jumpServers"; private static long __requestId = 0; protected void clientConnectionRun(Socket s) { @@ -245,6 +269,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable OutputStream out = null; String targetRequest = null; boolean usingWWWProxy = false; + boolean usingInternalServer = false; String currentProxy = null; long requestId = ++__requestId; try { @@ -271,6 +296,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable int pos = line.indexOf(" "); if (pos == -1) break; method = line.substring(0, pos); + // TODO use Java URL class to make all this simpler and more robust String request = line.substring(pos + 1); if (request.startsWith("/") && getTunnel().getClientOptions().getProperty("i2ptunnel.noproxy") != null) { request = "http://i2p" + request; @@ -316,8 +342,11 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable } } - // Quick hack for foo.bar.i2p - if (host.toLowerCase().endsWith(".i2p")) { + if (host.toLowerCase().equals("proxy.i2p")) { + // so we don't do any naming service lookups + destination = "proxy.i2p"; + usingInternalServer = true; + } else if (host.toLowerCase().endsWith(".i2p")) { // Destination gets the host name destination = host; // Host becomes the destination key @@ -454,15 +483,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable } destination = request.substring(0, pos); line = method + " " + request.substring(pos); - } + } // end host name processing - boolean isValid = usingWWWProxy || isSupportedAddress(host, protocol); + boolean isValid = usingWWWProxy || usingInternalServer || isSupportedAddress(host, protocol); if (!isValid) { if (_log.shouldLog(Log.INFO)) _log.info(getPrefix(requestId) + "notValid(" + host + ")"); method = null; destination = null; break; - } else if (!usingWWWProxy) { + } else if ((!usingWWWProxy) && (!usingInternalServer)) { if (_log.shouldLog(Log.INFO)) _log.info(getPrefix(requestId) + "host=getHostName(" + destination + ")"); host = getHostName(destination); // hide original host } @@ -473,7 +502,9 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable _log.debug(getPrefix(requestId) + "HOST :" + host + ":"); _log.debug(getPrefix(requestId) + "DEST :" + destination + ":"); } - + + // end first line processing + } else { if (lowercaseLine.startsWith("host: ") && !usingWWWProxy) { line = "Host: " + host; @@ -505,14 +536,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable continue; // completely strip the line } } - + if (line.length() == 0) { String ok = getTunnel().getClientOptions().getProperty("i2ptunnel.gzip"); boolean gzip = DEFAULT_GZIP; if (ok != null) gzip = Boolean.valueOf(ok).booleanValue(); - if (gzip) { + if (gzip && !usingInternalServer) { // according to rfc2616 s14.3, this *should* force identity, even if // an explicit q=0 for gzip doesn't. tested against orion.i2p, and it // seems to work. @@ -526,7 +557,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable } else { newRequest.append(line).append("\r\n"); // HTTP spec } - } + } // end header processing + if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix(requestId) + "NewRequest header: [" + newRequest.toString() + "]"); @@ -548,7 +580,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable // Serve local proxy files (images, css linked from error pages) // Ignore all the headers - if (destination.equals("proxy.i2p")) { + if (usingInternalServer) { serveLocalFile(out, method, targetRequest); s.close(); return; @@ -560,7 +592,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable if (_log.shouldLog(Log.WARN)) _log.warn("Unable to resolve " + destination + " (proxy? " + usingWWWProxy + ", request: " + targetRequest); byte[] header; - boolean showAddrHelper = false; + String jumpServers = null; if (usingWWWProxy) header = getErrorPage("dnfp", ERR_DESTINATION_UNKNOWN); else if(ahelper != 0) @@ -569,9 +601,11 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable header = getErrorPage("dnf", ERR_DESTINATION_UNKNOWN); else { header = getErrorPage("dnfh", ERR_DESTINATION_UNKNOWN); - showAddrHelper = true; + jumpServers = getTunnel().getClientOptions().getProperty(PROP_JUMP_SERVERS); + if (jumpServers == null) + jumpServers = DEFAULT_JUMP_SERVERS; } - writeErrorMessage(header, out, targetRequest, usingWWWProxy, destination, showAddrHelper); + writeErrorMessage(header, out, targetRequest, usingWWWProxy, destination, jumpServers); s.close(); return; } @@ -726,15 +760,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable } } - private static String jumpServers[] = { - "http://i2host.i2p/cgi-bin/i2hostjump?", - // "http://orion.i2p/jump/", - "http://stats.i2p/cgi-bin/jump.cgi?a=", - // "http://trevorreznik.i2p/cgi-bin/jump.php?hostname=", - "http://i2jump.i2p/" - }; + private static String DEFAULT_JUMP_SERVERS = + "http://i2host.i2p/cgi-bin/i2hostjump?," + + "http://stats.i2p/cgi-bin/jump.cgi?a=," + + "http://i2jump.i2p/"; + + /** + * @param jumpServers comma- or space-separated list, or null + */ private static void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest, - boolean usingWWWProxy, String wwwProxy, boolean showAddrHelper) throws IOException { + boolean usingWWWProxy, String wwwProxy, String jumpServers) throws IOException { if (out != null) { out.write(errMessage); if (targetRequest != null) { @@ -750,12 +785,17 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable out.write(uri.getBytes()); out.write("".getBytes()); if (usingWWWProxy) out.write(("
WWW proxy: " + wwwProxy).getBytes()); - if (showAddrHelper) { + if (jumpServers != null && jumpServers.length() > 0) { // Fixme untranslated out.write("

Click a link below to look for an address helper by using a \"jump\" service:
".getBytes()); - for (int i = 0; i < jumpServers.length; i++) { + + StringTokenizer tok = new StringTokenizer(jumpServers, ", "); + while (tok.hasMoreTokens()) { + String jurl = tok.nextToken(); + if (!jurl.startsWith("http://")) + continue; // Skip jump servers we don't know - String jumphost = jumpServers[i].substring(7); // "http://" + String jumphost = jurl.substring(7); // "http://" jumphost = jumphost.substring(0, jumphost.indexOf('/')); try { Destination dest = I2PTunnel.destFromName(jumphost); @@ -765,10 +805,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable } out.write("
".getBytes()); - out.write(jumpServers[i].getBytes()); + out.write(jurl.getBytes()); out.write(uri.getBytes()); out.write("".getBytes()); } @@ -792,7 +832,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable header = getErrorPage(I2PAppContext.getGlobalContext(), "dnfp", ERR_DESTINATION_UNKNOWN); else header = getErrorPage(I2PAppContext.getGlobalContext(), "dnf", ERR_DESTINATION_UNKNOWN); - writeErrorMessage(header, out, targetRequest, usingWWWProxy, wwwProxy, false); + writeErrorMessage(header, out, targetRequest, usingWWWProxy, wwwProxy, null); } catch (IOException ioe) { // static //_log.warn(getPrefix(requestId) + "Error writing out the 'destination was unknown' " + "message", ioe); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java index e1ce9084e..af9f1c1ec 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java @@ -17,7 +17,7 @@ import java.util.zip.GZIPOutputStream; import net.i2p.client.streaming.I2PSocket; import net.i2p.data.DataHelper; import net.i2p.util.EventDispatcher; -import net.i2p.util.I2PThread; +import net.i2p.util.I2PAppThread; import net.i2p.util.Log; import net.i2p.data.Base32; @@ -118,7 +118,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { useGZIP = true; if (allowGZIP && useGZIP) { - I2PThread req = new I2PThread(new CompressedRequestor(s, socket, modifiedHeader), Thread.currentThread().getName()+".hc"); + I2PAppThread req = new I2PAppThread(new CompressedRequestor(s, socket, modifiedHeader), Thread.currentThread().getName()+".hc"); req.start(); } else { new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(), null); @@ -174,7 +174,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { _log.info("request headers: " + _headers); serverout.write(_headers.getBytes()); browserin = _browser.getInputStream(); - I2PThread sender = new I2PThread(new Sender(serverout, browserin, "server: browser to server"), Thread.currentThread().getName() + "hcs"); + I2PAppThread sender = new I2PAppThread(new Sender(serverout, browserin, "server: browser to server"), Thread.currentThread().getName() + "hcs"); sender.start(); browserout = _browser.getOutputStream(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java index b194ab702..007652673 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java @@ -14,7 +14,7 @@ import net.i2p.client.streaming.I2PSocket; import net.i2p.data.DataFormatException; import net.i2p.data.Destination; import net.i2p.util.EventDispatcher; -import net.i2p.util.I2PThread; +import net.i2p.util.I2PAppThread; import net.i2p.util.Log; public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable { @@ -83,9 +83,9 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable i2ps = createI2PSocket(clientDest); i2ps.setReadTimeout(readTimeout); StringBuilder expectedPong = new StringBuilder(); - Thread in = new I2PThread(new IrcInboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " in"); + Thread in = new I2PAppThread(new IrcInboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " in"); in.start(); - Thread out = new I2PThread(new IrcOutboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " out"); + Thread out = new I2PAppThread(new IrcOutboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " out"); out.start(); } catch (Exception ex) { if (_log.shouldLog(Log.ERROR)) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java index 76480a940..446ad5563 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java @@ -16,10 +16,10 @@ import net.i2p.client.streaming.I2PSocket; import net.i2p.data.ByteArray; import net.i2p.util.ByteCache; import net.i2p.util.Clock; -import net.i2p.util.I2PThread; +import net.i2p.util.I2PAppThread; import net.i2p.util.Log; -public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorListener { +public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErrorListener { private final static Log _log = new Log(I2PTunnelRunner.class); private static volatile long __runnerId; @@ -222,7 +222,7 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL } } - private class StreamForwarder extends I2PThread { + private class StreamForwarder extends I2PAppThread { InputStream in; OutputStream out; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java index 76246d7b6..2471fcc50 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java @@ -24,7 +24,7 @@ import net.i2p.client.streaming.I2PSocketManager; import net.i2p.client.streaming.I2PSocketManagerFactory; import net.i2p.data.Base64; import net.i2p.util.EventDispatcher; -import net.i2p.util.I2PThread; +import net.i2p.util.I2PAppThread; import net.i2p.util.Log; public class I2PTunnelServer extends I2PTunnelTask implements Runnable { @@ -132,7 +132,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { * */ public void startRunning() { - Thread t = new I2PThread(this); + Thread t = new I2PAppThread(this); t.setName("Server " + (++__serverId)); t.start(); } @@ -204,7 +204,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { I2PServerSocket i2pS_S = sockMgr.getServerSocket(); int handlers = getHandlerCount(); for (int i = 0; i < handlers; i++) { - I2PThread handler = new I2PThread(new Handler(i2pS_S), "Handle Server " + i); + I2PAppThread handler = new I2PAppThread(new Handler(i2pS_S), "Handle Server " + i); handler.start(); } } else { @@ -213,7 +213,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { try { final I2PSocket i2ps = i2pS_S.accept(); if (i2ps == null) throw new I2PException("I2PServerSocket closed"); - new I2PThread(new Runnable() { public void run() { blockingHandle(i2ps); } }).start(); + new I2PAppThread(new Runnable() { public void run() { blockingHandle(i2ps); } }).start(); } catch (I2PException ipe) { if (_log.shouldLog(Log.ERROR)) _log.error("Error accepting - KILLING THE TUNNEL SERVER", ipe); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java index 1f358abf0..a3cd1ad99 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java @@ -14,7 +14,7 @@ import net.i2p.I2PException; import net.i2p.client.streaming.I2PSocketManager; import net.i2p.data.Destination; import net.i2p.util.EventDispatcher; -import net.i2p.util.I2PThread; +import net.i2p.util.I2PAppThread; import net.i2p.util.Log; public class I2Ping extends I2PTunnelTask implements Runnable { @@ -59,7 +59,7 @@ public class I2Ping extends I2PTunnelTask implements Runnable { sockMgr = I2PTunnelClient.getSocketManager(tunnel); } } - Thread t = new I2PThread(this); + Thread t = new I2PAppThread(this); t.setName("Client"); t.start(); open = true; @@ -188,7 +188,7 @@ public class I2Ping extends I2PTunnelTask implements Runnable { } } - public class PingHandler extends I2PThread { + public class PingHandler extends I2PAppThread { private String destination; public PingHandler(String dest) { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/InternalSocketRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/InternalSocketRunner.java new file mode 100644 index 000000000..5e3eefd4f --- /dev/null +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/InternalSocketRunner.java @@ -0,0 +1,55 @@ +package net.i2p.i2ptunnel; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +import net.i2p.util.I2PAppThread; +import net.i2p.util.InternalServerSocket; +import net.i2p.util.Log; + +/** + * Listen for in-JVM connections on the internal "socket" + * + * @author zzz + */ +class InternalSocketRunner implements Runnable { + private I2PTunnelClientBase client; + private int port; + private ServerSocket ss; + private boolean open; + private static final Log _log = new Log(InternalSocketRunner.class); + + /** starts the runner */ + InternalSocketRunner(I2PTunnelClientBase client) { + this.client = client; + this.port = client.getLocalPort(); + Thread t = new I2PAppThread(this, "Internal socket port " + this.port, true); + t.start(); + } + + public final void run() { + try { + this.ss = new InternalServerSocket(this.port); + this.open = true; + while (true) { + Socket s = this.ss.accept(); + this.client.manageConnection(s); + } + } catch (IOException ex) { + if (this.open) { + _log.error("Error listening for internal connections on " + this.port, ex); + } + this.open = false; + } + } + + void stopRunning() { + if (this.open) { + try { + this.ss.close(); + } catch (IOException ex) {} + this.open = false; + } + } +} diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java index b5ca6c3a1..06beffae5 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java @@ -16,7 +16,7 @@ import net.i2p.client.I2PClientFactory; import net.i2p.client.I2PSession; import net.i2p.data.Base32; import net.i2p.data.Destination; -import net.i2p.util.I2PThread; +import net.i2p.util.I2PAppThread; import net.i2p.util.Log; /** @@ -106,7 +106,7 @@ public class TunnelController implements Logging { public void startTunnelBackground() { if (_running) return; _starting = true; - new I2PThread(new Runnable() { public void run() { startTunnel(); } }).start(); + new I2PAppThread(new Runnable() { public void run() { startTunnel(); } }).start(); } /** diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java index fb330679a..4250dedd0 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java @@ -18,7 +18,7 @@ import net.i2p.I2PAppContext; import net.i2p.client.I2PSession; import net.i2p.client.I2PSessionException; import net.i2p.data.DataHelper; -import net.i2p.util.I2PThread; +import net.i2p.util.I2PAppThread; import net.i2p.util.Log; /** @@ -94,7 +94,7 @@ public class TunnelControllerGroup { _controllers.add(controller); i++; } - I2PThread startupThread = new I2PThread(new StartControllers(), "Startup tunnels"); + I2PAppThread startupThread = new I2PAppThread(new StartControllers(), "Startup tunnels"); startupThread.start(); if (_log.shouldLog(Log.INFO)) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java index be398f770..db37b9e59 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java @@ -55,7 +55,7 @@ public class I2PSOCKSTunnel extends I2PTunnelClientBase { I2PSocket destSock = serv.getDestinationI2PSocket(this); new I2PTunnelRunner(clientSock, destSock, sockLock, null, mySockets); } catch (SOCKSException e) { - _log.error("Error from SOCKS connection: " + e.getMessage()); + _log.error("Error from SOCKS connection", e); closeSocket(s); } } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/Messages.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/Messages.java new file mode 100644 index 000000000..591d6a98c --- /dev/null +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/Messages.java @@ -0,0 +1,37 @@ +package net.i2p.i2ptunnel.web; + +import net.i2p.I2PAppContext; +import net.i2p.util.Translate; + +/** + * Translate strings for this package. + */ +public class Messages { + private static final String BUNDLE_NAME = "net.i2p.i2ptunnel.web.messages"; + private final I2PAppContext _context; + + public Messages() { + _context = I2PAppContext.getGlobalContext(); + } + + /** lang in routerconsole.lang property, else current locale */ + public String _(String key) { + return Translate.getString(key, _context, BUNDLE_NAME); + } + + /** + * translate a string with a parameter + * This is a lot more expensive than getString(s, ctx), so use sparingly. + * + * @param s string to be translated containing {0} + * The {0} will be replaced by the parameter. + * Single quotes must be doubled, i.e. ' -> '' in the string. + * @param o parameter, not translated. + * To tranlslate parameter also, use _("foo {0} bar", _("baz")) + * Do not double the single quotes in the parameter. + * Use autoboxing to call with ints, longs, floats, etc. + */ + public String _(String s, Object o) { + return Translate.getString(s, o, _context, BUNDLE_NAME); + } +} diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp index c0ad7cdb5..40d1028b0 100644 --- a/apps/i2ptunnel/jsp/editClient.jsp +++ b/apps/i2ptunnel/jsp/editClient.jsp @@ -1,6 +1,7 @@ <%@page contentType="text/html" import="net.i2p.i2ptunnel.web.EditBean"%> + <% String tun = request.getParameter("tunnel"); int curTunnel = -1; if (tun != null) { @@ -13,7 +14,7 @@ %> - I2P Tunnel Manager - Edit + <%=intl._("I2P Tunnel Manager - Edit Client Tunnel")%> @@ -205,9 +206,9 @@
- <% int tunnelDepth = editBean.getTunnelDepth(curTunnel, 2); %> @@ -222,7 +223,7 @@ - <% int tunnelVariance = editBean.getTunnelVariance(curTunnel, 0); %> diff --git a/apps/i2ptunnel/jsp/editServer.jsp b/apps/i2ptunnel/jsp/editServer.jsp index 958c7e8b1..da98470f7 100644 --- a/apps/i2ptunnel/jsp/editServer.jsp +++ b/apps/i2ptunnel/jsp/editServer.jsp @@ -1,6 +1,7 @@ <%@page contentType="text/html" import="net.i2p.i2ptunnel.web.EditBean"%> + <% String tun = request.getParameter("tunnel"); int curTunnel = -1; if (tun != null) { @@ -13,7 +14,7 @@ %> - I2P Tunnel Manager - Edit + <%=intl._("I2P Tunnel Manager - Edit Server Tunnel")%> @@ -172,9 +173,9 @@
- <% int tunnelDepth = editBean.getTunnelDepth(curTunnel, 2); %> diff --git a/apps/i2ptunnel/jsp/index.jsp b/apps/i2ptunnel/jsp/index.jsp index 87a006f6d..6c2f7f73e 100644 --- a/apps/i2ptunnel/jsp/index.jsp +++ b/apps/i2ptunnel/jsp/index.jsp @@ -8,9 +8,10 @@ + - I2P Tunnel Manager - List + <%=intl._("I2P Tunnel Manager - List")%> diff --git a/apps/i2ptunnel/locale/messages_de.po b/apps/i2ptunnel/locale/messages_de.po new file mode 100644 index 000000000..3862132a9 --- /dev/null +++ b/apps/i2ptunnel/locale/messages_de.po @@ -0,0 +1,30 @@ +# I2P +# Copyright (C) 2009 The I2P Project +# This file is distributed under the same license as the i2ptunnel package. +# To contribute translations, see http://www.i2p2.de/newdevelopers +# foo , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: I2P i2ptunnel\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-12-10 00:50+0000\n" +"PO-Revision-Date: 2009-10-19 12:50+0000\n" +"Last-Translator: foo \n" +"Language-Team: foo \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: German\n" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:73 +msgid "I2P Tunnel Manager - Edit Client Tunnel" +msgstr "" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:73 +msgid "I2P Tunnel Manager - Edit Server Tunnel" +msgstr "" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:71 +msgid "I2P Tunnel Manager - List" +msgstr "" diff --git a/apps/i2ptunnel/locale/messages_ru.po b/apps/i2ptunnel/locale/messages_ru.po new file mode 100644 index 000000000..57770b2e2 --- /dev/null +++ b/apps/i2ptunnel/locale/messages_ru.po @@ -0,0 +1,31 @@ +# I2P +# Copyright (C) 2009 The I2P Project +# This file is distributed under the same license as the i2ptunnel package. +# To contribute translations, see http://www.i2p2.de/newdevelopers +# foo , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: I2P i2ptunnel\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-12-10 00:50+0000\n" +"PO-Revision-Date: 2009-12-14 11:51+0000\n" +"Last-Translator: 4get \n" +"Language-Team: foo \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Russian\n" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:73 +msgid "I2P Tunnel Manager - Edit Client Tunnel" +msgstr "Менеджер Туннелей I2P — Редактирование Клиентского Туннеля" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:73 +msgid "I2P Tunnel Manager - Edit Server Tunnel" +msgstr "Менеджер Туннелей I2P — Редактирование Серверного Туннеля" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:71 +msgid "I2P Tunnel Manager - List" +msgstr "Менеджер Туннелей I2P — Список" + diff --git a/apps/routerconsole/java/build.xml b/apps/routerconsole/java/build.xml index e5b602129..d8d85e21d 100644 --- a/apps/routerconsole/java/build.xml +++ b/apps/routerconsole/java/build.xml @@ -89,7 +89,7 @@ - + diff --git a/apps/routerconsole/java/bundle-messages.sh b/apps/routerconsole/java/bundle-messages.sh index 33db27572..ddc6785a0 100755 --- a/apps/routerconsole/java/bundle-messages.sh +++ b/apps/routerconsole/java/bundle-messages.sh @@ -104,7 +104,7 @@ do echo "Generating ${CLASS}_$LG ResourceBundle..." # convert to class files in build/obj - msgfmt --java -r $CLASS -l $LG -d build/obj $i + msgfmt --java --statistics -r $CLASS -l $LG -d build/obj $i if [ $? -ne 0 ] then echo 'Warning - msgfmt failed, not updating translations' diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java index 35045d485..90f02596a 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java @@ -232,7 +232,7 @@ public class ConfigNetHandler extends FormHandler { if (_requireIntroductions) { _context.router().setConfigSetting(UDPTransport.PROP_FORCE_INTRODUCERS, "true"); - addFormNotice(_("Requiring SSU introduers")); + addFormNotice(_("Requiring SSU introducers")); } else { _context.router().removeConfigSetting(UDPTransport.PROP_FORCE_INTRODUCERS); } @@ -256,24 +256,26 @@ public class ConfigNetHandler extends FormHandler { if (switchRequired) { hiddenSwitch(); } else if (restartRequired) { - // Wow this dumps all conns immediately and really isn't nice - //addFormNotice("Performing a soft restart"); - //_context.router().restart(); - //addFormNotice("Soft restart complete"); + if (System.getProperty("wrapper.version") == null) { + // Wow this dumps all conns immediately and really isn't nice + addFormNotice("Performing a soft restart"); + _context.router().restart(); + addFormNotice("Soft restart complete"); - // Most of the time we aren't changing addresses, just enabling or disabling - // things, so let's try just a new routerInfo and see how that works. - // Maybe we should restart if we change addresses though? - // No, this doesn't work well, really need to call SSU Transport externalAddressReceived(), - // but that's hard to get to, and doesn't handle port changes, etc. - // So don't do this... - //_context.router().rebuildRouterInfo(); - //addFormNotice("Router Info rebuilt"); - - // There's a few changes that don't really require restart (e.g. enabling inbound TCP) - // But it would be hard to get right, so just do a restart. - addFormError(_("Gracefully restarting I2P to change published router address")); - _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART); + // Most of the time we aren't changing addresses, just enabling or disabling + // things, so let's try just a new routerInfo and see how that works. + // Maybe we should restart if we change addresses though? + // No, this doesn't work well, really need to call SSU Transport externalAddressReceived(), + // but that's hard to get to, and doesn't handle port changes, etc. + // So don't do this... + //_context.router().rebuildRouterInfo(); + //addFormNotice("Router Info rebuilt"); + } else { + // There's a few changes that don't really require restart (e.g. enabling inbound TCP) + // But it would be hard to get right, so just do a restart. + addFormError(_("Gracefully restarting I2P to change published router address")); + _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART); + } } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java index 657039400..aacdfc91a 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java @@ -54,7 +54,12 @@ public class ConfigRestartBean { long timeRemaining = ctx.router().getShutdownTimeRemaining(); StringBuilder buf = new StringBuilder(128); if ((shuttingDown || restarting) && timeRemaining <= 0) { - buf.append("
").append(_("Shutdown imminent", ctx)).append("
"); + buf.append("
"); + if (restarting) + buf.append(_("Restart imminent", ctx)); + else + buf.append(_("Shutdown imminent", ctx)); + buf.append("
"); } else if (shuttingDown) { buf.append("
"); buf.append(_("Shutdown in {0}", DataHelper.formatDuration(timeRemaining), ctx)); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java index 108b94e52..2be5a4a00 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java @@ -84,7 +84,7 @@ public class ConfigTunnelsHelper extends HelperBase { // buf.append("InboundOutbound\n"); // tunnel depth - buf.append("" + _("Depth") + ":\n"); + buf.append("" + _("Length") + ":\n"); buf.append(""); + buf.append(" "); buf.append(""); buf.append(_("Statistics gathered during this router's uptime")).append(" ("); @@ -69,7 +69,7 @@ public class StatsGenerator { buf.append("

"); - buf.append(group); + buf.append(_(group)); buf.append("

"); buf.append("
    "); out.write(buf.toString()); @@ -88,7 +88,7 @@ public class StatsGenerator { out.write(buf.toString()); buf.setLength(0); } - out.write("

"); + out.write("
\n"); } out.flush(); } @@ -104,7 +104,7 @@ public class StatsGenerator { for (int i = 0; i < periods.length; i++) { if (periods[i] > uptime) break; - renderPeriod(buf, periods[i], "frequency"); + renderPeriod(buf, periods[i], _("frequency")); Frequency curFreq = freq.getFrequency(periods[i]); buf.append(" avg per period: ("); buf.append(num(curFreq.getAverageEventsPerPeriod())); @@ -124,9 +124,9 @@ public class StatsGenerator { buf.append(" using the lifetime of "); buf.append(curFreq.getEventCount()); buf.append(" events)"); - buf.append("
"); + buf.append("
\n"); } - buf.append("
"); + buf.append("
\n"); } private void renderRate(String name, StringBuilder buf) { @@ -138,7 +138,7 @@ public class StatsGenerator { buf.append("
"); } if (rate.getLifetimeEventCount() <= 0) { - buf.append("No lifetime events
"); + buf.append(_("No lifetime events")).append("
\n"); return; } long now = _context.clock().now(); @@ -150,9 +150,9 @@ public class StatsGenerator { if (curRate.getLastCoalesceDate() <= curRate.getCreationDate()) break; buf.append("
  • "); - renderPeriod(buf, periods[i], "rate"); + renderPeriod(buf, periods[i], _("rate")); if (curRate.getLastEventCount() > 0) { - buf.append( "avg value: ("); + buf.append( "").append(_("avg value")).append(": ("); buf.append(num(curRate.getAverageValue())); buf.append(" peak "); buf.append(num(curRate.getExtremeAverageValue())); @@ -181,21 +181,21 @@ public class StatsGenerator { buf.append(num(curRate.getExtremeSaturationLimit())); buf.append(")"); } - buf.append(" events: "); + buf.append(" ").append(_("events")).append(": "); buf.append(curRate.getLastEventCount()); buf.append(" in this period which ended: "); buf.append(DataHelper.formatDuration(now - curRate.getLastCoalesceDate())); buf.append(" ago "); } else { - buf.append(" No events "); + buf.append(" ").append(_("No events")).append(" "); } long numPeriods = curRate.getLifetimePeriods(); if (numPeriods > 0) { double avgFrequency = curRate.getLifetimeEventCount() / (double)numPeriods; double peakFrequency = curRate.getExtremeEventCount(); - buf.append(" (lifetime average: "); + buf.append(" (").append(_("lifetime average")).append(": "); buf.append(num(avgFrequency)); - buf.append(", peak average: "); + buf.append(", ").append(_("peak average")).append(": "); buf.append(curRate.getExtremeEventCount()); buf.append(")"); } @@ -210,16 +210,16 @@ public class StatsGenerator { buf.append("&format=xml\" title=\"Dump stat history as XML\">XML"); buf.append(" in a format RRDTool understands)"); } - buf.append("
  • "); + buf.append("\n"); } // Display the strict average - buf.append("
  • lifetime average value: "); + buf.append("
  • ").append(_("lifetime average value")).append(": "); buf.append(num(rate.getLifetimeAverageValue())); buf.append(" over "); buf.append(rate.getLifetimeEventCount()); buf.append(" events
  • "); buf.append(""); - buf.append("
    "); + buf.append("
    \n"); } private static void renderPeriod(StringBuilder buf, long period, String name) { @@ -240,4 +240,9 @@ public class StatsGenerator { private String _(String s) { return Messages.getString(s, _context); } + + /** translate a string */ + private String _(String s, Object o) { + return Messages.getString(s, o, _context); + } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java index bbffa6c9d..23f297031 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java @@ -19,10 +19,14 @@ public class SummaryBarRenderer { _helper = helper; } + /** + * Note - ensure all links in here are absolute, as the summary bar may be displayed + * on lower-level directory errors. + */ public void renderSummaryHTML(Writer out) throws IOException { StringBuilder buf = new StringBuilder(8*1024); - buf.append("\"")\"")" + - "
    ") .append(_("Addressbook")) .append("\n" + - "") .append(_("Torrents")) .append("\n" + - "") .append(_("Webmail")) @@ -68,7 +72,7 @@ public class SummaryBarRenderer { .append(_("Webserver")) .append("
    \n" + - "

    ") .append(_("I2P Internals")) @@ -76,49 +80,49 @@ public class SummaryBarRenderer { "
    \n" + - "") .append(_("Tunnels")) .append("\n" + - "") .append(_("Peers")) .append("\n" + - "") .append(_("Profiles")) .append("\n" + - "") .append(_("NetDB")) .append("\n" + - "") .append(_("Logs")) .append("\n" + - "") .append(_("Jobs")) .append("\n" + - "") .append(_("Graphs")) .append("\n" + - "") .append(_("Stats")) @@ -130,7 +134,7 @@ public class SummaryBarRenderer { - buf.append("

    ") .append(_("General")) @@ -141,7 +145,7 @@ public class SummaryBarRenderer { .append(_helper.getIdent()) .append(", ") .append(_("never reveal it to anyone")) - .append("\" href=\"netdb.jsp?r=.\" target=\"_top\">") + .append("\" href=\"/netdb.jsp?r=.\" target=\"_top\">") .append(_("Local Identity")) .append("


    \n" + @@ -163,7 +167,7 @@ public class SummaryBarRenderer { .append(_helper.getUptime()) .append("

    \n" + - "

    ") .append(_helper.getReachability()) @@ -172,7 +176,7 @@ public class SummaryBarRenderer { if (_helper.updateAvailable() || _helper.unsignedUpdateAvailable()) { // display all the time so we display the final failure message - buf.append("
    ").append(UpdateHandler.getStatus()); + buf.append(UpdateHandler.getStatus()); if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress"))) { // nothing } else if( @@ -187,7 +191,7 @@ public class SummaryBarRenderer { System.setProperty("net.i2p.router.web.UpdateHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.UpdateHandler.nonce", nonce+""); String uri = _helper.getRequestURI(); - buf.append("
    \n"); + buf.append("

    \n"); buf.append("\n"); if (_helper.updateAvailable()) { buf.append("

    \n"); } @@ -295,6 +296,26 @@ public class TunnelRenderer { return ((Hash)l).toBase64().compareTo(((Hash)r).toBase64()); } } + + private static class CountryComparator implements Comparator { + public CountryComparator(CommSystemFacade comm) { + this.comm = comm; + } + public int compare(Hash l, Hash r) { + // get both countries + String lc = this.comm.getCountry(l); + String rc = this.comm.getCountry(r); + + // make them non-null + lc = (lc == null) ? "zzzz" : lc; + rc = (rc == null) ? "zzzz" : rc; + + // let String handle the rest + return lc.compareTo(rc); + } + + private CommSystemFacade comm; + } private String getCapacity(Hash peer) { RouterInfo info = _context.netDb().lookupRouterInfoLocally(peer); diff --git a/apps/routerconsole/java/strings/Strings.java b/apps/routerconsole/java/strings/Strings.java index cddec4197..0805d479a 100644 --- a/apps/routerconsole/java/strings/Strings.java +++ b/apps/routerconsole/java/strings/Strings.java @@ -52,5 +52,24 @@ class Dummy { _("dark"); _("light"); _("midnight"); + + // stat groups for stats.jsp + _("Bandwidth"); + _("BandwidthLimiter"); + _("ClientMessages"); + _("Encryption"); + _("i2cp"); + _("I2PTunnel"); + _("InNetPool"); + _("JobQueue"); + _("NetworkDatabase"); + _("ntcp"); + _("Peers"); + _("Router"); + _("Stream"); + _("Throttle"); + _("Transport"); + _("Tunnels"); + _("udp"); } } diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp index c422e1016..9a9942c79 100644 --- a/apps/routerconsole/jsp/config.jsp +++ b/apps/routerconsole/jsp/config.jsp @@ -32,15 +32,18 @@

    +<% /******** +*********/ %> +<% /******** +*********/ %>
    " /> <%=intl._("KBps In")%> ()
    " /> <%=intl._("KBps Out")%> ()
    <%=intl._("Share")%> () @@ -121,6 +125,7 @@

    <%=intl._("UDP Configuration:")%>
    <%=intl._("UDP port:")%> " />
    +<% /******** +*********/ %>

    <%=intl._("TCP Configuration")%>:
    <%=intl._("Externally reachable hostname or IP address")%>:
    @@ -163,10 +169,12 @@ <%=intl._("Most of the options above are for special situations, for example where UPnP does not work correctly, or a firewall not under your control is doing harm.")%> <%=intl._("Certain firewalls such as symmetric NATs may not work well with I2P.")%>

    +<% /******** +*********/ %>

    <%=intl._("UPnP is used to communicate with Internet Gateway Devices (IGDs) to detect the external IP address and forward ports.")%> <%=intl._("UPnP support is beta, and may not work for any number of reasons")%>: diff --git a/apps/routerconsole/jsp/configclients.jsp b/apps/routerconsole/jsp/configclients.jsp index 974673b31..b2f39c198 100644 --- a/apps/routerconsole/jsp/configclients.jsp +++ b/apps/routerconsole/jsp/configclients.jsp @@ -39,7 +39,7 @@ button span.hide{ <%=intl._("All changes require restart to take effect.")%>


    " /> -

    <%=intl._("WebApp Configuration")%>

    +

    <%=intl._("WebApp Configuration")%>

    <%=intl._("The Java web applications listed below are started by the webConsole client and run in the same JVM as the router. They are usually web applications accessible through the router console. They may be complete applications (e.g. i2psnark),front-ends to another client or application which must be separately enabled (e.g. susidns, i2ptunnel), or have no web interface at all (e.g. addressbook).")%>

    <%=intl._("A web app may also be disabled by removing the .war file from the webapps directory; however the .war file and web app will reappear when you update your router to a newer version, so disabling the web app here is the preferred method.")%> diff --git a/apps/routerconsole/jsp/configpeer.jsp b/apps/routerconsole/jsp/configpeer.jsp index 8b61f274d..bd5390108 100644 --- a/apps/routerconsole/jsp/configpeer.jsp +++ b/apps/routerconsole/jsp/configpeer.jsp @@ -24,7 +24,7 @@ <% String peer = ""; if (request.getParameter("peer") != null) - peer = request.getParameter("peer"); + peer = net.i2p.data.DataHelper.stripHTML(request.getParameter("peer")); // XSS %>

    diff --git a/apps/routerconsole/jsp/i2ptunnel/index.jsp b/apps/routerconsole/jsp/i2ptunnel/index.jsp index 8c7eefc2e..f3cceda0d 100644 --- a/apps/routerconsole/jsp/i2ptunnel/index.jsp +++ b/apps/routerconsole/jsp/i2ptunnel/index.jsp @@ -3,5 +3,5 @@ -The I2P Tunnel Manager is not currently running. Please visit theClient Configuration page to start it. +The I2P Tunnel Manager is not currently running. Please visit the Client Configuration page to start it. diff --git a/apps/routerconsole/jsp/logs.jsp b/apps/routerconsole/jsp/logs.jsp index 5af8b6afd..5aa0150fb 100644 --- a/apps/routerconsole/jsp/logs.jsp +++ b/apps/routerconsole/jsp/logs.jsp @@ -20,10 +20,10 @@ Encoding: <%=System.getProperty("file.encoding")%>

    " /> -

    Critical Logs

    +

    <%=intl._("Critical Logs")%>

    -

    Router Logs [configure]

    +

    <%=intl._("Router Logs")%> (<%=intl._("configure")%>)

    -

    Service (Wrapper) Logs

    +

    <%=intl._("Service (Wrapper) Logs")%>


    diff --git a/apps/routerconsole/jsp/nowebapp.jsp b/apps/routerconsole/jsp/nowebapp.jsp new file mode 100644 index 000000000..f62ae6b16 --- /dev/null +++ b/apps/routerconsole/jsp/nowebapp.jsp @@ -0,0 +1,16 @@ +<%@page contentType="text/html"%> +<%@page pageEncoding="UTF-8"%> + +<% + response.setStatus(404, "Not Found"); +%> + +<%@include file="css.jsi" %> +<%=intl.title("WebApp Not Found")%> + +<%@include file="summary.jsi" %> +

    <%=intl._("Web Application Not Running")%>

    +
    +<%=intl._("The requested web application is not running.")%> +<%=intl._("Please visit the config clients page to start it.")%> +
    diff --git a/apps/routerconsole/jsp/profiles.jsp b/apps/routerconsole/jsp/profiles.jsp index 035f50b5b..69100e349 100644 --- a/apps/routerconsole/jsp/profiles.jsp +++ b/apps/routerconsole/jsp/profiles.jsp @@ -11,6 +11,7 @@ " /> + " />

    <%=intl._("Banned Peers")%>

    diff --git a/apps/routerconsole/jsp/summary.jsi b/apps/routerconsole/jsp/summary.jsi index 10b71ae2c..fcab70132 100644 --- a/apps/routerconsole/jsp/summary.jsi +++ b/apps/routerconsole/jsp/summary.jsi @@ -11,7 +11,7 @@ // pass the new delay parameter to the iframe newDelay = "?refresh=" + d; if (!"0".equals(d)) - out.print("