forked from I2P_Developers/i2p.i2p
* Translate: Add GNU ngettext (plurals) support
This commit is contained in:
@ -64,6 +64,9 @@ Public domain except as listed below:
|
|||||||
Copyright 2006 Gregory Rubin grrubin@gmail.com
|
Copyright 2006 Gregory Rubin grrubin@gmail.com
|
||||||
See licenses/LICENSE-HashCash.txt
|
See licenses/LICENSE-HashCash.txt
|
||||||
|
|
||||||
|
GettextResource from gettext v0.18:
|
||||||
|
Copyright (C) 2001, 2007 Free Software Foundation, Inc.
|
||||||
|
See licenses/LICENSE-LGPLv2.1.txt
|
||||||
|
|
||||||
|
|
||||||
Router:
|
Router:
|
||||||
|
@ -430,4 +430,9 @@ public class I2PSnarkUtil {
|
|||||||
public String getString(String s, Object o, Object o2) {
|
public String getString(String s, Object o, Object o2) {
|
||||||
return Translate.getString(s, o, o2, _context, BUNDLE_NAME);
|
return Translate.getString(s, o, o2, _context, BUNDLE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** ngettext @since 0.7.14 */
|
||||||
|
public String getString(int n, String s, String p) {
|
||||||
|
return Translate.getString(n, s, p, _context, BUNDLE_NAME);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,10 +269,10 @@ public class I2PSnarkServlet extends Default {
|
|||||||
" <th align=\"left\" colspan=\"2\">");
|
" <th align=\"left\" colspan=\"2\">");
|
||||||
out.write(_("Totals"));
|
out.write(_("Totals"));
|
||||||
out.write(" (");
|
out.write(" (");
|
||||||
out.write(_("{0} torrents", snarks.size()));
|
out.write(ngettext("1 torrent", "{0} torrents", snarks.size()));
|
||||||
out.write(", ");
|
out.write(", ");
|
||||||
out.write(DataHelper.formatSize2(stats[5]) + "B, ");
|
out.write(DataHelper.formatSize2(stats[5]) + "B, ");
|
||||||
out.write(_("{0} connected peers", stats[4]));
|
out.write(ngettext("1 connected peer", "{0} connected peers", (int) stats[4]));
|
||||||
out.write(")</th>\n" +
|
out.write(")</th>\n" +
|
||||||
" <th> </th>\n" +
|
" <th> </th>\n" +
|
||||||
" <th align=\"right\">" + formatSize(stats[0]) + "</th>\n" +
|
" <th align=\"right\">" + formatSize(stats[0]) + "</th>\n" +
|
||||||
@ -629,10 +629,12 @@ public class I2PSnarkServlet extends Default {
|
|||||||
if (err != null) {
|
if (err != null) {
|
||||||
if (isRunning && curPeers > 0 && !showPeers)
|
if (isRunning && curPeers > 0 && !showPeers)
|
||||||
statusString = "<a title=\"" + err + "\">" + _("TrackerErr") + "</a> (" +
|
statusString = "<a title=\"" + err + "\">" + _("TrackerErr") + "</a> (" +
|
||||||
curPeers + "/" + knownPeers +
|
"<a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
|
||||||
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + _("peers") + "</a>)";
|
curPeers + '/' +
|
||||||
|
ngettext("1 peer", "{0} peers", knownPeers) + "</a>)";
|
||||||
else if (isRunning)
|
else if (isRunning)
|
||||||
statusString = "<a title=\"" + err + "\">" + _("TrackerErr") + " (" + curPeers + '/' + knownPeers + ' ' + _("peers") + ')';
|
statusString = "<a title=\"" + err + "\">" + _("TrackerErr") + " (" + curPeers + '/' +
|
||||||
|
ngettext("1 peer", "{0} peers", knownPeers) + ')';
|
||||||
else {
|
else {
|
||||||
if (err.length() > MAX_DISPLAYED_ERROR_LENGTH)
|
if (err.length() > MAX_DISPLAYED_ERROR_LENGTH)
|
||||||
err = err.substring(0, MAX_DISPLAYED_ERROR_LENGTH) + "…";
|
err = err.substring(0, MAX_DISPLAYED_ERROR_LENGTH) + "…";
|
||||||
@ -641,25 +643,31 @@ public class I2PSnarkServlet extends Default {
|
|||||||
} else if (remaining <= 0) {
|
} else if (remaining <= 0) {
|
||||||
if (isRunning && curPeers > 0 && !showPeers)
|
if (isRunning && curPeers > 0 && !showPeers)
|
||||||
statusString = _("Seeding") + " (" +
|
statusString = _("Seeding") + " (" +
|
||||||
curPeers + '/' + knownPeers +
|
"<a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
|
||||||
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + _("peers") + "</a>)";
|
curPeers + '/' +
|
||||||
|
ngettext("1 peer", "{0} peers", knownPeers) + "</a>)";
|
||||||
else if (isRunning)
|
else if (isRunning)
|
||||||
statusString = _("Seeding") + " (" + curPeers + "/" + knownPeers + ' ' + _("peers") + ')';
|
statusString = _("Seeding") + " (" + curPeers + "/" +
|
||||||
|
ngettext("1 peer", "{0} peers", knownPeers) + ')';
|
||||||
else
|
else
|
||||||
statusString = _("Complete");
|
statusString = _("Complete");
|
||||||
} else {
|
} else {
|
||||||
if (isRunning && curPeers > 0 && downBps > 0 && !showPeers)
|
if (isRunning && curPeers > 0 && downBps > 0 && !showPeers)
|
||||||
statusString = _("OK") + " (" +
|
statusString = _("OK") + " (" +
|
||||||
curPeers + "/" + knownPeers +
|
"<a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
|
||||||
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + _("peers") + "</a>)";
|
curPeers + "/" +
|
||||||
|
ngettext("1 peer", "{0} peers", knownPeers) + "</a>)";
|
||||||
else if (isRunning && curPeers > 0 && downBps > 0)
|
else if (isRunning && curPeers > 0 && downBps > 0)
|
||||||
statusString = _("OK") + " (" + curPeers + "/" + knownPeers + ' ' + _("peers") + ')';
|
statusString = _("OK") + " (" + curPeers + "/" +
|
||||||
|
ngettext("1 peer", "{0} peers", knownPeers) + ')';
|
||||||
else if (isRunning && curPeers > 0 && !showPeers)
|
else if (isRunning && curPeers > 0 && !showPeers)
|
||||||
statusString = _("Stalled") + " (" +
|
statusString = _("Stalled") + " (" +
|
||||||
curPeers + '/' + knownPeers +
|
"<a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
|
||||||
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + _("peers") + "</a>)";
|
curPeers + '/' +
|
||||||
|
ngettext("1 peer", "{0} peers", knownPeers) + "</a>)";
|
||||||
else if (isRunning && curPeers > 0)
|
else if (isRunning && curPeers > 0)
|
||||||
statusString = _("Stalled") + " (" + curPeers + '/' + knownPeers + ' ' + _("peers") + ')';
|
statusString = _("Stalled") + " (" + curPeers + '/' +
|
||||||
|
ngettext("1 peer", "{0} peers", knownPeers) + ')';
|
||||||
else if (isRunning)
|
else if (isRunning)
|
||||||
statusString = _("No Peers") + " (0/" + knownPeers + ')';
|
statusString = _("No Peers") + " (0/" + knownPeers + ')';
|
||||||
else
|
else
|
||||||
@ -1078,11 +1086,11 @@ public class I2PSnarkServlet extends Default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** copied from ConfigTunnelsHelper */
|
/** copied from ConfigTunnelsHelper */
|
||||||
private static final String HOP = _x("hop");
|
private static final String HOP = "hop";
|
||||||
private static final String TUNNEL = _x("tunnel");
|
private static final String TUNNEL = "tunnel";
|
||||||
/** dummies for translation */
|
/** dummies for translation */
|
||||||
private static final String HOPS = _x("hops");
|
private static final String HOPS = ngettext("1 hop", "{0} hops");
|
||||||
private static final String TUNNELS = _x("tunnels");
|
private static final String TUNNELS = ngettext("1 tunnel", "{0} tunnels");
|
||||||
|
|
||||||
/** modded from ConfigTunnelsHelper @since 0.7.14 */
|
/** modded from ConfigTunnelsHelper @since 0.7.14 */
|
||||||
private String renderOptions(int min, int max, String strNow, String selName, String name) {
|
private String renderOptions(int min, int max, String strNow, String selName, String name) {
|
||||||
@ -1096,13 +1104,7 @@ public class I2PSnarkServlet extends Default {
|
|||||||
buf.append("<option value=\"").append(i).append("\" ");
|
buf.append("<option value=\"").append(i).append("\" ");
|
||||||
if (i == now)
|
if (i == now)
|
||||||
buf.append("selected=\"true\" ");
|
buf.append("selected=\"true\" ");
|
||||||
String pname;
|
buf.append(">").append(ngettext("1 " + name, "{0} " + name + 's', i));
|
||||||
// pluralize and then translate
|
|
||||||
if (i != 1 && i != -1)
|
|
||||||
pname = name + 's';
|
|
||||||
else
|
|
||||||
pname = name;
|
|
||||||
buf.append(">").append(i).append(' ').append(_(pname));
|
|
||||||
buf.append("</option>\n");
|
buf.append("</option>\n");
|
||||||
}
|
}
|
||||||
buf.append("</select>\n");
|
buf.append("</select>\n");
|
||||||
@ -1119,9 +1121,14 @@ public class I2PSnarkServlet extends Default {
|
|||||||
return _manager.util().getString(s, o);
|
return _manager.util().getString(s, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** translate (ngettext) @since 0.7.14 */
|
||||||
|
private String ngettext(String s, String p, int n) {
|
||||||
|
return _manager.util().getString(n, s, p);
|
||||||
|
}
|
||||||
|
|
||||||
/** dummy for tagging */
|
/** dummy for tagging */
|
||||||
private static String _x(String s) {
|
private static String ngettext(String s, String p) {
|
||||||
return s;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rounding makes us look faster :)
|
// rounding makes us look faster :)
|
||||||
|
@ -16,6 +16,8 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Poedit-Language: Russian\n"
|
"X-Poedit-Language: Russian\n"
|
||||||
|
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%"
|
||||||
|
"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
|
||||||
|
|
||||||
#: ../java/src/org/klomp/snark/SnarkManager.java:87
|
#: ../java/src/org/klomp/snark/SnarkManager.java:87
|
||||||
#, java-format
|
#, java-format
|
||||||
|
@ -16,6 +16,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Poedit-Language: Chinese\n"
|
"X-Poedit-Language: Chinese\n"
|
||||||
|
"Plural-Forms: nplurals=1; plural=0\n"
|
||||||
|
|
||||||
#: ../java/src/org/klomp/snark/SnarkManager.java:84
|
#: ../java/src/org/klomp/snark/SnarkManager.java:84
|
||||||
#, java-format
|
#, java-format
|
||||||
|
@ -8,11 +8,11 @@ import net.i2p.data.Destination;
|
|||||||
import net.i2p.router.TunnelPoolSettings;
|
import net.i2p.router.TunnelPoolSettings;
|
||||||
|
|
||||||
public class ConfigTunnelsHelper extends HelperBase {
|
public class ConfigTunnelsHelper extends HelperBase {
|
||||||
static final String HOP = _x("hop");
|
private static final String HOP = "hop";
|
||||||
static final String TUNNEL = _x("tunnel");
|
private static final String TUNNEL = "tunnel";
|
||||||
/** dummies for translation */
|
/** dummies for translation */
|
||||||
static final String HOPS = _x("hops");
|
private static final String HOPS = ngettext("1 hop", "{0} hops");
|
||||||
static final String TUNNELS = _x("tunnels");
|
private static final String TUNNELS = ngettext("1 tunnel", "{0} tunnels");
|
||||||
|
|
||||||
public ConfigTunnelsHelper() {}
|
public ConfigTunnelsHelper() {}
|
||||||
|
|
||||||
@ -196,14 +196,13 @@ public class ConfigTunnelsHelper extends HelperBase {
|
|||||||
buf.append("<option value=\"").append(i).append("\" ");
|
buf.append("<option value=\"").append(i).append("\" ");
|
||||||
if (i == now)
|
if (i == now)
|
||||||
buf.append("selected=\"true\" ");
|
buf.append("selected=\"true\" ");
|
||||||
String pname;
|
buf.append(">").append(_(i, "1 " + name, "{0} " + name + 's'));
|
||||||
// pluralize and then translate
|
|
||||||
if (i != 1 && i != -1)
|
|
||||||
pname = name + 's';
|
|
||||||
else
|
|
||||||
pname = name;
|
|
||||||
buf.append(">").append(prefix).append(i).append(' ').append(_(pname));
|
|
||||||
buf.append("</option>\n");
|
buf.append("</option>\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** dummy for tagging */
|
||||||
|
private static String ngettext(String s, String p) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,11 @@ public abstract class HelperBase {
|
|||||||
return Messages.getString(s, o, _context);
|
return Messages.getString(s, o, _context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** translate (ngettext) @since 0.7.14 */
|
||||||
|
public String _(int n, String s, String p) {
|
||||||
|
return Messages.getString(n, s, p, _context);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark a string for extraction by xgettext and translation.
|
* Mark a string for extraction by xgettext and translation.
|
||||||
* Use this only in static initializers.
|
* Use this only in static initializers.
|
||||||
|
@ -29,4 +29,9 @@ public class Messages extends Translate {
|
|||||||
public static String getString(String s, Object o, I2PAppContext ctx) {
|
public static String getString(String s, Object o, I2PAppContext ctx) {
|
||||||
return Translate.getString(s, o, ctx, BUNDLE_NAME);
|
return Translate.getString(s, o, ctx, BUNDLE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** translate (ngettext) @since 0.7.14 */
|
||||||
|
public static String getString(int n, String s, String p, I2PAppContext ctx) {
|
||||||
|
return Translate.getString(n, s, p, ctx, BUNDLE_NAME);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Poedit-Language: Russian\n"
|
"X-Poedit-Language: Russian\n"
|
||||||
|
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%"
|
||||||
|
"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
|
||||||
"X-Poedit-Bookmarks: 283,-1,-1,-1,-1,-1,-1,-1,-1,-1\n"
|
"X-Poedit-Bookmarks: 283,-1,-1,-1,-1,-1,-1,-1,-1,-1\n"
|
||||||
|
|
||||||
#: ../../../router/java/src/net/i2p/router/Blocklist.java:126
|
#: ../../../router/java/src/net/i2p/router/Blocklist.java:126
|
||||||
|
@ -17,6 +17,7 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Poedit-Language: Chinese\n"
|
"X-Poedit-Language: Chinese\n"
|
||||||
"X-Poedit-Country: CHINA\n"
|
"X-Poedit-Country: CHINA\n"
|
||||||
|
"Plural-Forms: nplurals=1; plural=0\n"
|
||||||
|
|
||||||
#: ../../../router/java/src/net/i2p/router/Blocklist.java:117
|
#: ../../../router/java/src/net/i2p/router/Blocklist.java:117
|
||||||
#, java-format
|
#, java-format
|
||||||
|
269
core/java/src/gnu/gettext/GettextResource.java
Normal file
269
core/java/src/gnu/gettext/GettextResource.java
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
/* GNU gettext for Java
|
||||||
|
* Copyright (C) 2001, 2007 Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Library General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package gnu.gettext;
|
||||||
|
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements the main GNU libintl functions in Java.
|
||||||
|
* <P>
|
||||||
|
* Using the GNU gettext approach, compiled message catalogs are normal
|
||||||
|
* Java ResourceBundle classes and are thus interoperable with standard
|
||||||
|
* ResourceBundle based code.
|
||||||
|
* <P>
|
||||||
|
* The main differences between the Sun ResourceBundle approach and the
|
||||||
|
* GNU gettext approach are:
|
||||||
|
* <UL>
|
||||||
|
* <LI>In the Sun approach, the keys are abstract textual shortcuts.
|
||||||
|
* In the GNU gettext approach, the keys are the English/ASCII version
|
||||||
|
* of the messages.
|
||||||
|
* <LI>In the Sun approach, the translation files are called
|
||||||
|
* "<VAR>Resource</VAR>_<VAR>locale</VAR>.properties" and have non-ASCII
|
||||||
|
* characters encoded in the Java
|
||||||
|
* <CODE>\</CODE><CODE>u<VAR>nnnn</VAR></CODE> syntax. Very few editors
|
||||||
|
* can natively display international characters in this format. In the
|
||||||
|
* GNU gettext approach, the translation files are called
|
||||||
|
* "<VAR>Resource</VAR>.<VAR>locale</VAR>.po"
|
||||||
|
* and are in the encoding the translator has chosen. Many editors
|
||||||
|
* can be used. There are at least three GUI translating tools
|
||||||
|
* (Emacs PO mode, KDE KBabel, GNOME gtranslator).
|
||||||
|
* <LI>In the Sun approach, the function
|
||||||
|
* <CODE>ResourceBundle.getString</CODE> throws a
|
||||||
|
* <CODE>MissingResourceException</CODE> when no translation is found.
|
||||||
|
* In the GNU gettext approach, the <CODE>gettext</CODE> function
|
||||||
|
* returns the (English) message key in that case.
|
||||||
|
* <LI>In the Sun approach, there is no support for plural handling.
|
||||||
|
* Even the most elaborate MessageFormat strings cannot provide decent
|
||||||
|
* plural handling. In the GNU gettext approach, we have the
|
||||||
|
* <CODE>ngettext</CODE> function.
|
||||||
|
* </UL>
|
||||||
|
* <P>
|
||||||
|
* To compile GNU gettext message catalogs into Java ResourceBundle classes,
|
||||||
|
* the <CODE>msgfmt</CODE> program can be used.
|
||||||
|
*
|
||||||
|
* @author Bruno Haible
|
||||||
|
*/
|
||||||
|
public abstract class GettextResource extends ResourceBundle {
|
||||||
|
|
||||||
|
public static boolean verbose = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like gettext(catalog,msgid), except that it returns <CODE>null</CODE>
|
||||||
|
* when no translation was found.
|
||||||
|
*/
|
||||||
|
private static String gettextnull (ResourceBundle catalog, String msgid) {
|
||||||
|
try {
|
||||||
|
return (String)catalog.getObject(msgid);
|
||||||
|
} catch (MissingResourceException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the translation of <VAR>msgid</VAR>.
|
||||||
|
* @param catalog a ResourceBundle
|
||||||
|
* @param msgid the key string to be translated, an ASCII string
|
||||||
|
* @return the translation of <VAR>msgid</VAR>, or <VAR>msgid</VAR> if
|
||||||
|
* none is found
|
||||||
|
*/
|
||||||
|
public static String gettext (ResourceBundle catalog, String msgid) {
|
||||||
|
String result = gettextnull(catalog,msgid);
|
||||||
|
if (result != null)
|
||||||
|
return result;
|
||||||
|
return msgid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like ngettext(catalog,msgid,msgid_plural,n), except that it returns
|
||||||
|
* <CODE>null</CODE> when no translation was found.
|
||||||
|
*/
|
||||||
|
private static String ngettextnull (ResourceBundle catalog, String msgid, long n) {
|
||||||
|
// The reason why we use so many reflective API calls instead of letting
|
||||||
|
// the GNU gettext generated ResourceBundles implement some interface,
|
||||||
|
// is that we want the generated ResourceBundles to be completely
|
||||||
|
// standalone, so that migration from the Sun approach to the GNU gettext
|
||||||
|
// approach (without use of plurals) is as straightforward as possible.
|
||||||
|
ResourceBundle origCatalog = catalog;
|
||||||
|
do {
|
||||||
|
// Try catalog itself.
|
||||||
|
if (verbose)
|
||||||
|
System.out.println("ngettext on "+catalog);
|
||||||
|
Method handleGetObjectMethod = null;
|
||||||
|
Method getParentMethod = null;
|
||||||
|
try {
|
||||||
|
handleGetObjectMethod = catalog.getClass().getMethod("handleGetObject", new Class[] { java.lang.String.class });
|
||||||
|
getParentMethod = catalog.getClass().getMethod("getParent", new Class[0]);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
}
|
||||||
|
if (verbose)
|
||||||
|
System.out.println("handleGetObject = "+(handleGetObjectMethod!=null)+", getParent = "+(getParentMethod!=null));
|
||||||
|
if (handleGetObjectMethod != null
|
||||||
|
&& Modifier.isPublic(handleGetObjectMethod.getModifiers())
|
||||||
|
&& getParentMethod != null) {
|
||||||
|
// A GNU gettext created class.
|
||||||
|
Method lookupMethod = null;
|
||||||
|
Method pluralEvalMethod = null;
|
||||||
|
try {
|
||||||
|
lookupMethod = catalog.getClass().getMethod("lookup", new Class[] { java.lang.String.class });
|
||||||
|
pluralEvalMethod = catalog.getClass().getMethod("pluralEval", new Class[] { Long.TYPE });
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
}
|
||||||
|
if (verbose)
|
||||||
|
System.out.println("lookup = "+(lookupMethod!=null)+", pluralEval = "+(pluralEvalMethod!=null));
|
||||||
|
if (lookupMethod != null && pluralEvalMethod != null) {
|
||||||
|
// A GNU gettext created class with plural handling.
|
||||||
|
Object localValue = null;
|
||||||
|
try {
|
||||||
|
localValue = lookupMethod.invoke(catalog, new Object[] { msgid });
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.getTargetException().printStackTrace();
|
||||||
|
}
|
||||||
|
if (localValue != null) {
|
||||||
|
if (verbose)
|
||||||
|
System.out.println("localValue = "+localValue);
|
||||||
|
if (localValue instanceof String)
|
||||||
|
// Found the value. It doesn't depend on n in this case.
|
||||||
|
return (String)localValue;
|
||||||
|
else {
|
||||||
|
String[] pluralforms = (String[])localValue;
|
||||||
|
long i = 0;
|
||||||
|
try {
|
||||||
|
i = ((Long) pluralEvalMethod.invoke(catalog, new Object[] { new Long(n) })).longValue();
|
||||||
|
if (!(i >= 0 && i < pluralforms.length))
|
||||||
|
i = 0;
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.getTargetException().printStackTrace();
|
||||||
|
}
|
||||||
|
return pluralforms[(int)i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// A GNU gettext created class without plural handling.
|
||||||
|
Object localValue = null;
|
||||||
|
try {
|
||||||
|
localValue = handleGetObjectMethod.invoke(catalog, new Object[] { msgid });
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.getTargetException().printStackTrace();
|
||||||
|
}
|
||||||
|
if (localValue != null) {
|
||||||
|
// Found the value. It doesn't depend on n in this case.
|
||||||
|
if (verbose)
|
||||||
|
System.out.println("localValue = "+localValue);
|
||||||
|
return (String)localValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object parentCatalog = catalog;
|
||||||
|
try {
|
||||||
|
parentCatalog = getParentMethod.invoke(catalog, new Object[0]);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.getTargetException().printStackTrace();
|
||||||
|
}
|
||||||
|
if (parentCatalog != catalog)
|
||||||
|
catalog = (ResourceBundle)parentCatalog;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
// Not a GNU gettext created class.
|
||||||
|
break;
|
||||||
|
} while (catalog != null);
|
||||||
|
// The end of chain of GNU gettext ResourceBundles is reached.
|
||||||
|
if (catalog != null) {
|
||||||
|
// For a non-GNU ResourceBundle we cannot access 'parent' and
|
||||||
|
// 'handleGetObject', so make a single call to catalog and all
|
||||||
|
// its parent catalogs at once.
|
||||||
|
Object value;
|
||||||
|
try {
|
||||||
|
value = catalog.getObject(msgid);
|
||||||
|
} catch (MissingResourceException e) {
|
||||||
|
value = null;
|
||||||
|
}
|
||||||
|
if (value != null)
|
||||||
|
// Found the value. It doesn't depend on n in this case.
|
||||||
|
return (String)value;
|
||||||
|
}
|
||||||
|
// Default: null.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the plural form for <VAR>n</VAR> of the translation of
|
||||||
|
* <VAR>msgid</VAR>.
|
||||||
|
* @param catalog a ResourceBundle
|
||||||
|
* @param msgid the key string to be translated, an ASCII string
|
||||||
|
* @param msgid_plural its English plural form
|
||||||
|
* @return the translation of <VAR>msgid</VAR> depending on <VAR>n</VAR>,
|
||||||
|
* or <VAR>msgid</VAR> or <VAR>msgid_plural</VAR> if none is found
|
||||||
|
*/
|
||||||
|
public static String ngettext (ResourceBundle catalog, String msgid, String msgid_plural, long n) {
|
||||||
|
String result = ngettextnull(catalog,msgid,n);
|
||||||
|
if (result != null)
|
||||||
|
return result;
|
||||||
|
// Default: English strings and Germanic plural rule.
|
||||||
|
return (n != 1 ? msgid_plural : msgid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The separator between msgctxt and msgid. */
|
||||||
|
private static final String CONTEXT_GLUE = "\u0004";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the translation of <VAR>msgid</VAR> in the context of
|
||||||
|
* <VAR>msgctxt</VAR>.
|
||||||
|
* @param catalog a ResourceBundle
|
||||||
|
* @param msgctxt the context for the key string, an ASCII string
|
||||||
|
* @param msgid the key string to be translated, an ASCII string
|
||||||
|
* @return the translation of <VAR>msgid</VAR>, or <VAR>msgid</VAR> if
|
||||||
|
* none is found
|
||||||
|
*/
|
||||||
|
public static String pgettext (ResourceBundle catalog, String msgctxt, String msgid) {
|
||||||
|
String result = gettextnull(catalog,msgctxt+CONTEXT_GLUE+msgid);
|
||||||
|
if (result != null)
|
||||||
|
return result;
|
||||||
|
return msgid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the plural form for <VAR>n</VAR> of the translation of
|
||||||
|
* <VAR>msgid</VAR> in the context of <VAR>msgctxt</VAR>.
|
||||||
|
* @param catalog a ResourceBundle
|
||||||
|
* @param msgctxt the context for the key string, an ASCII string
|
||||||
|
* @param msgid the key string to be translated, an ASCII string
|
||||||
|
* @param msgid_plural its English plural form
|
||||||
|
* @return the translation of <VAR>msgid</VAR> depending on <VAR>n</VAR>,
|
||||||
|
* or <VAR>msgid</VAR> or <VAR>msgid_plural</VAR> if none is found
|
||||||
|
*/
|
||||||
|
public static String npgettext (ResourceBundle catalog, String msgctxt, String msgid, String msgid_plural, long n) {
|
||||||
|
String result = ngettextnull(catalog,msgctxt+CONTEXT_GLUE+msgid,n);
|
||||||
|
if (result != null)
|
||||||
|
return result;
|
||||||
|
// Default: English strings and Germanic plural rule.
|
||||||
|
return (n != 1 ? msgid_plural : msgid);
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,8 @@ import java.util.ResourceBundle;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import gnu.gettext.GettextResource;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.util.ConcurrentHashSet;
|
import net.i2p.util.ConcurrentHashSet;
|
||||||
|
|
||||||
@ -102,6 +104,40 @@ public abstract class Translate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use GNU ngettext
|
||||||
|
* For .po file format see http://www.gnu.org/software/gettext/manual/gettext.html.gz#Translating-plural-forms
|
||||||
|
*
|
||||||
|
* @param n how many
|
||||||
|
* @param s singluar string, optionally with {0} e.g. "one tunnel"
|
||||||
|
* @param s plural string optionally with {0} e.g. "{0} tunnels"
|
||||||
|
* @since 0.7.14
|
||||||
|
*/
|
||||||
|
public static String getString(int n, String s, String p, I2PAppContext ctx, String bun) {
|
||||||
|
String lang = getLanguage(ctx);
|
||||||
|
if (lang.equals(TEST_LANG))
|
||||||
|
return TEST_STRING + '(' + n + ')' + TEST_STRING;
|
||||||
|
ResourceBundle bundle = null;
|
||||||
|
if (!lang.equals("en"))
|
||||||
|
bundle = findBundle(bun, lang);
|
||||||
|
String x;
|
||||||
|
if (bundle == null)
|
||||||
|
x = n == 1 ? s : p;
|
||||||
|
else
|
||||||
|
x = GettextResource.ngettext(bundle, s, p, n);
|
||||||
|
Object[] oArray = new Object[1];
|
||||||
|
oArray[0] = Integer.valueOf(n);
|
||||||
|
try {
|
||||||
|
MessageFormat fmt = new MessageFormat(x, new Locale(lang));
|
||||||
|
return fmt.format(oArray, new StringBuffer(), null).toString();
|
||||||
|
} catch (IllegalArgumentException iae) {
|
||||||
|
System.err.println("Bad format: sing: \"" + s +
|
||||||
|
"\" plural: \"" + p +
|
||||||
|
"\" lang: " + lang);
|
||||||
|
return "FIXME: " + s + ' ' + p + ',' + n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @return lang in routerconsole.lang property, else current locale */
|
/** @return lang in routerconsole.lang property, else current locale */
|
||||||
public static String getLanguage(I2PAppContext ctx) {
|
public static String getLanguage(I2PAppContext ctx) {
|
||||||
String lang = ctx.getProperty(PROP_LANG);
|
String lang = ctx.getProperty(PROP_LANG);
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
2010-05-27 zzz
|
||||||
|
* Translate: Add GNU ngettext (plurals) support
|
||||||
|
|
||||||
2010-05-26 zzz
|
2010-05-26 zzz
|
||||||
* i2psnark: Listing fixes and cleanups;
|
* i2psnark: Listing fixes and cleanups;
|
||||||
icons on front page; tweak bw choker again
|
icons on front page; tweak bw choker again
|
||||||
|
@ -18,7 +18,7 @@ public class RouterVersion {
|
|||||||
/** deprecated */
|
/** deprecated */
|
||||||
public final static String ID = "Monotone";
|
public final static String ID = "Monotone";
|
||||||
public final static String VERSION = CoreVersion.VERSION;
|
public final static String VERSION = CoreVersion.VERSION;
|
||||||
public final static long BUILD = 12;
|
public final static long BUILD = 13;
|
||||||
|
|
||||||
/** for example "-test" */
|
/** for example "-test" */
|
||||||
public final static String EXTRA = "";
|
public final static String EXTRA = "";
|
||||||
|
Reference in New Issue
Block a user