Merge branch 'master' of i2pgit.org:i2p-hackers/i2p.i2p

This commit is contained in:
eyedeekay
2024-07-27 13:43:56 -04:00
34 changed files with 2522 additions and 238 deletions
@@ -33,9 +33,14 @@ abstract class FilterDefinitionElement {
* Utility method to create a Hash object from a .b32 string
*/
protected static Hash fromBase32(String b32) throws InvalidDefinitionException {
if (b32.length() != 60)
throw new InvalidDefinitionException("Invalid b32 " + b32);
if (!b32.endsWith(".b32.i2p"))
throw new InvalidDefinitionException("Invalid b32 " + b32);
b32 = b32.substring(0, b32.length() - 8);
return new Hash(Base32.decode(b32));
String s = b32.substring(0, 52);
byte[] b = Base32.decode(s);
if (b == null)
throw new InvalidDefinitionException("Invalid b32 " + b32);
return Hash.create(b);
}
}
+1
View File
@@ -16,6 +16,7 @@ sourceSets {
dependencies {
implementation project(':core')
implementation project(':apps:jetty')
implementation project(':apps:jrobin')
implementation fileTree("../jetty/apache-tomcat-${tomcatVersion}")
}
@@ -153,7 +153,7 @@ public class NineBlockIdenticonRenderer2 implements IdenticonRenderer {
}
public BufferedImage render(BigInteger code, int size) {
return renderQuilt(code.intValue(), size);
return renderQuilt(null, code.intValue(), size);
}
/**
@@ -172,10 +172,22 @@ public class NineBlockIdenticonRenderer2 implements IdenticonRenderer {
* @return identicon image
*/
public BufferedImage render(int code, int size) {
return renderQuilt(code, size);
return renderQuilt(null, code, size);
}
protected BufferedImage renderQuilt(int code, int size) {
/**
* @param g custom Graphics2D or null
* @since 0.9.64
*/
public BufferedImage render(Graphics2D g, int code, int size) {
return renderQuilt(g, code, size);
}
/**
* @param gg custom Graphics2D or null
* @since 0.9.64
*/
protected BufferedImage renderQuilt(Graphics2D gg, int code, int size) {
// -------------------------------------------------
// PREPARE
//
@@ -220,9 +232,15 @@ public class NineBlockIdenticonRenderer2 implements IdenticonRenderer {
// RENDER
//
BufferedImage targetImage = new BufferedImage(size, size,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = targetImage.createGraphics();
BufferedImage targetImage = null;
Graphics2D g;
if (gg != null) {
g = gg;
} else {
targetImage = new BufferedImage(size, size,
BufferedImage.TYPE_INT_RGB);
g = targetImage.createGraphics();
}
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
@@ -256,7 +274,8 @@ public class NineBlockIdenticonRenderer2 implements IdenticonRenderer {
drawPatch(g, 0, blockSize2, blockSize, cornerType, cornerTurn++,
cornerInvert, fillColor, strokeColor);
g.dispose();
if (gg == null)
g.dispose();
return targetImage;
}
+1
View File
@@ -8,6 +8,7 @@
<pathelement location="../identicon/build/identicon.jar" />
<pathelement location="../zxing/build/zxing.jar" />
<pathelement location="../../../build/i2p.jar" />
<pathelement location="../../../build/jrobin.jar" />
</path>
<target name="all" depends="war" />
@@ -19,6 +19,7 @@ import com.docuverse.identicon.NineBlockIdenticonRenderer2;
import net.i2p.I2PAppContext;
import net.i2p.data.Hash;
import net.i2p.rrd4j.SimpleSVGGraphics2D;
import net.i2p.util.ConvertToHash;
import net.i2p.util.Log;
@@ -67,10 +68,10 @@ public class IdenticonServlet extends HttpServlet {
private static final String PARAM_IDENTICON_SIZE_SHORT = "s";
private static final String PARAM_IDENTICON_CODE_SHORT = "c";
private static final String IDENTICON_IMAGE_FORMAT = "PNG";
private static final String IDENTICON_IMAGE_MIMETYPE = "image/png";
private static final String IDENTICON_IMAGE_MIMETYPE = "image/svg+xml";
private static final long DEFAULT_IDENTICON_EXPIRES_IN_MILLIS = 24 * 60 * 60 * 1000;
private int version = 1;
private final IdenticonRenderer renderer = new NineBlockIdenticonRenderer2();
private final NineBlockIdenticonRenderer2 renderer = new NineBlockIdenticonRenderer2();
private IdenticonCache cache;
private long identiconExpiresInMillis = DEFAULT_IDENTICON_EXPIRES_IN_MILLIS;
@@ -147,6 +148,7 @@ public class IdenticonServlet extends HttpServlet {
// retrieve image bytes from either cache or renderer
if (cache == null
|| (imageBytes = cache.get(identiconETag)) == null) {
/*
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
RenderedImage image;
try {
@@ -160,6 +162,20 @@ public class IdenticonServlet extends HttpServlet {
}
ImageIO.write(image, IDENTICON_IMAGE_FORMAT, byteOut);
imageBytes = byteOut.toByteArray();
*/
SimpleSVGGraphics2D g = new SimpleSVGGraphics2D(size, size);
try {
renderer.render(g, code, size);
} catch (Throwable t) {
// java.lang.NoClassDefFoundError: Could not initialize class java.awt.GraphicsEnvironment$LocalGE
Log log = I2PAppContext.getGlobalContext().logManager().getLog(IdenticonServlet.class);
//log.logAlways(Log.WARN, "Identicon render failure: " + t);
log.error("Identicon render failure", t);
response.setStatus(403);
return;
}
String s = g.getSVG();
imageBytes = s.getBytes("UTF-8");
if (cache != null)
cache.add(identiconETag, imageBytes);
} else {
@@ -178,6 +194,7 @@ public class IdenticonServlet extends HttpServlet {
// return image bytes to requester
response.setContentType(IDENTICON_IMAGE_MIMETYPE);
response.setCharacterEncoding("UTF-8");
response.setHeader("X-Content-Type-Options", "nosniff");
response.setHeader("Accept-Ranges", "none");
response.setContentLength(imageBytes.length);
+3
View File
@@ -37,6 +37,9 @@
encoding="UTF-8"
includes="**/*.java" >
<compilerarg line="${javac.compilerargs}" />
<classpath>
<pathelement location="../../../core/java/build/i2p.jar" />
</classpath>
</javac>
</target>
@@ -0,0 +1,431 @@
package net.i2p.rrd4j;
import java.text.AttributedCharacterIterator;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import static java.awt.geom.PathIterator.*;
import java.awt.image.*;
import java.awt.image.renderable.RenderableImage;
/**
* Very simple SVGGraphics2D, only enough for basic rrd4j use, without dependencies.
* Plus a few things that rrd4j doesn't use, but not much.
* Unsupported things will throw UnsupportedOperationExceptions.
*
* Supports custom RenderingHints for id and class on top-level svg element.
* Supports custom RenderingHints for id, class, title, and arbitrary attributes
* on all drawn elements.
* Supports custom RenderingHints for inner SVG on all drawn elements except text.
*
* No standard Java AWT hints are supported.
* Antialiasing is done automatically.
* Antialiasing hints have no effect.
*
* License: Apache 2.0 (same as rrd4j)
*
* @since 0.9.64
* @author zzz
*/
public class SimpleSVGGraphics2D extends Graphics2D {
//// hints - all strings except for ATTMAP ////
/**
* On the top svg element.
* Value is a string and will be XML-escaped when rendering.
*/
public static final RenderingHints.Key KEY_SVG_ID = new RHKey(1);
/**
* On the top svg element.
* Value is a string and will be XML-escaped when rendering.
*/
public static final RenderingHints.Key KEY_SVG_CLASS = new RHKey(2);
/**
* On the top svg element.
* Value is a string and will be XML-escaped when rendering.
*/
public static final RenderingHints.Key KEY_SVG_TITLE = new RHKey(3);
/**
* On the next element drawn, one-shot, will be removed after rendering.
* Value is a string and will be XML-escaped when rendering.
*/
public static final RenderingHints.Key KEY_ELEMENT_ID = new RHKey(4);
/**
* On the next element drawn, one-shot, will be removed after rendering.
* Value is a string and will be XML-escaped when rendering.
*/
public static final RenderingHints.Key KEY_ELEMENT_CLASS = new RHKey(5);
/**
* Value is a Map of String to String of extra attributes on the next element drawn, one-shot, will be removed after rendering.
* Map keys must be XML-escaped by caller if necessary.
* Map values will be XML-escaped when rendering.
*/
public static final RenderingHints.Key KEY_ELEMENT_ATTMAP = new RHKey(6);
/**
* On the next element drawn, one-shot, will be removed after rendering.
* Value is a string and will be XML-escaped when rendering.
*/
public static final RenderingHints.Key KEY_ELEMENT_TITLE = new RHKey(7);
/**
* Put "inside" the next element drawn, one-shot, will be removed after rendering.
* Value is an XML string and must be XML-escaped by caller if necessary.
*/
public static final RenderingHints.Key KEY_ELEMENT_INNERSVG = new RHKey(8);
private final StringBuilder buf;
private final SimpleSVGMaker svg;
private final Map<Object,Object> hints = new HashMap<Object,Object>();
private AffineTransform transform = new AffineTransform();
private final FontRenderContext frctx = new FontRenderContext(transform, true, true);
private final int width, height;
private final Rectangle origclip;
// null unless different from origclip
private Rectangle clip;
private String clipID;
private Color bgcolor = Color.WHITE;
private Paint paint = Color.BLACK;
private Stroke stroke = new BasicStroke(1);
private Font font = new Font(Font.SANS_SERIF, Font.PLAIN, 12);
private boolean started;
public SimpleSVGGraphics2D(int width, int height) {
this.width = width;
this.height = height;
origclip = new Rectangle(0, 0, width, height);
buf = new StringBuilder(16*1024);
svg = new SimpleSVGMaker(buf);
}
public String getSVG() {
stop();
String rv = buf.toString();
dispose();
return rv;
}
private void start() {
if (!started) {
String id = (String) hints.remove(KEY_SVG_ID);
String cl = (String) hints.remove(KEY_SVG_CLASS);
svg.startSVG(width, height, bgcolor, id, cl);
started = true;
}
}
private void stop() {
if (started) {
if (!transform.isIdentity()) {
svg.endGroup();
transform = frctx.getTransform();
}
svg.endSVG();
clip = null;
clipID = null;
started = false;
}
}
public void dispose() { buf.setLength(0); }
//// API bypass ////
/**
* Graphics2D API bypass, advanced use only
*/
public SimpleSVGMaker getMaker() { start(); return svg; }
/**
* Graphics2D API bypass, advanced use only
*/
public void append(String s) { start(); buf.append(s).append('\n'); }
//// draws/fills used by rrd4j ////
public void drawLine(int x1, int y1, int x2, int y2) {
start();
svg.drawLine(x1, y1, x2, y2, (Color) paint, (BasicStroke) stroke, clipID, hints);
}
public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
start();
svg.drawPolyline(xPoints, yPoints, nPoints, (Color) paint, (BasicStroke) stroke, clipID, hints);
}
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
start();
String id = (String) hints.remove(KEY_ELEMENT_ID);
String cl = (String) hints.remove(KEY_ELEMENT_CLASS);
svg.fillPolygon(xPoints, yPoints, nPoints, (Color) paint, clipID, hints);
}
public void fillRect(int x, int y, int width, int height) {
if (!started) {
// rrd4j calls this first with the background color, it does not call setBackground()
if (x == 0 && y == 0 && width == this.width && height == this.height) {
// disable setting the background color, this is it
bgcolor = null;
}
start();
}
svg.drawRect(x, y, width, height, null, (Color) paint, null, clipID, hints);
}
//// text ////
public void drawString(String str, int x, int y) {
start();
svg.drawText(str, x, y, (Color) paint, font, clipID, hints);
}
public void drawString(String str, float x, float y) { drawString(str, (int) x, (int) y); }
public FontRenderContext getFontRenderContext() { return frctx; }
//// supported things not used by rrd4j ////
/**
* Circles only for now, must be width == height and arcAngle == 360
* Otherwise throws UnsupportedOperationException
* TODO
*/
public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
if (width != height || arcAngle != 360)
throw new UnsupportedOperationException("circles only!");
start();
int r = width / 2;
svg.drawCircle(x + r, y + r, r, (Color) paint, null, (BasicStroke) stroke, clipID, hints);
}
/**
* Circles only for now, must be width == height and arcAngle == 360
* Otherwise throws UnsupportedOperationException
* TODO
*/
public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
if (width != height || arcAngle != 360)
throw new UnsupportedOperationException("circles only!");
start();
int r = width / 2;
svg.drawCircle(x + r, y + r, r, null, (Color) paint, (BasicStroke) stroke, clipID, hints);
}
public void clearRect(int x, int y, int width, int height) {
boolean wasStarted = started;
if (!wasStarted) {
start();
} else {
// don't do it twice at the start
String id = (String) hints.remove(KEY_ELEMENT_ID);
String cl = (String) hints.remove(KEY_ELEMENT_CLASS);
svg.drawRect(x, y, width, height, null, bgcolor, null, clipID, hints);
}
}
public void draw(Shape s) {
drawOrFill(s, true, false);
}
public void fill(Shape s) {
drawOrFill(s, false, true);
}
/**
* Lines only for now
* Will draw a closed shape, open shapes will become closed.
* Arcs will throw UnsupportedOperationException
*/
private void drawOrFill(Shape s, boolean draw, boolean fill) {
int[] x = new int[16];
int[] y = new int[16];
int i = 0;
float[] coords = new float[6];
for (PathIterator it = s.getPathIterator(frctx.getTransform()); !it.isDone(); it.next()) {
int type = it.currentSegment(coords);
switch(type) {
case SEG_MOVETO:
case SEG_LINETO:
if (i >= x.length) {
x = Arrays.copyOf(x, x.length * 2);
y = Arrays.copyOf(y, y.length * 2);
}
x[i] = (int) coords[0];
y[i++] = (int) coords[1];
break;
case SEG_CLOSE:
break;
case SEG_CUBICTO:
case SEG_QUADTO:
throw new UnsupportedOperationException("Unsupported curved shape");
default:
throw new UnsupportedOperationException("Unsupported type " + type);
}
}
if (draw)
drawPolyline(x, y, i);
else
fillPolygon(x, y, i);
}
//// clips ////
public void setClip(int x, int y, int width, int height) {
setClip(new Rectangle(x, y, width, height));
}
public void setClip(Shape clip) {
if (clip.equals(this.clip))
return;
if (this.clip == null && clip.equals(origclip))
return;
Rectangle newclip;
if (clip instanceof Rectangle)
newclip = (Rectangle) clip;
else
newclip = clip.getBounds();
if (clip.equals(origclip)) {
this.clip = null;
clipID = null;
return;
}
// define new clip, save the Rectangle and ID
clipID = svg.defineClipPath(newclip);
this.clip = newclip;
}
//// transforms ////
public void translate(int x, int y) { translate((double) x, (double) y); }
public void translate(double tx, double ty) {
AffineTransform ntx = (AffineTransform) transform.clone();
ntx.translate(tx, ty);
setTransform(ntx);
}
public void rotate(double theta) {
AffineTransform ntx = (AffineTransform) transform.clone();
ntx.rotate(theta);
setTransform(ntx);
}
public void rotate(double theta, double x, double y) {
AffineTransform ntx = (AffineTransform) transform.clone();
ntx.rotate(theta, x, y);
setTransform(ntx);
}
public void scale(double sx, double sy) {
AffineTransform ntx = (AffineTransform) transform.clone();
ntx.scale(sx, sy);
setTransform(ntx);
}
public void shear(double shx, double shy) {
AffineTransform ntx = (AffineTransform) transform.clone();
ntx.shear(shx, shy);
setTransform(ntx);
}
public void setTransform(AffineTransform tx) {
// For each transform, we close the previous group if non-identity,
// and start a new group with a transform containing the new combined transform.
// We don't 'stack' groups with each individual transform.
if (transform.equals(tx))
return;
if (!transform.isIdentity())
svg.endGroup();
if (!tx.isIdentity()) {
String matrix = String.format(Locale.US, "matrix(%.3f %.3f %.3f %.3f %.3f %.3f)",
tx.getScaleX(), tx.getShearY(),
tx.getShearX(), tx.getScaleY(),
tx.getTranslateX(), tx.getTranslateY());
svg.startGroup(null, null, "transform", matrix);
}
transform = tx;
}
public AffineTransform getTransform() { return transform; }
//// setters ////
public void setFont(Font font) { this.font = font; }
public void setPaint(Paint paint) { this.paint = paint; }
public void setStroke(Stroke stroke) { this.stroke = stroke; }
//// we support these but unused by rrd4j ////
public void setBackground(Color color) { bgcolor = color; }
public Color getBackground() { return bgcolor; }
public Shape getClip() { return clip; }
public Rectangle getClipBounds() { return clip; }
public void setColor(Color color) { paint = color; }
public Color getColor() { return (Color) paint; }
public Font getFont() { return font; }
public Paint getPaint() { return paint; }
public Stroke getStroke() { return stroke; }
//// Hints ////
private static class RHKey extends RenderingHints.Key {
public RHKey(int k) {
super(k);
}
public boolean isCompatibleValue(Object o) {
if (intKey() == 6)
return o instanceof Map;
return o instanceof String;
}
}
public void addRenderingHints(Map<?,?> hints) { this.hints.putAll(hints); }
public Object getRenderingHint(RenderingHints.Key hintKey) { return hints.get(hintKey); }
public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) { hints.put(hintKey, hintValue); }
public void setRenderingHints(Map<?,?> hints) { this.hints.clear(); addRenderingHints(hints); }
//// unsupported things ////
//// all do nothing or throw ////
public void clipRect(int x, int y, int width, int height) { throw new UnsupportedOperationException(); }
public void clip(Shape s) { throw new UnsupportedOperationException(); }
public void copyArea(int x, int y, int width, int height, int dx, int dy) { throw new UnsupportedOperationException(); }
public Graphics create() { throw new UnsupportedOperationException(); }
public void drawGlyphVector(GlyphVector g, float x, float y) { throw new UnsupportedOperationException(); }
public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { throw new UnsupportedOperationException(); }
public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { throw new UnsupportedOperationException(); }
public boolean drawImage(Image img, int x, int y, ImageObserver obs) { throw new UnsupportedOperationException(); }
public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver obs) { throw new UnsupportedOperationException(); }
public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver obs) { throw new UnsupportedOperationException(); }
public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver obs) { throw new UnsupportedOperationException(); }
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver obs) { throw new UnsupportedOperationException(); }
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver obs) { throw new UnsupportedOperationException(); }
public void drawOval(int x, int y, int width, int height) { throw new UnsupportedOperationException(); }
public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { throw new UnsupportedOperationException(); }
public void drawRenderableImage(RenderableImage img, AffineTransform xform) { throw new UnsupportedOperationException(); }
public void drawRenderedImage(RenderedImage img, AffineTransform xform) { throw new UnsupportedOperationException(); }
public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { throw new UnsupportedOperationException(); }
public void drawString(AttributedCharacterIterator iterator, float x, float y) { throw new UnsupportedOperationException(); }
public void drawString(AttributedCharacterIterator iterator, int x, int y) { throw new UnsupportedOperationException(); }
public void fillOval(int x, int y, int width, int height) { throw new UnsupportedOperationException(); }
public void fillPolyline(int[] xPoints, int[] yPoints, int nPoints) { throw new UnsupportedOperationException(); }
public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { throw new UnsupportedOperationException(); }
public Composite getComposite() { return null; }
public GraphicsConfiguration getDeviceConfiguration() { return null; }
public FontMetrics getFontMetrics(Font f) { return null; }
public RenderingHints getRenderingHints() { return null; }
public boolean hit(Rectangle rect, Shape s, boolean onStroke) { return false; }
public void setComposite(Composite comp) { throw new UnsupportedOperationException(); }
public void setPaintMode() {}
public void setXORMode(Color color) { throw new UnsupportedOperationException(); }
public void transform(AffineTransform tx) {}
}
@@ -0,0 +1,75 @@
package net.i2p.rrd4j;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.io.OutputStream;
import org.rrd4j.graph.ImageWorker;
/**
* rrd4j adapter for SimpleSVGGraphics2D
*
* Requires: rrd4j 3.10 or higher
* Ref: https://github.com/rrd4j/rrd4j/issues/165
*
* Usage:
* No ImageIO/BufferedImage/ImageWriter required!
*
*<pre>
* RRDGraph graph = new RrdGraph(graphdef, new SimpleSVGImageWorker(width, height));
* outputstream.write(graph.getRrdGraphInfo().getBytes());
*</pre>
*
* License: Apache 2.0 (same as rrd4j)
*
* @since 0.9.64
* @author zzz
*/
public class SimpleSVGImageWorker extends ImageWorker {
private SimpleSVGGraphics2D g2d;
private AffineTransform initialAffineTransform;
private int imgWidth;
private int imgHeight;
public SimpleSVGImageWorker(int width, int height) {
resize(width, height);
}
protected void resize(int width, int height) {
imgWidth = width;
imgHeight = height;
g2d = new SimpleSVGGraphics2D(imgWidth, imgHeight);
initialAffineTransform = g2d.getTransform();
setG2d(g2d);
}
protected void reset(Graphics2D g2d) {
g2d.setTransform(initialAffineTransform);
g2d.setClip(0, 0, imgWidth, imgHeight);
}
protected void makeImage(OutputStream os) throws IOException {
os.write(g2d.getSVG().getBytes("UTF-8"));
}
/**
* Overridden because the SVG format essentially strips leading/trailing spaces,
* causing alignment issues in ValueAxis with the %x.y number formatting.
* Consecutive spaces within text are also probably collapsed, that is not addressed here.
*/
@Override
protected void drawString(String text, int x, int y, Font font, Paint paint) {
super.drawString(text.trim(), x, y, font, paint);
}
/**
* Overridden because the SVG format essentially strips leading/trailing spaces,
* causing alignment issues in ValueAxis with the %x.y number formatting.
* Consecutive spaces within text are also probably collapsed, that is not addressed here.
*/
@Override
protected double getStringWidth(String text, Font font) {
return super.getStringWidth(text.trim(), font);
}
}
@@ -0,0 +1,439 @@
package net.i2p.rrd4j;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Rectangle;
import net.i2p.data.DataHelper;
import static net.i2p.rrd4j.SimpleSVGGraphics2D.*;
/**
* Create full or partial SVG images, without dependencies.
* Does not extend or use Graphics2D or ImageWriter.
*
* Each drawn element can be passed an optional CSS ID and/or classes,
* for easy styling and manipulation via CSS or js.
* All parameters are set as attributes, not as inline style,
* so a separate CSS style may easily override them.
* If inline style is desired, add it with the KEY_ELEMENT_ATTMAP hint.
*
* Unlike in Graphics2D, the border and fill for an object may be drawn in
* the same call, with separate colors.
*
* There is no state here other than the StringBuffer;
* there is no concept of current Color or Stroke or Font;
* caller must keep track of current Colors, Stroke, and Font, and pass them in
* on every draw() call, and/or overridden via CSS.
*
* License: Apache 2.0 (same as rrd4j)
*
* @since 0.9.64
* @author zzz
*/
public class SimpleSVGMaker {
private final StringBuilder buf;
private int clipid;
public SimpleSVGMaker(StringBuilder buf) {
this.buf = buf;
}
/**
* Start svg tag
* @param bgcolor null for none
* @param id CSS id or null for none
* @param clz CSS class or null for none
*/
public void startSVG(int width, int height, Color bgcolor, String id, String clz) {
buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
// "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n" +
"<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" ");
addIDClass(id, clz);
addString("viewBox", "0 0 " + width + ' ' + height);
addInt("width", width);
addInt("height", height);
buf.append(">\n");
if (bgcolor != null && bgcolor.getAlpha() > 0)
drawRect(0, 0, width, height, null, bgcolor, null, null, Collections.emptyMap());
}
/**
* End svg tag
*/
public void endSVG() {
buf.append("</svg>\n");
}
/**
* Start group
* @param id CSS id or null for none
* @param clz CSS class or null for none
* @param att an attribute to add att=val, e.g. "transform", or null for none
* @param val an attribute to add att=val, or null for none
*/
public void startGroup(String id, String clz, String att, String val) {
buf.append("<g ");
addIDClass(id, clz);
if (att != null && val != null)
addString(att, val);
buf.append(">\n");
}
/**
* End group
*/
public void endGroup() {
buf.append("</g>\n");
}
/**
* Define clip path
* @return a unique ID to pass to draw() calls
*/
public String defineClipPath(Rectangle clip) {
buf.append("<clipPath ");
String rv = "clip-" + hashCode() + '-' + (clipid++);
addIDClass(rv, null);
buf.append("><rect ");
addInt("x", (int) clip.getX());
addInt("y", (int) clip.getY());
addInt("width", (int) clip.getWidth());
addInt("height", (int) clip.getHeight());
buf.append("/></clipPath>\n");
return rv;
}
/**
* Draw circle centered on x,y with a radius given
* @param border null for none
* @param fill null for none
* @param clipid as returned from defineClipID() or null for none
* @param hints non-null
*/
public void drawCircle(int x, int y, int radius, Color border, Color fill, BasicStroke stroke, String clipid, Map<Object, Object> hints) {
buf.append("<circle ");
addAttributes(hints);
addClipPath(clipid);
addInt("cx", x);
addInt("cy", y);
addInt("r", radius);
addStroke("fill", fill, null);
addStroke("stroke", border, stroke);
String title = (String) hints.remove(KEY_ELEMENT_TITLE);
String inner = (String) hints.remove(KEY_ELEMENT_INNERSVG);
if (title != null || inner != null) {
buf.append(">\n");
addInner(title, inner);
buf.append("</circle>\n");
} else {
buf.append("/>\n");
}
}
/**
* Draw square centered on x,y with a width/height given
* @param border null for none
* @param fill null for none
* @param clipid as returned from defineClipID() or null for none
* @param hints non-null
*/
public void drawSquare(int x, int y, int sz, Color border, Color fill, BasicStroke stroke, String clipid, Map<Object, Object> hints) {
drawRect(x - (sz/2), y - (sz/2), sz, sz, border, fill, stroke, clipid, hints);
}
/**
* Draw rect
* @param border null for none
* @param fill null for none
* @param hints non-null
*/
public void drawRect(int x, int y, int width, int height, Color border, Color fill, BasicStroke stroke, String clipid, Map<Object, Object> hints) {
buf.append("<rect ");
addAttributes(hints);
addClipPath(clipid);
addInt("x", x);
addInt("y", y);
addInt("width", width);
addInt("height", height);
addStroke("fill", fill, null);
addStroke("stroke", border, stroke);
buf.append("shape-rendering=\"crispEdges\" ");
String title = (String) hints.remove(KEY_ELEMENT_TITLE);
String inner = (String) hints.remove(KEY_ELEMENT_INNERSVG);
if (title != null || inner != null) {
buf.append(">\n");
addInner(title, inner);
buf.append("</rect>\n");
} else {
buf.append("/>\n");
}
}
/**
* Draw line
* @param color null to let CSS do it
* @param clipid as returned from defineClipID() or null for none
* @param hints non-null
*/
public void drawLine(int x1, int y1, int x2, int y2, Color color, BasicStroke stroke, String clipid, Map<Object, Object> hints) {
buf.append("<line ");
addAttributes(hints);
addClipPath(clipid);
addInt("x1", x1);
addInt("y1", y1);
addInt("x2", x2);
addInt("y2", y2);
addStroke("stroke", color, stroke);
// don't do this for diagonal lines, it kills antialiasing
if (x1 == x2 || y1 == y2)
buf.append("shape-rendering=\"crispEdges\" ");
String title = (String) hints.remove(KEY_ELEMENT_TITLE);
String inner = (String) hints.remove(KEY_ELEMENT_INNERSVG);
if (title != null || inner != null) {
buf.append(">\n");
addInner(title, inner);
buf.append("</line>\n");
} else {
buf.append("/>\n");
}
}
/**
* Draw polyline
* @param color null to let CSS do it
* @param clipid as returned from defineClipID() or null for none
* @param hints non-null
*/
public void drawPolyline(int[] x, int[] y, int sz, Color color, BasicStroke stroke, String clipid, Map<Object, Object> hints) {
if (sz < 2)
return;
buf.append("<path ");
addAttributes(hints);
addClipPath(clipid);
buf.append("d=\"M");
buf.append(x[0]).append(',').append(y[0]);
for (int i = 1; i < sz; i++) {
// use relative coords to save a little space
buf.append('l');
buf.append(x[i] - x[i-1]).append(',').append(y[i] - y[i-1]);
}
buf.append("\" ");
addStroke("stroke", color, stroke);
buf.append("fill=\"none\" ");
// this is good for the horizontal/vertical paths drawn by rrd4j,
// but not so great for diagonal path segments
// Take our cue from the first segment
if (x[0] == x[1] || y[0] == y[1])
buf.append("shape-rendering=\"crispEdges\" ");
String title = (String) hints.remove(KEY_ELEMENT_TITLE);
String inner = (String) hints.remove(KEY_ELEMENT_INNERSVG);
if (title != null || inner != null) {
buf.append(">\n");
addInner(title, inner);
buf.append("</path>\n");
} else {
buf.append("/>\n");
}
}
/**
* Fill polygon
* @param color null to let CSS do it
* @param clipid as returned from defineClipID() or null for none
* @param hints non-null
*/
public void fillPolygon(int[] x, int[] y, int sz, Color color, String clipid, Map<Object, Object> hints) {
if (sz < 2)
return;
buf.append("<path ");
addAttributes(hints);
addClipPath(clipid);
buf.append("d=\"M");
buf.append(x[0]).append(',').append(y[0]);
for (int i = 1; i < sz; i++) {
// use relative coords to save a little space
buf.append('l');
buf.append(x[i] - x[i-1]).append(',').append(y[i] - y[i-1]);
}
buf.append("Z\" ");
addStroke("fill", color, null);
buf.append("stroke=\"none\" ");
// see above
if (x[0] == x[1] || y[0] == y[1])
buf.append("shape-rendering=\"crispEdges\" ");
String title = (String) hints.remove(KEY_ELEMENT_TITLE);
String inner = (String) hints.remove(KEY_ELEMENT_INNERSVG);
if (title != null || inner != null) {
buf.append(">\n");
addInner(title, inner);
buf.append("</path>\n");
} else {
buf.append("/>\n");
}
}
/**
* Draw text
* @param color null to let CSS do it
* @param font null to let CSS do it
* @param clipid as returned from defineClipID() or null for none
* @param hints non-null
*/
public void drawText(String text, int x, int y, Color color, Font font, String clipid, Map<Object, Object> hints) {
buf.append("<text ");
addAttributes(hints);
addClipPath(clipid);
addInt("x", x);
addInt("y", y);
addStroke("fill", color, null);
if (font != null) {
addString("font-family", font.getFamily());
buf.append("font-size=\"").append(font.getSize()).append("px\" ");
if (font.isBold())
buf.append("font-weight=\"bold\" ");
if (font.isItalic())
buf.append("font-style=\"italic\" ");
}
buf.append("text-rendering=\"optimizeLegibility\">").append(DataHelper.escapeHTML(text));
String title = (String) hints.remove(KEY_ELEMENT_TITLE);
if (title != null)
addInner(title, null);
buf.append("</text>\n");
}
private void addInt(String key, int val) {
buf.append(key).append("=\"").append(val).append("\" ");
}
private void addString(String key, String val) {
buf.append(key).append("=\"").append(DataHelper.escapeHTML(val)).append("\" ");
}
/**
* @param id CSS id or null for none
* @param clz CSS class or null for none
*/
private void addIDClass(String id, String clz) {
if (id != null)
addString("id", id);
if (clz != null)
addString("class", clz);
}
private void addAttributes(Map<Object, Object> hints) {
String id = (String) hints.remove(KEY_ELEMENT_ID);
if (id != null)
addString("id", id);
String clz = (String) hints.remove(KEY_ELEMENT_CLASS);
if (clz != null)
addString("class", clz);
Map<?,?> atts = (Map) hints.remove(KEY_ELEMENT_ATTMAP);
if (atts != null) {
for (Map.Entry e : atts.entrySet()) {
addString((String) e.getKey(), (String) e.getValue());
}
}
}
/**
* @param type "fill" or "stroke"
* @param color null to let CSS do it
* @param stroke null to omit for fill
*/
private void addStroke(String type, Color color, BasicStroke stroke) {
buf.append(type);
if (color != null) {
// Output RGB or RGBA. getRGB() is ARGB.
buf.append("=\"#").append(String.format(Locale.US, "%06x", color.getRGB() & 0xffffff));
int alpha = color.getAlpha();
if (alpha < 255)
buf.append(String.format(Locale.US, "%02x", alpha));
buf.append("\" ");
} else {
// default is black opaque, so fixup for none
buf.append("=\"none\" ");
}
if (stroke != null) {
int width = (int) stroke.getLineWidth();
if (width > 0) {
if (width != 1)
buf.append(type).append("-width=\"").append(width).append("\" ");
float[] dash = stroke.getDashArray();
if (dash != null && dash.length > 1) {
buf.append("stroke-dasharray=\"");
for (int i = 0; i < dash.length; i++) {
buf.append((int) dash[i]);
if (i != dash.length - 1)
buf.append(' ');
}
buf.append("\" ");
}
}
}
}
/**
* @param clipid as received from defineClipPath() or null for none
*/
private void addClipPath(String clipid) {
if (clipid != null)
buf.append("clip-path='url(#").append(clipid).append(")' ");
}
/**
* @param title, will be XML escaped here, or null
* @param other full elements, must be XML escaped, or null
*/
private void addInner(String title, String inner) {
if (title != null)
buf.append(" <title>").append(DataHelper.escapeHTML(title)).append("</title>\n");
if (inner != null)
buf.append(" ").append(inner).append("\n");
}
/*
public void main(String[] args) {
StringBuilder buf = new StringBuilder(2048);
SimpleSVGMaker g = new SimpleSVGMaker(buf);
Font f = new Font("Dialog", Font.BOLD, 24);
Color c = new Color(255, 128, 128);
g.startSVG(190, 200, c, "id", "class");
g.startGroup("gid", "class", "transform", "matrix");
c = new Color(255, 0, 0);
BasicStroke s = new BasicStroke(4);
Map<Object,Object> hints = new java.util.HashMap<Object,Object>();
g.drawSquare(100, 36, 17, null, c, s, null, hints);
c = new Color(33, 33, 33, 128);
s = new BasicStroke(8);
g.drawCircle(75, 56, 27, c, null, s, null, hints);
g.drawCircle(100, 100, 110, c, null, s, null, hints);
c = new Color(0, 255, 0);
s = new BasicStroke(2);
g.drawLine(55, 96, 97, 178, c, s, null, hints);
int[] xx = { 10, 20, 30, 40, 150 };
int[] yy = { 81, 92, 113, 184, 29 };
c = new Color(0, 0, 255);
s = new BasicStroke(2);
g.drawPolyline(xx, yy, 5, c, s, null, hints);
Color cc = new Color(128, 128, 0, 128);
Color ccc = new Color(128, 0, 192, 128);
g.drawRect(100, 80, 40, 20, cc, ccc, s, null, hints);
c = new Color(0, 128, 128);
g.drawText("foo", 135, 156, c, f, null, hints);
c = new Color(128, 128, 0);
f = new Font(Font.SANS_SERIF, Font.ITALIC, 20);
g.drawText("bar", 115, 136, c, f, null, hints);
f = new Font(Font.SANS_SERIF, Font.PLAIN, 16);
g.drawText("baz", 115, 176, c, f, null, hints);
g.endGroup();
g.endSVG();
System.out.print(buf.toString());
}
*/
}
@@ -0,0 +1,7 @@
<html>
<body>
<p>
SVG renderer and adapter for rrd4j. Since 0.9.64.
</p>
</body>
</html>
@@ -1,179 +0,0 @@
package org.rrd4j.data;
import org.rrd4j.core.Util;
import java.util.Calendar;
import java.util.Date;
/**
* Class used to interpolate datasource values from the collection of (timestamp, values)
* points using natural cubic spline interpolation.
* <p>
*
* <b>WARNING</b>: So far, this class cannot handle NaN datasource values
* (an exception will be thrown by the constructor). Future releases might change this.
*/
@SuppressWarnings("deprecation")
public class CubicSplineInterpolator extends Plottable {
private final double[] x;
private final double[] y;
// second derivates come here
private double[] y2;
// internal spline variables
private int n, klo, khi;
/**
* Creates cubic spline interpolator from arrays of timestamps and corresponding
* datasource values.
*
* @param timestamps timestamps in seconds
* @param values corresponding datasource values
* @throws java.lang.IllegalArgumentException Thrown if supplied arrays do not contain at least 3 values, or if
* timestamps are not ordered, or array lengths are not equal, or some datasource value is NaN.
*/
public CubicSplineInterpolator(long[] timestamps, double[] values) {
this.x = new double[timestamps.length];
for (int i = 0; i < timestamps.length; i++) {
this.x[i] = timestamps[i];
}
this.y = values;
validate();
spline();
}
/**
* Creates cubic spline interpolator from arrays of Date objects and corresponding
* datasource values.
*
* @param dates Array of Date objects
* @param values corresponding datasource values
* @throws java.lang.IllegalArgumentException Thrown if supplied arrays do not contain at least 3 values, or if
* timestamps are not ordered, or array lengths are not equal, or some datasource value is NaN.
*/
public CubicSplineInterpolator(Date[] dates, double[] values) {
this.x = new double[dates.length];
for (int i = 0; i < dates.length; i++) {
this.x[i] = Util.getTimestamp(dates[i]);
}
this.y = values;
validate();
spline();
}
/**
* Creates cubic spline interpolator from arrays of GregorianCalendar objects and corresponding
* datasource values.
*
* @param dates Array of GregorianCalendar objects
* @param values corresponding datasource values
* @throws java.lang.IllegalArgumentException Thrown if supplied arrays do not contain at least 3 values, or if
* timestamps are not ordered, or array lengths are not equal, or some datasource value is NaN.
*/
public CubicSplineInterpolator(Calendar[] dates, double[] values) {
this.x = new double[dates.length];
for (int i = 0; i < dates.length; i++) {
this.x[i] = Util.getTimestamp(dates[i]);
}
this.y = values;
validate();
spline();
}
/**
* Creates cubic spline interpolator for an array of 2D-points.
*
* @param x x-axis point coordinates
* @param y y-axis point coordinates
* @throws java.lang.IllegalArgumentException Thrown if supplied arrays do not contain at least 3 values, or if
* timestamps are not ordered, or array lengths are not equal, or some datasource value is NaN.
*/
public CubicSplineInterpolator(double[] x, double[] y) {
this.x = x;
this.y = y;
validate();
spline();
}
private void validate() {
boolean ok = true;
if (x.length != y.length || x.length < 3) {
ok = false;
}
for (int i = 0; i < x.length - 1 && ok; i++) {
if (x[i] >= x[i + 1] || Double.isNaN(y[i])) {
ok = false;
break;
}
}
if (!ok) {
throw new IllegalArgumentException("Invalid plottable data supplied");
}
}
private void spline() {
n = x.length;
y2 = new double[n];
double[] u = new double[n - 1];
y2[0] = y2[n - 1] = 0.0;
u[0] = 0.0; // natural spline
for (int i = 1; i <= n - 2; i++) {
double sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]);
double p = sig * y2[i - 1] + 2.0;
y2[i] = (sig - 1.0) / p;
u[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1]);
u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p;
}
for (int k = n - 2; k >= 0; k--) {
y2[k] = y2[k] * y2[k + 1] + u[k];
}
// prepare everything for getValue()
klo = 0;
khi = n - 1;
}
/**
* Calculates spline-interpolated y-value for the corresponding x-value. Call
* this if you need spline-interpolated values in your code.
*
* @param xval x-value
* @return inteprolated y-value
*/
public double getValue(double xval) {
if (xval < x[0] || xval > x[n - 1]) {
return Double.NaN;
}
if (xval < x[klo] || xval > x[khi]) {
// out of bounds
klo = 0;
khi = n - 1;
}
while (khi - klo > 1) {
// find bounding interval using bisection method
int k = (khi + klo) / 2;
if (x[k] > xval) {
khi = k;
}
else {
klo = k;
}
}
double h = x[khi] - x[klo];
double a = (x[khi] - xval) / h;
double b = (xval - x[klo]) / h;
return a * y[klo] + b * y[khi] +
((a * a * a - a) * y2[klo] + (b * b * b - b) * y2[khi]) * (h * h) / 6.0;
}
/**
* {@inheritDoc}
*
* Method overridden from the base class. This method will be called by the framework. Call
* this method only if you need spline-interpolated values in your code.
*/
public double getValue(long timestamp) {
return getValue((double)timestamp);
}
}
@@ -147,8 +147,7 @@ public class RrdGraph implements RrdGraphConstants {
drawAxis();
drawText();
drawLegend();
drawRules();
drawSpans();
drawRulesAndSpans();
gator();
drawOverlay();
saveImage();
@@ -219,13 +218,17 @@ public class RrdGraph implements RrdGraphConstants {
}
}
private void drawRules() {
worker.clip(im.xorigin + 1, im.yorigin - gdef.height - 1, gdef.width - 1, gdef.height + 2);
private void drawRulesAndSpans() {
boolean found = false;
for (PlotElement pe : gdef.plotElements) {
if (pe instanceof HRule) {
HRule hr = (HRule) pe;
if (hr.value >= im.minval && hr.value <= im.maxval) {
int y = mapper.ytr(hr.value);
if (!found) {
worker.clip(im.xorigin + 1, im.yorigin - gdef.height - 1, gdef.width - 1, gdef.height + 2);
found = true;
}
worker.drawLine(im.xorigin, y, im.xorigin + im.xsize, y, hr.color, hr.stroke);
}
}
@@ -233,31 +236,37 @@ public class RrdGraph implements RrdGraphConstants {
VRule vr = (VRule) pe;
if (vr.timestamp >= im.start && vr.timestamp <= im.end) {
int x = mapper.xtr(vr.timestamp);
if (!found) {
worker.clip(im.xorigin + 1, im.yorigin - gdef.height - 1, gdef.width - 1, gdef.height + 2);
found = true;
}
worker.drawLine(x, im.yorigin, x, im.yorigin - im.ysize, vr.color, vr.stroke);
}
}
}
worker.reset();
}
private void drawSpans() {
worker.clip(im.xorigin + 1, im.yorigin - gdef.height - 1, gdef.width - 1, gdef.height + 2);
for (PlotElement pe : gdef.plotElements) {
if (pe instanceof HSpan) {
else if (pe instanceof HSpan) {
HSpan hr = (HSpan) pe;
int ys = mapper.ytr(hr.start);
int ye = mapper.ytr(hr.end);
int height = ys - ye;
if (!found) {
worker.clip(im.xorigin + 1, im.yorigin - gdef.height - 1, gdef.width - 1, gdef.height + 2);
found = true;
}
worker.fillRect(im.xorigin, ys - height, im.xsize, height, hr.color);
}
else if (pe instanceof VSpan) {
VSpan vr = (VSpan) pe;
int xs = mapper.xtr(vr.start);
int xe = mapper.xtr(vr.end);
if (!found) {
worker.clip(im.xorigin + 1, im.yorigin - gdef.height - 1, gdef.width - 1, gdef.height + 2);
found = true;
}
worker.fillRect(xs, im.yorigin - im.ysize, xe - xs, im.ysize, vr.color);
}
}
worker.reset();
if (found)
worker.reset();
}
private void drawText() {
@@ -726,9 +735,15 @@ public class RrdGraph implements RrdGraphConstants {
if (c instanceof LegendText) {
// draw with BOX
worker.fillRect(x, y - box, box, box, gdef.getColor(ElementsNames.frame));
worker.fillRect(x + 1, y - box + 1, box - 2, box - 2, gdef.getColor(ElementsNames.canvas));
worker.fillRect(x + 1, y - box + 1, box - 2, box - 2, gdef.getColor(ElementsNames.back));
worker.fillRect(x + 1, y - box + 1, box - 2, box - 2, ((LegendText) c).legendColor);
Color bc = (Color) gdef.getColor(ElementsNames.back);
Color lc = (Color) ((LegendText) c).legendColor;
// no use drawing unless both the two on top have some transparency
if (bc.getAlpha() < 255 && lc.getAlpha() < 255)
worker.fillRect(x + 1, y - box + 1, box - 2, box - 2, gdef.getColor(ElementsNames.canvas));
// no use drawing unless the one on top has some transparency
if (lc.getAlpha() < 255)
worker.fillRect(x + 1, y - box + 1, box - 2, box - 2, bc);
worker.fillRect(x + 1, y - box + 1, box - 2, box - 2, lc);
worker.drawString(c.resolvedText, x + boxSpace, y, gdef.getFont(FONTTAG_LEGEND), gdef.getColor(ElementsNames.font));
}
else {
@@ -42,14 +42,12 @@ public class HostCheckHandler extends GzipHandler
_context = ctx;
_portMapper = ctx.portMapper();
_listenHosts = new HashSet<String>(8);
setMinGzipSize(64*1024);
setMinGzipSize(32*1024);
if (_context.getBooleanPropertyDefaultTrue(PROP_GZIP)) {
addIncludedMimeTypes(
// our js is very small
//"application/javascript", "application/x-javascript",
"application/javascript", "application/x-javascript",
"application/xhtml+xml", "application/xml",
// ditto svg
//"image/svg+xml",
"image/svg+xml",
"text/css", "text/html", "text/plain"
);
} else {
@@ -45,7 +45,7 @@ public class StatSummarizer implements Runnable, ClientApp {
private final Log _log;
/** list of SummaryListener instances */
private final List<SummaryListener> _listeners;
private static final int MAX_CONCURRENT_PNG = SystemVersion.isSlow() ? 1 : 3;
private static final int MAX_CONCURRENT_PNG = SystemVersion.isSlow() ? 3 : 8;
private final Semaphore _sem;
private volatile boolean _isRunning;
private volatile Thread _thread;
@@ -19,6 +19,7 @@ import javax.imageio.stream.MemoryCacheImageOutputStream;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.rrd4j.SimpleSVGImageWorker;
import net.i2p.router.RouterContext;
import net.i2p.router.util.EventLog;
import static net.i2p.router.web.GraphConstants.*;
@@ -374,7 +375,8 @@ class SummaryRenderer {
RrdGraph graph;
try {
// NPE here if system is missing fonts - see ticket #915
graph = new RrdGraph(def);
SimpleSVGImageWorker svg = new SimpleSVGImageWorker(width, height);
graph = new RrdGraph(def, svg);
} catch (NullPointerException npe) {
_log.error("Error rendering graph", npe);
StatSummarizer.setDisabled(_context);
@@ -385,13 +387,8 @@ class SummaryRenderer {
StatSummarizer.setDisabled(_context);
throw new IOException("Error rendering - disabling graph generation. Missing font?");
}
int totalWidth = graph.getRrdGraphInfo().getWidth();
int totalHeight = graph.getRrdGraphInfo().getHeight();
BufferedImage img = new BufferedImage(totalWidth, totalHeight, BufferedImage.TYPE_USHORT_565_RGB);
Graphics gfx = img.getGraphics();
graph.render(gfx);
ios = new MemoryCacheImageOutputStream(out);
ImageIO.write(img, "png", ios);
out.write(graph.getRrdGraphInfo().getBytes());
out.flush();
_context.statManager().addRateData("graph.renderTime", System.currentTimeMillis() - begin);
} catch (RrdException re) {
+1 -1
View File
@@ -1,5 +1,4 @@
<%@page contentType="text/html"%>
<%@page trimDirectiveWhitespaces="true"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html><head>
@@ -55,6 +54,7 @@ input.default {
<div id="langsettings">
<jsp:getProperty name="uihelper" property="langSettings" />
<p id="helptranslate"><%=uihelper._t("Please contribute to the router console translation project! Contact the developers in #i2p-dev on IRC to help.")%>
<%=uihelper._t("See the {0}translation status report{1}.", "<a href=\"/debug?d=6\">", "</a>")%>
</p><hr><div class="formaction" id="langui">
<input type="reset" class="cancel" value="<%=intl._t("Cancel")%>" >
<input type="submit" name="foo" class="accept" value="<%=intl._t("Apply")%>" >
+22
View File
@@ -22,6 +22,7 @@
<span class="tab"><a href="/debug?d=3">Router Session Key Manager</a></span>
<span class="tab"><a href="/debug?d=4">Client Session Key Managers</a></span>
<span class="tab"><a href="/debug?d=5">Router DHT</a></span>
<span class="tab"><a href="/debug?d=6">Translation Status</a></span>
</div>
<%
@@ -116,6 +117,27 @@ if (dd == null || dd.equals("0")) {
out.print("<h2 id=\"dht\">Router DHT</h2>");
ctx.netDb().renderStatusHTML(out);
} else if (dd.equals("6")) {
/*
* Print out the status of the translations
*/
java.io.InputStream is = this.getClass().getResourceAsStream("/net/i2p/router/web/resources/translationstatus.html");
if (is == null) {
out.println("Translation status not available");
} else {
java.io.Reader br = null;
try {
br = new java.io.InputStreamReader(is, "UTF-8");
char[] buf = new char[4096];
int read;
while ( (read = br.read(buf)) >= 0) {
out.write(buf, 0, read);
}
} finally {
if (br != null) try { br.close(); } catch (java.io.IOException ioe) {}
}
}
}
%>
@@ -7547,6 +7547,25 @@ b.netdb_transport {
font-weight: bold;
}
.debug_tx_total, .debug_tx_resource, .debug_tx_file {
width: auto;
}
.debug_tx_total td:nth-child(3),
.debug_tx_total td:nth-child(4),
.debug_tx_resource td:nth-child(3),
.debug_tx_resource td:nth-child(4) {
text-align: right !important;
}
.debug_tx_center,
.debug_tx_total td:nth-child(2),
.debug_tx_resource td:nth-child(2),
.debug_tx_file td:nth-child(2),
.debug_tx_file td:nth-child(3) {
text-align: center !important;
}
#portmapper td:first-child {
font-weight: bold;
}
@@ -7647,6 +7647,25 @@ b.netdb_transport {
color: #050;
}
.debug_tx_total, .debug_tx_resource, .debug_tx_file {
width: auto;
}
.debug_tx_total td:nth-child(3),
.debug_tx_total td:nth-child(4),
.debug_tx_resource td:nth-child(3),
.debug_tx_resource td:nth-child(4) {
text-align: right;
}
.debug_tx_center,
.debug_tx_total td:nth-child(2),
.debug_tx_resource td:nth-child(2),
.debug_tx_file td:nth-child(2),
.debug_tx_file td:nth-child(3) {
text-align: center !important;
}
/* end debug */
+3 -2
View File
@@ -53,8 +53,9 @@ if ( !rendered && ((rs != null) || fakeBw) ) {
rendered = ss.getXML(rate, cout);
}
} else {
response.setContentType("image/png");
response.setHeader("Content-Disposition", "inline; filename=\"" + stat + ".png\"");
response.setContentType("image/svg+xml");
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Disposition", "inline; filename=\"" + stat + ".svg\"");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Accept-Ranges", "none");
// http://jira.codehaus.org/browse/JETTY-1346
+49 -8
View File
@@ -54,6 +54,7 @@
<echo message=" updater200WithJbigi" />
<echo message=" updaterSmall: updater with the essentials only - no SAM, i2psnark, SusiMail, SusiDNS, or history.txt" />
<echo message=" updaterRouter: updater with the i2p.jar and router.jar only" />
<echo message=" translationReport: generate a translation status report" />
<echo message=" distclean: clean up all derived files" />
<!-- <echo message=" syndie: generate a standalone syndie install" /> -->
<echo message=" desktopgui: generate a standalone desktopgui install" />
@@ -290,7 +291,7 @@
<ant dir="apps/i2psnark/java/" target="standalone" />
-->
</target>
<target name="build2" depends="builddep, jar, buildWEB" />
<target name="build2" depends="builddep, jar, buildWEB, bundleTranslationReport" />
<target name="buildSmall" depends="builddepSmall, jarSmall, buildWEB" />
<target name="buildclean" depends="distclean, build" />
@@ -315,23 +316,23 @@
<copy file="apps/sam/java/build/sam.jar" todir="build/" />
</target>
<target name="buildSusiMail" depends="buildCore, buildJetty" >
<target name="buildSusiMail" depends="buildJetty" >
<ant dir="apps/susimail/" target="war" />
<copy file="apps/susimail/susimail.war" todir="build/" />
</target>
<!-- jar (not war) for testing only -->
<target name="buildSusiMailJar" depends="buildCore, buildJetty" >
<target name="buildSusiMailJar" depends="buildJetty" >
<ant dir="apps/susimail/" target="jar" />
<copy file="apps/susimail/susimail.jar" todir="build/" />
</target>
<target name="buildSusiDNS" depends="buildCore, buildJetty, buildImagegen, buildAddressbook" >
<target name="buildSusiDNS" depends="buildImagegen, buildAddressbook" >
<ant dir="apps/susidns/src" target="all" />
<copy file="apps/susidns/src/susidns.war" todir="build/" />
</target>
<target name="buildImagegen" depends="buildCore, buildJetty" >
<target name="buildImagegen" depends="buildJetty" >
<ant dir="apps/imagegen" target="build" />
<copy file="apps/imagegen/imagegen/build/imagegen.war" todir="build/" />
</target>
@@ -368,7 +369,7 @@
<copy file="apps/i2ptunnel/java/build/i2ptunnel-ui.jar" todir="build/" />
</target>
<target name="buildI2PTunnel" depends="buildMinistreaming, buildJetty, buildImagegen" >
<target name="buildI2PTunnel" depends="buildMinistreaming, buildImagegen" >
<ant dir="apps/i2ptunnel/java/" target="build" />
<copy file="apps/i2ptunnel/java/build/i2ptunnel.jar" todir="build/" />
<copy file="apps/i2ptunnel/java/build/i2ptunnel.war" todir="build/" />
@@ -421,7 +422,7 @@
<copy file="core/java/build/i2p.jar" todir="build/" />
</target>
<target name="buildJrobin" depends="buildProperties" >
<target name="buildJrobin" depends="buildCore" >
<ant dir="apps/jrobin/java/" target="jar" />
<copy file="apps/jrobin/java/build/jrobin.jar" todir="build/" />
</target>
@@ -879,7 +880,7 @@
<group title="Imagegen Application" packages="com.docuverse.identicon:com.google.zxing:com.google.zxing.*:net.i2p.imagegen" />
<group title="Installer Utilities" packages="net.i2p.installer" />
<group title="Jetty Utilities" packages="net.i2p.jetty:net.i2p.servlet:net.i2p.servlet.*" />
<group title="RRD4J Library (jrobin.jar)" packages="org.rrd4j:org.rrd4j.*:com.tomgibara.crinch.hashing" />
<group title="RRD4J Library (jrobin.jar)" packages="org.rrd4j:org.rrd4j.*:com.tomgibara.crinch.hashing:net.i2p.rrd4j" />
<group title="SAM Bridge" packages="net.i2p.sam" />
<group title="SAM Demos" packages="net.i2p.sam.client" />
<group title="SusiDNS Application" packages="i2p.susi.dns:net.i2p.addressbook.servlet" />
@@ -936,6 +937,9 @@
<link offline="true" href="${jettydocs.url}" packagelistLoc="installer/resources/package-lists/jetty/" />
<link offline="true" href="${wrapperdocs.url}" packagelistLoc="installer/resources/package-lists/wrapper/" />
</javadoc>
<!-- create an empty dejavu.css file to keep the browser happy -->
<mkdir dir="./build/javadoc/resources/fonts" />
<echo message="/* intentionally empty */" file="build/javadoc/resources/fonts/dejavu.css" />
</target>
<target name="javadoc-zip" depends="javadoc">
@@ -1205,6 +1209,8 @@
<ant dir="installer/tools/java" target="distclean" />
<delete dir="installer/lib/izpack5/patches/java/build" quiet="true" />
<delete dir="reproducible/build" />
<!-- custom langpacks -->
<delete dir="com" />
<!--
NOTE! We need to turn off the default excludes for these
patterns to work.
@@ -1609,6 +1615,32 @@
<su3sign infile="i2pseeds.zip" sigtype="RESEED" outfile="i2pseeds.su3" su3.ver="${epoch}" />
</target>
<!-- text output -->
<target name="translationReport" depends="buildTools, builddep, jar, buildWEB" unless="no.bundle">
<java classname="net.i2p.util.TranslationStatus" fork="true" dir="build/" failonerror="true">
<classpath>
<pathelement location="build/i2p.jar" />
<pathelement location="build/tools.jar" />
</classpath>
</java>
</target>
<!-- stuff html output into routerconsole.war -->
<target name="bundleTranslationReport" depends="buildTools, builddep, jar, buildWEB" unless="no.bundle">
<mkdir dir="build/txstatus/WEB-INF/classes/net/i2p/router/web/resources/" />
<java classname="net.i2p.util.TranslationStatus" fork="true" dir="build/" failonerror="true" output="build/txstatus/WEB-INF/classes/net/i2p/router/web/resources/translationstatus.html" logError="true">
<classpath>
<pathelement location="build/i2p.jar" />
<pathelement location="build/tools.jar" />
</classpath>
<arg value="-h" />
</java>
<jar destfile="build/routerconsole.war" update="true" duplicate="preserve">
<fileset dir="build/txstatus" />
</jar>
<echo message="Translation status report bundled in routerconsole.war" />
</target>
<!-- this is no longer required, izpack 4.3.0 supports headless installs with java -jar i2pinstall.exe -console -->
<!-- and this is no longer used by the SlackBuild -->
<target name="tarball" depends="preppkg">
@@ -1897,6 +1929,15 @@
<target name="izpack5-patches" depends="ensureIzpack5, buildProperties" >
<ant dir="installer/lib/izpack5/patches/java/" target="jar" />
<!-- custom langpacks
Izpack tries to load the resource both from the classpath and the file system;
we do it this way because jaring them up and adding a pathelement to izpack5.lib.path doesn't work.
See installer/install5.xml for details.
-->
<mkdir dir="com/izforge/izpack/bin/langpacks/" />
<copy toDir="com/izforge/izpack/bin/langpacks/" >
<fileset dir="installer/lib/izpack5/patches/resources" />
</copy>
</target>
<target name="installer5" depends="izpack5-patches, preppkg, buildProperties, buildUtilityJar" >
@@ -3,7 +3,8 @@ package freenet.support.CPUInformation;
/**
* Moved out of CPUID.java
*
* Ref: http://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures
* Ref: https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures
* Ref: https://gmplib.org/repo/gmp/file/tip/config.guess
*
* @since 0.8.7
*/
@@ -468,7 +469,7 @@ class AMDInfoImpl extends CPUIDCPUInfo implements AMDCPUInfo
}
break;
// Zen / Zen+ / Zen2 / Zen3 / Ryzen 3/5/7/9/Threadripper / EPYC
// Zen / Zen+ / Zen2 / Zen3 / Zen4 / Ryzen 3/5/7/9/Threadripper / EPYC
// untested
case 23:
case 25: {
@@ -4,7 +4,8 @@ package freenet.support.CPUInformation;
* Moved out of CPUID.java
*
* Ref: https://software.intel.com/en-us/articles/intel-architecture-and-processor-identification-with-cpuid-model-and-family-numbers
* Ref: http://en.wikipedia.org/wiki/List_of_Intel_CPU_microarchitectures
* Ref: https://en.wikipedia.org/wiki/List_of_Intel_CPU_microarchitectures
* Ref: https://gmplib.org/repo/gmp/file/tip/config.guess
*
* @since 0.8.7
*/
@@ -521,6 +522,8 @@ class IntelInfoImpl extends CPUIDCPUInfo implements IntelCPUInfo
case 0xa7: // Rocket Lake
case 0x97: // Alder Lake
case 0x9a: // Alder Lake
case 0xba: // Raptor Lake
case 0xb7: // Raptor Lake
{
CPUIDCPUInfo c = new CPUIDCPUInfo();
if (c.hasAVX2() && c.hasBMI1() && c.hasBMI2() &&
+11
View File
@@ -1,3 +1,14 @@
2024-07-25 zzz
* Console:
- Add translation status report (Gitlab MR !207)
- Convert graphs to SVG (Gitlab MR !208)
- Enable compression of js and svg files
* i2ptunnel: Additional fixes for invalid entries in filter file (Gitlab #483)
* imagegen: Convert identicons to SVG
* Installer: Fix some izpack5 translated languages
* rrd4j: More optimizations for graph generation
* Util: Add new processors for CPUID
2024-07-19 2.6.0 (API 0.9.63) released
2024-07-19 idk
+65 -3
View File
@@ -34,19 +34,81 @@ https://izpack.atlassian.net/wiki/spaces/IZPACK/pages/491730/GUI+Preferences
<modifier key="langDisplayType" value="native" />
</guiprefs>
<!--
Locales:
This is poorly documented, like a lot of things in izpack, but these can
be 2 OR 3 character country OR language codes.
Whatever it is, there must be xx.xml and xx.gif files available at
build time or the build will error out.
At runtime, izpack loads all the JVM's locales and tries to find
the "best match" locale for the code. See izpack DefaultLocales.java.
It then uses Locale.getDisplayLanguage() on that best match to show the (translated) language name
when langDisplayType=native, which we set in guiprefs above.
At https://izpack.atlassian.net/wiki/spaces/IZPACK/pages/491613/Overriding+Built-in+Translations
it says:
"In IzPack, language packs are identified by a 3 character ISO country or language code.
Country codes are converted to lowercase.
Country codes are used in preference to language codes.
This is to handle the case where a language variation is spoken for which there is no ISO language code."
This is wrong in that 2-character country and language codes are also allowed.
It is also wrong in that, unfortunately,
country codes combined with "best match" can go very badly.
Izpack 4 used the language code "ind" for Indonesian, but
Izpack 5 switched to use the country code "idn" instead.
This worked fine on Java 8, but on Java 21, the best match finds Javanese/Jawa for "idn",
which is a completely different language than Indonesian.
See: https://old.reddit.com/r/i2p/comments/1e61lsp/wrong_country_name_indonesia_as_jawa/
Renamed or custom langpacks (xml + gif) must be checked in to
installer/lib/izpack5/patches/resources
and may then be added below, and will be bundled with the installer.
Note that the JVM's installed locales varies widely by Java version.
For example, as of 2024 on Ubuntu, Java 8 has 159 locales and Java 21 has 1050.
The selected locale may even depend on the ordering of locales returned by getAvailableLocales() in the JVM.
If no locale for any code is found, it outputs "WARNING: No locale for xx"
which is annoying. Even worse, if no locale found, it doesn't display the translation
as an option.
But that shouldn't stop us from including it if some JVMs have it.
-->
<locale>
<langpack iso3="eng"/>
<!--
Brazilian Portuguese
see above, wrongly matches neegatu, replaced by por.
Portuguese (Portugal) is prt below.
<langpack iso3="bra"/>
-->
<langpack iso3="por"/>
<langpack iso3="cat"/>
<langpack iso3="ces"/>
<!--
Chinese
see above, wrongly matches Sichuan Yi (iii), replaced by zho
<langpack iso3="chn"/>
-->
<langpack iso3="zho"/>
<langpack iso3="dan"/>
<langpack iso3="deu"/>
<langpack iso3="ell"/>
<!-- fa not found in older JVMs, may generate warning, see above -->
<langpack iso3="fa"/>
<langpack iso3="fin"/>
<langpack iso3="fra"/>
<langpack iso3="hun"/>
<!--
see above, replaced by ind
<langpack iso3="idn"/>
-->
<langpack iso3="ind"/>
<langpack iso3="ita"/>
<langpack iso3="jpn"/>
<langpack iso3="kor"/>
@@ -65,10 +127,10 @@ https://izpack.atlassian.net/wiki/spaces/IZPACK/pages/491730/GUI+Preferences
<langpack iso3="twn"/>
<langpack iso3="ukr"/>
<!--
At runtime, if the JVM does not have a locale:
"WARNING: No locale for:"
<langpack iso3="eus"/>
<langpack iso3="fa"/>
<langpack iso3="glg"/>
<langpack iso3="eus"/> Basque
<langpack iso3="glg"/> Galician
-->
</locale>
Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

+352
View File
@@ -0,0 +1,352 @@
<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
<!-- The Indonesian langpack -->
<!-- translation provided by Thomas Edwin Santosa - thomas (at) katalisindonesia dot com-->
<izpack:langpack version="5.0"
xmlns:izpack="http://izpack.org/schema/langpack"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://izpack.org/schema/langpack http://izpack.org/schema/5.0/izpack-langpack-5.0.xsd">
<!-- Heading messages START -->
<str id="CheckedHelloPanel.headline" txt="Selamat Datang"/>
<str id="CompilePanel.headline" txt="Kompilasi Kode Sumber Java"/>
<str id="ConditionalUserInputPanel.headline" txt="Data Pengguna"/>
<str id="FinishPanel.headline" txt="Pemasangan Telah Selesai"/>
<str id="HelloPanel.headline" txt="Selamat Datang"/>
<str id="HTMLInfoPanel.headline" txt="Informasi"/>
<str id="HTMLLicencePanel.headline" txt="Perjanjian Lisensi"/>
<str id="PDFLicencePanel.headline" txt="Perjanjian Lisensi"/>
<str id="ImgPacksPanel.headline" txt="Pilih Paket-Paket Pemasangan"/>
<str id="InfoPanel.headline" txt="Informasi"/>
<str id="InstallPanel.headline" txt="Pemasangan"/>
<str id="JDKPathPanel.headline" txt="Alamat JDK"/>
<str id="LicencePanel.headline" txt="Perjanjian Lisensi"/>
<str id="PacksPanel.headline" txt="Pilih Paket-Paket Pemasangan"/>
<str id="ProcessPanel.headline" txt="Lakukan Proses-Proses Eksternal"/>
<str id="ShortcutPanel.headline" txt="Jalan-Jalan Pintas"/>
<str id="SimpleFinishPanel.headline" txt="Pemasangan Telah Selesai"/>
<str id="SummaryPanel.headline" txt="Ringkasan Data Konfigurasi"/>
<str id="TargetPanel.headline" txt="Alamat Tujuan"/>
<str id="TreePacksPanel.headline" txt="Pilih Paket-Paket Pemasangan"/>
<str id="UserInputPanel.headline" txt="Data Pengguna"/>
<str id="UserPathPanel.headline" txt="Pilih Lokasi"/>
<str id="InstallationTypePanel.headline" txt="Jenis Pemasangan"/>
<!-- ConsolePrompt strings -->
<str id="ConsolePrompt.okCancel" txt="Enter O for OK, C to Cancel: "/>
<str id="ConsolePrompt.yesNo" txt="Enter Y for Yes, N for No: "/>
<str id="ConsolePrompt.yesNoCancel" txt="Enter Y for Yes, N for No, or C to Cancel: "/>
<str id="ConsolePrompt.ok" txt="O"/>
<str id="ConsolePrompt.cancel" txt="C"/>
<str id="ConsolePrompt.yes" txt="Y"/>
<str id="ConsolePrompt.no" txt="N"/>
<!-- ConsoleInstaller strings -->
<str id="ConsoleInstaller.continueQuitRedisplay" txt="Press 1 to continue, 2 to quit, 3 to redisplay"/>
<str id="ConsoleInstaller.acceptRejectRedisplay" txt="Press 1 to accept, 2 to reject, 3 to redisplay"/>
<str id="ConsoleInstaller.redisplayQuit" txt="Press 1 to redisplay, 2 to quit"/>
<str id="ConsoleInstaller.permissionError" txt="Administrative privileges required. Please re-run the installer with administrative privileges."/>
<str id="ConsoleInstaller.inputSelection" txt="Input selection: "/>
<str id="ConsoleInstaller.pagingMore" txt="More"/>
<str id="ConsoleInstaller.aborted.PressedCTRL-C" txt="CTRL-C pressed"/>
<str id="ConsoleInstaller.aborted.LicenseRejected" txt="License rejected"/>
<str id="ConsoleInstaller.aborted.PressedQuit" txt="Quit pressed"/>
<str id="ConsoleInstaller.shutdown.pendingFileOperations" txt="There are file operations pending after reboot"/>
<str id="ConsoleInstaller.shutdown.rebootingNow" txt="Rebooting now automatically"/>
<str id="ConsoleInstaller.shutdown.done" txt="Console installation done"/>
<str id="ConsoleInstaller.shutdown.aborted" txt="Console installation ABORTED by the user!"/>
<str id="ConsoleInstaller.shutdown.failed" txt="Console installation FAILED!"/>
<!-- General installer strings -->
<str id="installer.title" txt="IzPack - Pemasangan "/>
<str id="installer.next" txt="Berikut"/>
<str id="installer.prev" txt="Sebelum"/>
<str id="installer.quit" txt="Keluar"/>
<str id="installer.madewith" txt="(Dibuat dengan IzPack- http://izpack.org/)"/>
<str id="installer.quit.title" txt="Apakah Anda yakin ingin keluar?"/>
<str id="installer.quit.message" txt="Ini akan membatalkan pemasangan!"/>
<str id="installer.warning" txt="Peringatan!"/>
<str id="installer.yes" txt="Ya"/>
<str id="installer.no" txt="Tidak"/>
<str id="installer.cancel" txt="Batal"/>
<str id="installer.error" txt="Kesalahan"/>
<str id="installer.help" txt="Pertolongan"/>
<str id="installer.help.close" txt="Tutup"/>
<str id="installer.of" txt="dari"/>
<str id="installer.step" txt="Langkah"/>
<str id="installer.Message" txt="Pesan"/>
<str id="installer.errorMessage" txt="An error occured"/>
<str id="installer.close" txt="Close"/>
<str id="installer.showDetails" txt="Show Details"/>
<str id="installer.hideDetails" txt="Hide Details"/>
<str id="installer.copy" txt="Copy"/>
<str id="installer.sendReport" txt="Send Report"/>
<str id="installer.continueQuestion" txt="Continue anyway?"/>
<str id="installer.cancelled" txt="Installation cancelled"/>
<str id="installer.started" txt="Installation started"/>
<str id="installer.platform" txt="Platform: {0}"/>
<str id="installer.version" txt="Framework: {0}"/>
<str id="installer.finished" txt="Installation finished"/>
<!-- Uninstaller specific strings -->
<str id="uninstaller.warning" txt="Ini akan menghapus aplikasi terpasang!"/>
<str id="uninstaller.destroytarget" txt=" Memaksa penghapusan "/>
<str id="uninstaller.uninstall" txt="Penghapusan"/>
<!-- The strings for the 'official' IzPack plugins -->
<str id="HelloPanel.welcome1" txt="Selamat datang ke pemasangan "/>
<str id="HelloPanel.welcome2" txt="!"/>
<str id="HelloPanel.authors" txt="Perangkat lunak ini dikembangkan oleh: "/>
<str id="HelloPanel.url" txt="Halaman rumah berada di: "/>
<str id="PrinterSelectPanel.select_printer"
txt="Pilihlah printer yang digunakan untuk pemasangan awal dan pengetesan."/>
<str id="CheckedHelloPanel.productAlreadyExist0" txt="Produk ini sudah terpasang di komputer ini pada lokasi "/>
<str id="CheckedHelloPanel.productAlreadyExist1" txt=" . Apakah Anda yakin untuk memasang entitas lain?"/>
<str id="CheckedHelloPanel.infoOverUninstallKey" txt="Kunci penghapusan akan dinamai: "/>
<str id="LicencePanel.info" txt="Silakan baca perjanjian lisensi berikut dengan seksama:"/>
<str id="LicencePanel.agree" txt="Saya menerima syarat-syarat dan kondisi-kondisi perjanjian lisensi ini."/>
<str id="LicencePanel.notagree"
txt="Saya tidak menerima syarat-syarat dan kondisi-kondisi perjanjian lisensi ini."/>
<str id="LicencePanel.yes" txt="Ya"/>
<str id="LicencePanel.no" txt="Tidak"/>
<str id="InstallationTypePanel.info" txt="Silakan pilih jenis pemasangan:"/>
<str id="InstallationTypePanel.modify" txt="Mengubah pemasangan"/>
<str id="InstallationTypePanel.normal" txt="Pemasangan baru"/>
<str id="InfoPanel.info" txt="Silakan baca informasi berikut: "/>
<str id="PathInputPanel.required" txt="Direktori yang terpilih seharusnya ada."/>
<str id="PathInputPanel.required.forModificationInstallation" txt="Direktori terpilih harus ada."/>
<str id="PathInputPanel.notValid" txt="Direktori terpilih tidak mengandung produk yang diperlukan."/>
<str id="TargetPanel.info" txt="Silakan pilih lokasi pemasangan: "/>
<str id="TargetPanel.browse" txt="Jelajah..."/>
<str id="TargetPanel.warn"
txt="Direktori tersebut sudah ada! Apakah Anda yakin untuk melakukan pemasangan ke sana dan kemungkinan menimpa arsip-arsip yang telah ada?"/>
<str id="TargetPanel.empty_target"
txt="Anda belum menspesifikasi lokasi tujuan! Apakah betul?"/>
<str id="TargetPanel.createdir" txt="Direktori tujuan akan dibuat: "/>
<str id="TargetPanel.nodir"
txt="Arsip ini bukan direktori! Silakan pilih sebuah direktori!"/>
<str id="TargetPanel.notwritable"
txt="Direktori ini tidak dapat ditulisi! Silakan pilih direktori lain!"/>
<str id="JDKPathPanel.extendedIntro"
txt="Aplikasi yang telah dipasang membutuhkan sebuah JDK dengan versi antara ${JDKPathPanel.minVersion} dan ${JDKPathPanel.maxVersion}. Sebuah Java Runtime Environment (JRE) tidak cukup."/>
<str id="JDKPathPanel.intro"
txt="Instalasi yang terinstal membutuhkan JDK. Sebuah Java Runtime Environment (JRE) saja tidak akan cukup."/>
<str id="JDKPathPanel.info" txt="Silakan pilih alamat JDK:"/>
<str id="JDKPathPanel.badVersion1" txt="JDK yang terpilih memiliki versi yang salah (yang ada: "/>
<str id="JDKPathPanel.badVersion2" txt=" yang diperlukan: "/>
<str id="JDKPathPanel.badVersion3" txt=") apakah JDK ini tetap akan digunakan?"/>
<str id="JDKPathPanel.nonValidPathInReg"
txt="The Windows registry contains a non-valid path for this JDK. Should this JDK be used anyway?"/>
<str id="PacksPanel.info" txt="Silakan pilih paket-paket yang ingin Anda pasang:"/>
<str id="PacksPanel.tip" txt="Catatan: paket-paket yang berwarna kelabu diperlukan."/>
<str id="PacksPanel.space" txt="Jumlah ruang yang dibutuhkan: "/>
<str id="PacksPanel.freespace" txt="Ruang yang ada: "/>
<str id="PacksPanel.description" txt="Deskripsi"/>
<str id="PacksPanel.dependencyList"
txt="Paket yang terpilih membutuhkan paket-paket berikut dipasang "/>
<str id="PacksPanel.dependencies" txt="Ketergantungan: "/>
<str id="PacksPanel.excludes" txt="Pengecualian: "/>
<str id="ImgPacksPanel.dependencyList" txt="Ketergantungan"/>
<str id="PacksPanel.notEnoughSpace"
txt="Ruang cakram yang diperlukan untuk pemasangan melebihi ruang cakram yang tersedia."/>
<str id="PacksPanel.notAscertainable" txt="tidak dapat ditetapkan"/>
<str id="InstallPanel.info" txt="Klik 'Pasang!' untuk memulai proses pemasangan"/>
<str id="InstallPanel.install" txt="Pasang!"/>
<str id="InstallPanel.tip" txt="Perkembangan pemasangan paket:"/>
<str id="InstallPanel.begin" txt="[Tidak ada]"/>
<str id="InstallPanel.finished" txt="[Selesai]"/>
<str id="InstallPanel.progress" txt="Perkembangan pemasangan keseluruhan:"/>
<str id="InstallPanel.overwrite.title" txt="Arsip sudah ada"/>
<str id="InstallPanel.overwrite.question" txt="Arsip berikut sudah ada. Apakah akan ditimpa?"/>
<str id="FinishPanel.success" txt="Pemasangan telah selesai dengan sukses."/>
<str id="FinishPanel.done" txt="Selesai"/>
<str id="FinishPanel.fail" txt="Pemasangan gagal!"/>
<str id="FinishPanel.uninst.info" txt="Program penghapusan sudah dibuat di: "/>
<str id="FinishPanel.auto" txt="Buat naskah pemasangan otomatis"/>
<str id="FinishPanel.auto.tip"
txt="Gunakan naskah ini untuk mengulangi pemasangan ini ke komputer lain."/>
<str id="FinishPanel.auto.dialog.filterdesc" txt="Arsip-arsip XML"/>
<str id="ImgPacksPanel.packs" txt="Paket-paket berikut tersedia:"/>
<str id="ImgPacksPanel.snap" txt="Gambaran paket:"/>
<str id="ImgPacksPanel.checkbox" txt=" Pasang paket berikut"/>
<str id="ShortcutPanel.headline" txt="Pemasangan Jalan Pintas"/>
<str id="ShortcutPanel.regular.list" txt="Pilih Kelompok Program untuk Jalan Pintas:"/>
<str id="ShortcutPanel.regular.default" txt="Nilai awal"/>
<str id="ShortcutPanel.regular.desktop" txt="Buat jalan pintas di atas meja (desktop)"/>
<str id="ShortcutPanel.regular.StartMenu:Start-Menu" txt="Menu-Mulai"/>
<str id="ShortcutPanel.regular.StartMenu:K-Menu" txt="K-Menu"/>
<!-- "StartMenu" is a placeholder will be replaced at runtime -->
<str id="ShortcutPanel.regular.create" txt="Buat Jalan Pintas pada StartMenu"/>
<str id="ShortcutPanel.regular.userIntro" txt="buat jalan pintas untuk:"/>
<str id="ShortcutPanel.regular.currentUser" txt="pengguna sekarang"/>
<str id="ShortcutPanel.regular.allUsers" txt="semua pengguna"/>
<str id="ShortcutPanel.alternate.apology"
txt="Kami minta maaf karena IzPack tidak mendukung pembuatan jalan pintas di sistem operasi ini. Untuk membuat jalan pintas, silakan lihat petunjuk sistem operasi Anda."/>
<str id="ShortcutPanel.alternate.targetsLabel"
txt="Berikut ini adalah daftar tujuan-tujuan yang kami ingin Anda akses."/>
<str id="ShortcutPanel.alternate.textFileExplanation"
txt="Anda dapat menyimpan informasi terinci mengenai tujuan-tujuan aplikasi pada arsip teks untuk referensi di kemudian hari."/>
<str id="ShortcutPanel.alternate.saveButton" txt="Simpan Arsip Teks"/>
<str id="ShortcutPanel.textFile.header"
txt="Informasi Jalan Pintas\n======================\n\nBerikut ini adalah daftar semua informasi yang relevan tentang Jalan Pintas yang dimaksud. Informasi ini dapat digunakan untuk membuat jalan pintas secara manual.\n"/>
<str id="ShortcutPanel.textFile.name" txt="Jalan Pintas : "/>
<str id="ShortcutPanel.textFile.location" txt="Lokasi yang dimaksud : "/>
<str id="ShortcutPanel.textFile.description" txt="Dekripsi : "/>
<str id="ShortcutPanel.textFile.target" txt="Tujuan jalan pintas : "/>
<str id="ShortcutPanel.textFile.command" txt="Baris perintah : "/>
<str id="ShortcutPanel.textFile.iconName" txt="Arsip ikon : "/>
<str id="ShortcutPanel.textFile.iconIndex" txt="Indeks ikon : "/>
<str id="ShortcutPanel.textFile.work" txt="Direktori kerja : "/>
<str id="ShortcutPanel.location.desktop" txt="Atas Meja (Desktop)"/>
<str id="ShortcutPanel.location.applications" txt="Menu Aplikasi"/>
<str id="ShortcutPanel.location.startMenu" txt="Menu Awal"/>
<str id="ShortcutPanel.location.startup" txt="Grup Mulai Awal (Startup)"/>
<str id="UserInputPanel.error.caption" txt="Masalah Masukan"/>
<str id="UserInputPanel.search.autodetect" txt="Deteksi otomatis"/>
<str id="UserInputPanel.dir.nodirectory.message" txt="Anda harus memilih sebuah direktori yang sahih."/>
<str id="UserInputPanel.dir.nodirectory.caption" txt="Tidak Ada Direktori Terpilih"/>
<str id="UserInputPanel.dir.notdirectory.message"
txt="Direktori yang telah Anda pilih tidak ada atau tidak sahih."/>
<str id="UserInputPanel.dir.notdirectory.caption" txt="Direktori Tidak Sahih"/>
<str id="UserInputPanel.file.nofile.message" txt="Anda harus memilih sebuah berkas yang sahih."/>
<str id="UserInputPanel.file.nofile.caption" txt="Tidak Ada Berkas Terpilih"/>
<str id="UserInputPanel.file.notfile.message" txt="Berkas yang telah Anda pilih tidak ada atau tidak sahih."/>
<str id="UserInputPanel.file.notfile.caption" txt="Berkas Tidak Sahih"/>
<!-- more descriptive error message would be cool, like specifying what file we looked for -->
<str id="UserInputPanel.search.autodetect.failed.message" txt="Deteksi otomatis gagal."/>
<str id="UserInputPanel.search.autodetect.failed.caption" txt="Deteksi otomatis gagal."/>
<str id="UserInputPanel.search.autodetect.tooltip"
txt="Silakan periksa arsip atau direktori di alamat yang diberikan di atas."/>
<str id="UserInputPanel.search.location" txt="Masukkan lokasi {0}."/>
<str id="UserInputPanel.search.location.checkedfile" txt="Keberadaan {0} telah diperiksa."/>
<str id="UserInputPanel.search.browse" txt="Jelajah..."/>
<str id="UserInputPanel.search.wrongselection.message"
txt="Arsip atau direktori yang Anda pilih tidak ada atau tidak cocok."/>
<str id="UserInputPanel.search.wrongselection.caption" txt="Pilihan yang tidak sahih."/>
<str id="UserPathPanel.required" txt="Direktori terpilih harus ada."/>
<str id="UserPathPanel.info" txt="Pilih lokasi: "/>
<str id="UserPathPanel.browse" txt="Jelajah"/>
<str id="UserPathPanel.exists_warn"
txt="Direktori tersebut sudah ada! Apakah Anda yakin untuk melakukan pemasangan di sini dan kemungkinan menindih berkas yang telah ada?"/>
<str id="UserPathPanel.empty_target" txt="Anda belum menentukan lokasi target! Apakah benar?"/>
<str id="UserPathPanel.createdir" txt="Direktori target tersebut akan dibuat: "/>
<str id="UserPathPanel.nodir" txt="Berkas ini bukan suatu direktori! Silakan pilih suatu direktori!"/>
<str id="UserPathPanel.notwritable" txt="Direktori ini tidak dapat ditulisi! Silakan pilih direktori lain!"/>
<str id="CompilePanel.heading" txt="Kompilasi"/>
<str id="CompilePanel.tip" txt="Perkembangan pekerjaan kompilasi:"/>
<str id="CompilePanel.browse" txt="Jelajah..."/>
<str id="CompilePanel.browse.approve" txt="Gunakan sebagai kompiler"/>
<str id="CompilePanel.start" txt="Mulai"/>
<str id="CompilePanel.progress.initial" txt="[Silakan tekan tombol Mulai]"/>
<str id="CompilePanel.progress.finished" txt="[Selesai]"/>
<str id="CompilePanel.progress.overall" txt="Perkembangan kompilasi keseluruhan:"/>
<str id="CompilePanel.error" txt="Kompilasi gagal"/>
<str id="CompilePanel.error.reconfigure" txt="Konfigurasi ulang"/>
<str id="CompilePanel.error.ignore" txt="Abaikan"/>
<str id="CompilePanel.error.abort" txt="Batalkan"/>
<str id="CompilePanel.error.seebelow" txt="Lihat dibawah untuk perintah yang gagal dan keluarannya."/>
<str id="CompilePanel.error.nofiles" txt="Kesalahan terjadi saat melarik arsip-arsip untuk kompilasi."/>
<str id="CompilePanel.error.compilernotfound" txt="Kompiler tidak dapat dijalankan."/>
<str id="CompilePanel.error.invalidarguments" txt="Kompiler menerima argumen-argumen yang tidak sahih."/>
<str id="CompilePanel.error.noclassfile" txt="Kompiler tidak dapat menghasilkan arsip kelas untuk arsip sumber "/>
<str id="CompilePanel.choose_compiler" txt="Kompiler yang digunakan:"/>
<str id="CompilePanel.additional_arguments" txt="Argumen-argumen tambahan kompiler:"/>
<str id="ProcessPanel.heading" txt="Pemrosesan"/>
<!-- Strings for the summary of panels - START -->
<str id="SummaryPanel.info"
txt="Siap untuk pemasangan. Daftar data yang penting terdapat di bawah. Tekan &quot;Berikut&quot; untuk memulai pemasangan."/>
<str id="SummaryPanel.next" txt="Berikut"/>
<str id="TargetPanel.summaryCaption" txt="Lokasi pemasangan"/>
<str id="JDKPathPanel.summaryCaption" txt="Lokasi JDK"/>
<str id="PacksPanel.summaryCaption" txt="Paket-paket pemasangan yang dipilih"/>
<str id="ImgPacksPanel.summaryCaption" txt="Paket-paket pemasangan yang dipilih"/>
<str id="TreePacksPanel.summaryCaption" txt="Paket-paket pemasangan yang dipilih"/>
<str id="UserPathPanel.summaryCaption" txt="Lokasi Terpilih"/>
<!-- Strings for the summary of panels - END -->
<!-- Strings for the Registry -->
<str id="functionFailed.RegOpenKeyEx" txt="Tidak dapat membuka kunci registri {0}\\{1}"/>
<!-- Add your own panels specific strings here if you need or use a custom
langpack with the same syntax referred as resource CustomLangpack.xml_[ISO3]"
-->
<str id="nextmedia.title" txt="Media pemasangan berikutnya"/>
<str id="nextmedia.msg" txt="Pilih media pemasangan berikutnya."/>
<str id="nextmedia.browsebtn" txt="Jelajah"/>
<str id="nextmedia.okbtn" txt="Terapkan"/>
<str id="nextmedia.cancelbtn" txt="Batal"/>
<str id="nextmedia.choosertitle" txt="Pilih media pemasangan"/>
<str id="nextmedia.filedesc" txt="pak pemasangan (.pak*)"/>
<!-- Strings for the logging/reporting system (Messenger) -->
<!-- This string defines the time stamp format in the installation report.
The format details are documented in java.text.SimpleDateFormat -->
<str id="log.timeStamp" txt="dd-MM-yyyy [HH:mm:ss] zzzz"/>
<!-- Strings for various purposes in the logging/reporting system -->
<str id="log.reportHeading" txt=" LAPORAN PEMASANGAN IzPack"/>
<str id="log.installFailed" txt="PERINGATAN!!! Pemasangan tidak berhasil!"/>
<str id="log.partialInstall" txt="PERINGATAN!!! Pemasangan bisa jadi telah tidak selesai dengan sukses!"/>
<str id="log.messageCount" txt="Laporan ini mengandung {0} pesan umum, {1} peringatan and {2} kesalahan(s)"/>
<str id="log.application" txt="Laporan pemasangan untuk : {0} Versi {1}"/>
<str id="log.timePrefix" txt="Waktu pemasangan : {0}"/>
<str id="log.pathPrefix" txt="Direktori pemasangan : {0}"/>
<str id="log.messageHeading" txt=" --- Pesan-Pesan Pemasangan ---"/>
<str id="log.warningHeading" txt=" --- Peringatan-Peringatan ---"/>
<str id="log.errorHeading" txt=" --- Kesalahan-Kesalahan---"/>
<str id="log.exceptionPrefix" txt=" >> Eksepsi: {0}"/>
<str id="log.messagePrefix" txt="Pesan [{0}] - "/>
<str id="log.warningPrefix" txt="Warning [{0}] - "/>
<str id="log.errorPrefix" txt="Kesalahan [{0}] - "/>
<str id="log.reportWriteErrorTitle" txt="Kesalahan dalam penulisan laporan"/>
<str id="log.reportWriteError" txt="Tidak dapat menulis laporan pemasangan ke ''{0}''"/>
<str id="log.informUserTitle" txt="Masalah-Masalah Pemasangan"/>
<str id="log.saveLogTitle" txt="Simpan Berkas Catatan"/>
<str id="log.LogFileName" txt="catatanPemasangan.txt"/>
<str id="log.informUserFail"
txt="&lt;html&gt;Pemasangan tidak berhasil!&lt;br&gt;Apakah Anda ingin menulis suatu berkas catatan?&lt;/html&gt;"/>
<str id="log.informUserPartial"
txt="&lt;html&gt;Pemasangan bisa jadi telah tidak selesai dengan sukses!&lt;br&gt;Apakah Anda ingin menulis suatu berkas catatan?&lt;/html&gt;"/>
<!-- Strings for individual messages in the logging/reporting system.
Numbers for each category (message/warning/error) start at 0 -->
<str id="log.message_" txt=""/>
<str id="log.warning_" txt=""/>
<str id="log.error_0" txt="tidak dapat menulis ''{0}''"/>
<str id="InstallationGroupPanel.colNameSelected" txt="Terpilih"/>
<str id="InstallationGroupPanel.colNameInstallType" txt="JenisPemasangan"/>
<str id="InstallationGroupPanel.colNameSize" txt="Ukuran"/>
<str id="debug.changevariable" txt="ubah nilai"/>
</izpack:langpack>
+279
View File
@@ -0,0 +1,279 @@
<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
<!-- The Brazilian Portuguese langpack -->
<izpack:langpack version="5.0"
xmlns:izpack="http://izpack.org/schema/langpack"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://izpack.org/schema/langpack http://izpack.org/schema/5.0/izpack-langpack-5.0.xsd">
<!-- Heading messages START -->
<str id="CheckedHelloPanel.headline" txt="Bem vindo"/>
<str id="CompilePanel.headline" txt="Compilar códigos Java"/>
<str id="ConditionalUserInputPanel.headline" txt="Dados do usuário"/>
<str id="FinishPanel.headline" txt="Instalação terminada"/>
<str id="HelloPanel.headline" txt="Bem vindo"/>
<str id="HTMLInfoPanel.headline" txt="Informações"/>
<str id="HTMLLicencePanel.headline" txt="Acordo de licença"/>
<str id="PDFLicencePanel.headline" txt="Acordo de licença"/>
<str id="ImgPacksPanel.headline" txt="Selecione pacotes de instalação"/>
<str id="InfoPanel.headline" txt="Informações"/>
<str id="InstallPanel.headline" txt="Instalação"/>
<str id="JDKPathPanel.headline" txt="Caminho do JDK"/>
<str id="LicencePanel.headline" txt="Acordo de licença"/>
<str id="PacksPanel.headline" txt="Selecione pacotes de instalação"/>
<str id="ProcessPanel.headline" txt="Executar processos externos"/>
<str id="ShortcutPanel.headline" txt="Atalhos"/>
<str id="SimpleFinishPanel.headline" txt="Instalação terminada"/>
<str id="SummaryPanel.headline" txt="Resumo dos dados do usuário"/>
<str id="TargetPanel.headline" txt="Caminho de destino"/>
<str id="TreePacksPanel.headline" txt="Selecione pacotes de instalação"/>
<str id="UserInputPanel.headline" txt="Dados do usuário"/>
<!-- General installer strings -->
<str id="installer.title" txt="IzPack - Instalação de "/>
<str id="installer.next" txt="Próximo"/>
<str id="installer.prev" txt="Anterior"/>
<str id="installer.quit" txt="Sair"/>
<str id="installer.madewith" txt="(Criado com IzPack - http://izpack.org/)"/>
<str id="installer.quit.title" txt="Tem certeza de que deseja sair ?"/>
<str id="installer.quit.message" txt="Você quer cancelar a instalação?"/>
<str id="installer.warning" txt="Aviso !"/>
<str id="installer.yes" txt="Sim"/>
<str id="installer.no" txt="Não"/>
<str id="installer.cancel" txt="Cancelar"/>
<str id="installer.error" txt="Erro"/>
<str id="installer.help" txt="Ajuda"/>
<str id="installer.help.close" txt="Fechar"/>
<str id="installer.step" txt="Passo"/>
<str id="installer.of" txt="de"/>
<str id="installer.Message" txt="Mensagem"/>
<str id="installer.errorMessage" txt="Ocorreu um erro"/>
<str id="installer.close" txt="Fechar"/>
<str id="installer.showDetails" txt="Mostrar Detalhes"/>
<str id="installer.hideDetails" txt="Ocultar Detalhes"/>
<str id="installer.copy" txt="Copiar"/>
<str id="installer.sendReport" txt="Enviar Relatório"/>
<str id="installer.continueQuestion" txt="Deseja Continuar?"/>
<str id="installer.cancelled" txt="Instalação cancelada"/>
<str id="installer.started" txt="Installation started"/>
<str id="installer.platform" txt="Platform: {0}"/>
<str id="installer.version" txt="Framework: {0}"/>
<str id="installer.finished" txt="Installation finished"/>
<!-- Uninstaller specific strings -->
<str id="uninstaller.warning" txt="Isto removerá o(s) aplicativo(s) instalado(s) !"/>
<str id="uninstaller.destroytarget" txt=" Forçar a remoção de "/>
<str id="uninstaller.uninstall" txt="Desinstalar"/>
<!-- The strings for the 'official' IzPack plugins -->
<str id="HelloPanel.welcome1" txt="Bem vindo à instalação de "/>
<str id="HelloPanel.welcome2" txt=" !"/>
<str id="HelloPanel.authors" txt="Este programa foi desenvolvido por : "/>
<str id="HelloPanel.url" txt="A página do programa é : "/>
<str id="PrinterSelectPanel.select_printer"
txt="Selecione a impressora para utilizar na configuração inicial e teste."/>
<str id="CheckedHelloPanel.productAlreadyExist0" txt="Este produto já se encontra instalado neste computador em "/>
<str id="CheckedHelloPanel.productAlreadyExist1" txt=" . Você tem certeza de que quer instalar outra cópia?"/>
<str id="CheckedHelloPanel.infoOverUninstallKey" txt="A chave de desinstalação será chamada: "/>
<!-- ConsolePrompt strings -->
<str id="ConsolePrompt.okCancel" txt="Pressione O (Ok), (C) Cancelar: "/>
<str id="ConsolePrompt.yesNo" txt="Pressione (S) Sim, (N) Não: "/>
<str id="ConsolePrompt.yesNoCancel" txt="Pressione S (Sim), (N) Não ou C (Cancelar): "/>
<str id="ConsolePrompt.ok" txt="O"/>
<str id="ConsolePrompt.cancel" txt="C"/>
<str id="ConsolePrompt.yes" txt="S"/>
<str id="ConsolePrompt.no" txt="N"/>
<!-- ConsoleInstaller strings -->
<str id="ConsoleInstaller.continueQuitRedisplay"
txt="Pressione: (1) continuar, (2) sair, (3) mostrar novamente"/>
<str id="ConsoleInstaller.acceptRejectRedisplay"
txt="Pressione: (1) aceitar, (2) rejeitar, (3) mostrar novamente"/>
<str id="ConsoleInstaller.redisplayQuit" txt="Pressione: (1) mostrar novamente, (2) sair"/>
<str id="ConsoleInstaller.permissionError"
txt="Previlégios administrativos necessário. Por favor reexecute o instalador com previlégios administrativos."/>
<str id="ConsoleInstaller.inputSelection" txt="Selecione: "/>
<str id="ConsoleInstaller.pagingMore" txt="Mais"/>
<str id="ConsoleInstaller.aborted.PressedCTRL-C" txt="CTRL-C pessionado"/>
<str id="ConsoleInstaller.aborted.LicenseRejected" txt="Licença rejeitada"/>
<str id="ConsoleInstaller.aborted.PressedQuit" txt="Sair pressionado"/>
<str id="ConsoleInstaller.shutdown.pendingFileOperations" txt="Há operações de arquivo pendentes após a reinicialização"/>
<str id="ConsoleInstaller.shutdown.rebootingNow" txt="O sistemas será reiniciando"/>
<str id="ConsoleInstaller.shutdown.done" txt="Instalção concluída"/>
<str id="ConsoleInstaller.shutdown.aborted" txt="Instalação abortada!"/>
<str id="ConsoleInstaller.shutdown.failed" txt="Instalação falhou!"/>
<str id="LicencePanel.info" txt="Por favor, leia o seguinte contrato de licença :"/>
<str id="LicencePanel.agree" txt="Eu concordo com este contrato de licença."/>
<str id="LicencePanel.notagree" txt="Eu não concordo com este contrato de licença."/>
<str id="LicencePanel.yes" txt="Sim"/>
<str id="LicencePanel.no" txt="Não"/>
<str id="InfoPanel.info" txt="Por favor, leia a seguinte informação :"/>
<str id="PathInputPanel.required" txt="O diretório escolhido deve existir."/>
<str id="PathInputPanel.notValid" txt="O diretório escolhido não contém o produto requerido."/>
<str id="TargetPanel.info" txt="Selecione o caminho para instalação :"/>
<str id="TargetPanel.browse" txt="Procurar ..."/>
<str id="TargetPanel.warn"
txt="O diretório já existe ! Tem certeza de que quer instalar neste diretório e possivelmente sobrescrever arquivos existentes?"/>
<str id="TargetPanel.empty_target"
txt="Você não especificou um local! Isto está correto?"/>
<str id="TargetPanel.createdir" txt="O diretório especificado será criado :"/>
<str id="TargetPanel.nodir"
txt="Este arquivo não é um diretório! Por favor, selecione um diretório!"/>
<str id="TargetPanel.notwritable"
txt="Este diretório não pode ser escrito! Por favor, escolha outro diretório!"/>
<str id="JDKPathPanel.extendedIntro"
txt="O programa instalado necessita um JDK com versão entre ${JDKPathPanel.minVersion} e ${JDKPathPanel.maxVersion}. Um &quot;Java Runtime Environment&quot; (JRE) não é suficiente."/>
<str id="JDKPathPanel.intro"
txt="O programa instalado necessita um JDK. Um &quot;Java Runtime Environment&quot; (JRE) não é suficiente."/>
<str id="JDKPathPanel.info" txt="Selecione o caminho do JDK:"/>
<str id="JDKPathPanel.badVersion1" txt="O JDK escolhido tem versão não recomendada (Disponível: "/>
<str id="JDKPathPanel.badVersion2" txt=" Necessário: "/>
<str id="JDKPathPanel.badVersion3" txt="). Usar esse JDK mesmo assim?"/>
<str id="PacksPanel.info" txt="Selecione os pacotes que deseja instalar :"/>
<str id="PacksPanel.tip" txt="Nota: pacotes cinzas são requeridos."/>
<str id="PacksPanel.space" txt="Espaço total requerido: "/>
<str id="PacksPanel.freespace" txt="Espaço disponível: "/>
<str id="PacksPanel.description" txt="Descrição"/>
<str id="PacksPanel.dependencyList"
txt="O pacote escolhido tem as seguintes dependências e/ou exclui"/>
<str id="PacksPanel.dependencies" txt="Dependências: "/>
<str id="PacksPanel.excludes" txt="Exclui: "/>
<str id="ImgPacksPanel.dependencyList" txt="Dependências e/ou exclui"/>
<str id="PacksPanel.notEnoughSpace"
txt="O espaço em disco requerido para a instalação é maior que o espaço em disco disponível."/>
<str id="PacksPanel.notAscertainable" txt="não dedutível"/>
<str id="InstallPanel.info" txt="Clique 'Instalar !' para iniciar o processo de instalação"/>
<str id="InstallPanel.install" txt="Instalar !"/>
<str id="InstallPanel.tip" txt="Progresso da instalação :"/>
<str id="InstallPanel.begin" txt="[Nada]"/>
<str id="InstallPanel.finished" txt="[Terminado]"/>
<str id="InstallPanel.progress" txt="Progresso total da instalação:"/>
<str id="InstallPanel.overwrite.title" txt="O arquivo já existe."/>
<str id="InstallPanel.overwrite.question" txt="O seguinte arquivo já existe. Sobrescrevê-lo?"/>
<str id="FinishPanel.success" txt="Instalação realizada com sucesso."/>
<str id="FinishPanel.done" txt="Pronto"/>
<str id="FinishPanel.fail" txt="A instalação falhou!"/>
<str id="FinishPanel.uninst.info" txt="Um programa desinstalador foi criado em:"/>
<str id="FinishPanel.auto" txt="Gerar um script para instalação automática"/>
<str id="FinishPanel.auto.tip"
txt="Utilize este script para repetir esta instalação em outros computadores."/>
<str id="ImgPacksPanel.packs" txt="Os seguintes pacotes estão disponíveis :"/>
<str id="ImgPacksPanel.snap" txt="Visualização da tela do pacote :"/>
<str id="ImgPacksPanel.checkbox" txt=" Instalar este pacote"/>
<str id="ShortcutPanel.headline" txt="Configurar atalhos"/>
<str id="ShortcutPanel.regular.list" txt="Selecione um grupo para os atalhos:"/>
<str id="ShortcutPanel.regular.default" txt="Padrão"/>
<str id="ShortcutPanel.regular.desktop" txt="Criar atalhos adicionais na Área de Trabalho"/>
<str id="ShortcutPanel.regular.startup" txt="Executar na inicialização"/>
<str id="ShortcutPanel.regular.StartMenu:Start-Menu" txt="Start-Menu"/>
<str id="ShortcutPanel.regular.StartMenu:K-Menu" txt="K-Menu"/>
<!-- "StartMenu" is a placeholder will be replaced at runtime -->
<str id="ShortcutPanel.regular.create" txt="Criar Atalhos"/>
<str id="ShortcutPanel.regular.userIntro" txt="criar atalho para:"/>
<str id="ShortcutPanel.regular.currentUser" txt="usuário atual"/>
<str id="ShortcutPanel.regular.allUsers" txt="todos usuários"/>
<str id="ShortcutPanel.alternate.apology"
txt="Desculpe, mas IzPack não pode criar atalhos neste sistema operacional. Para criar os atalhos, favor consultar o manual de seu sistema operacional."/>
<str id="ShortcutPanel.alternate.targetsLabel"
txt="Esta é a lista de executáveis aos quais o produtor deste programa lhe deu acesso."/>
<str id="ShortcutPanel.alternate.textFileExplanation"
txt="Você pode salvar informações detalhadas sobre os arquivos executáveis em um arquivo de texto para referência futura."/>
<str id="ShortcutPanel.alternate.saveButton" txt="Salvar Arquivo de Texto"/>
<str id="ShortcutPanel.textFile.header"
txt="Informação Sobre Atalhos\n====================\n\nA seguinte é uma listagem de toda informação relevante sobre os atalhos\ndesejados. Esta informação deve possibilitar a criação manual de atalhos.\n"/>
<str id="ShortcutPanel.textFile.name" txt="Atalho : "/>
<str id="ShortcutPanel.textFile.location" txt="Local Desejado : "/>
<str id="ShortcutPanel.textFile.description" txt="Descrição : "/>
<str id="ShortcutPanel.textFile.target" txt="Arquivo Executável : "/>
<str id="ShortcutPanel.textFile.command" txt="Linha de Comando : "/>
<str id="ShortcutPanel.textFile.iconName" txt="Arquivo do Ícone : "/>
<str id="ShortcutPanel.textFile.iconIndex" txt="Índice do Ícone : "/>
<str id="ShortcutPanel.textFile.work" txt="Diretório de Trabalho : "/>
<str id="ShortcutPanel.location.desktop" txt="Desktop"/>
<str id="ShortcutPanel.location.applications" txt="Menu de Aplicativos"/>
<str id="ShortcutPanel.location.startMenu" txt="Menu Iniciar"/>
<str id="ShortcutPanel.location.startup" txt="Grupo Iniciar"/>
<str id="UserInputPanel.error.caption" txt="Erro de entrada"/>
<str id="UserInputPanel.search.autodetect" txt="Autodetecção"/>
<!-- more descriptive error message would be cool, like specifying what file we looked for -->
<str id="UserInputPanel.search.autodetect.failed.message" txt="Autodetecção falhou."/>
<str id="UserInputPanel.search.autodetect.failed.caption" txt="Autodetecção falhou."/>
<str id="UserInputPanel.search.autodetect.tooltip" txt="Procure pelo arquivo ou diretório nos caminhos abaixo."/>
<str id="UserInputPanel.search.location" txt="Entre a localização de {0}."/>
<str id="UserInputPanel.search.location.checkedfile" txt="A existencia de (0) é checada."/>
<str id="UserInputPanel.search.browse" txt="Procurar..."/>
<str id="UserInputPanel.search.wrongselection.message"
txt="O arquivo ou diretório escolhido não existe ou é não é apropriado."/>
<str id="UserInputPanel.search.wrongselection.caption" txt="Seleção inválida."/>
<str id="CompilePanel.heading" txt="Compilação"/>
<str id="CompilePanel.tip" txt="Progresso do trabalho de compilação:"/>
<str id="CompilePanel.browse" txt="Procurar..."/>
<str id="CompilePanel.browse.approve" txt="Usar como compilador"/>
<str id="CompilePanel.start" txt="Iniciar"/>
<str id="CompilePanel.progress.initial" txt="[Clique no botão Iniciar para instalar]"/>
<str id="CompilePanel.progress.finished" txt="[Terminado]"/>
<str id="CompilePanel.progress.overall" txt="Progresso total da compilação:"/>
<str id="CompilePanel.error" txt="Compilação falhou"/>
<str id="CompilePanel.error.reconfigure" txt="Reconfigurar"/>
<str id="CompilePanel.error.ignore" txt="Ignorar"/>
<str id="CompilePanel.error.abort" txt="Abortar"/>
<str id="CompilePanel.error.seebelow" txt="Veja abaixo o comando que falhou e sua saída."/>
<str id="CompilePanel.error.nofiles" txt="Erro durante a busca pelo arquivos para compilação."/>
<str id="CompilePanel.error.compilernotfound" txt="O compilador não pôde ser executado."/>
<str id="CompilePanel.error.invalidarguments" txt="O compilador recusou os argumentos fornecidos."/>
<str id="CompilePanel.error.noclassfile" txt="O compilador não gerou um arquivo class para o código fonte "/>
<str id="CompilePanel.choose_compiler" txt="Compilador a ser usado:"/>
<str id="CompilePanel.additional_arguments" txt="Argumentos adicionais do compilador:"/>
<str id="ProcessPanel.heading" txt="Processando"/>
<!-- Strings for the summary of panels - START -->
<str id="SummaryPanel.info"
txt="Pronto para instalar. Os dados importantes são listados abaixo. Clique &quot;Próximo&quot; para iniciar a instalação, "/>
<str id="SummaryPanel.next" txt="Proximo"/>
<str id="TargetPanel.summaryCaption" txt="Caminho da instalação"/>
<str id="JDKPathPanel.summaryCaption" txt="Caminho do JDK"/>
<str id="PacksPanel.summaryCaption" txt="Pacotes de instalação escolhidos"/>
<str id="ImgPacksPanel.summaryCaption" txt="Pacotes de instalação escolhidos"/>
<str id="TreePacksPanel.summaryCaption" txt="Pacotes de instalação escolhidos"/>
<!-- Strings for the summary of panels - END -->
<!-- Strings for the Registry -->
<str id="functionFailed.RegOpenKeyEx" txt="Não foi possível abrir a chave do registro {0}\\{1}."/>
<!-- Add your own panels specific strings here if you need or use a custom
langpack with the same syntax referred as resoure CustomLangpack.xml_[ISO3]"
-->
<str id="nextmedia.title" txt="Próxima mídia de instalação"/>
<str id="nextmedia.msg" txt="Escolha a próxima mídia de instalação."/>
<str id="nextmedia.browsebtn" txt="Explorar"/>
<str id="nextmedia.okbtn" txt="Aplicar"/>
<str id="nextmedia.cancelbtn" txt="Cancelar"/>
<str id="nextmedia.choosertitle" txt="Escolha a mídia de instalação"/>
<str id="nextmedia.filedesc" txt="pacotes de instalação (.pak*)"/>
</izpack:langpack>
+192
View File
@@ -0,0 +1,192 @@
<?xml version="1.0" encoding="GB2312" standalone="yes" ?>
<!-- The Simplified Chinese langpack -->
<izpack:langpack version="5.0"
xmlns:izpack="http://izpack.org/schema/langpack"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://izpack.org/schema/langpack http://izpack.org/schema/5.0/izpack-langpack-5.0.xsd">
<!-- ConsolePrompt strings -->
<str id="ConsolePrompt.okCancel" txt="Enter O for OK, C to Cancel: "/>
<str id="ConsolePrompt.yesNo" txt="Enter Y for Yes, N for No: "/>
<str id="ConsolePrompt.yesNoCancel" txt="Enter Y for Yes, N for No, or C to Cancel: "/>
<str id="ConsolePrompt.ok" txt="O"/>
<str id="ConsolePrompt.cancel" txt="C"/>
<str id="ConsolePrompt.yes" txt="Y"/>
<str id="ConsolePrompt.no" txt="N"/>
<!-- ConsoleInstaller strings -->
<str id="ConsoleInstaller.continueQuitRedisplay" txt="Press 1 to continue, 2 to quit, 3 to redisplay"/>
<str id="ConsoleInstaller.acceptRejectRedisplay" txt="Press 1 to accept, 2 to reject, 3 to redisplay"/>
<str id="ConsoleInstaller.redisplayQuit" txt="Press 1 to redisplay, 2 to quit"/>
<str id="ConsoleInstaller.permissionError" txt="Administrative privileges required. Please re-run the installer with administrative privileges."/>
<str id="ConsoleInstaller.inputSelection" txt="Input selection: "/>
<str id="ConsoleInstaller.pagingMore" txt="More"/>
<str id="ConsoleInstaller.aborted.PressedCTRL-C" txt="CTRL-C pressed"/>
<str id="ConsoleInstaller.aborted.LicenseRejected" txt="License rejected"/>
<str id="ConsoleInstaller.aborted.PressedQuit" txt="Quit pressed"/>
<str id="ConsoleInstaller.shutdown.pendingFileOperations" txt="There are file operations pending after reboot"/>
<str id="ConsoleInstaller.shutdown.rebootingNow" txt="Rebooting now automatically"/>
<str id="ConsoleInstaller.shutdown.done" txt="Console installation done"/>
<str id="ConsoleInstaller.shutdown.aborted" txt="Console installation ABORTED by the user!"/>
<str id="ConsoleInstaller.shutdown.failed" txt="Console installation FAILED!"/>
<!-- General installer strings -->
<str id="installer.title" txt="IzPack - 安装 "/>
<str id="installer.next" txt="下一步"/>
<str id="installer.prev" txt="上一步"/>
<str id="installer.quit" txt="退出"/>
<str id="installer.madewith" txt="(由IzPack制作生成 - http://izpack.org/)"/>
<str id="installer.quit.title" txt="是否确定退出?"/>
<str id="installer.quit.message" txt="将取消该安装过程 !"/>
<str id="installer.warning" txt="警告 !"/>
<str id="installer.yes" txt="是"/>
<str id="installer.no" txt="否"/>
<str id="installer.cancel" txt="取消"/>
<str id="installer.error" txt="错误"/>
<str id="installer.errorMessage" txt="An error occured"/>
<str id="installer.close" txt="Close"/>
<str id="installer.showDetails" txt="Show Details"/>
<str id="installer.hideDetails" txt="Hide Details"/>
<str id="installer.copy" txt="Copy"/>
<str id="installer.sendReport" txt="Send Report"/>
<str id="installer.continueQuestion" txt="Continue anyway?"/>
<str id="installer.cancelled" txt="Installation cancelled"/>
<str id="installer.started" txt="Installation started"/>
<str id="installer.platform" txt="Platform: {0}"/>
<str id="installer.version" txt="Framework: {0}"/>
<str id="installer.finished" txt="Installation finished"/>
<!-- Uninstaller specific strings -->
<str id="uninstaller.warning" txt="将卸载已安装的应用程序 !"/>
<str id="uninstaller.destroytarget" txt=" 强制删除 "/>
<str id="uninstaller.uninstall" txt="卸载"/>
<!-- The strings for the 'official' IzPack plugins -->
<str id="HelloPanel.welcome1" txt="欢迎安装"/>
<str id="HelloPanel.welcome2" txt=" !"/>
<str id="HelloPanel.authors" txt="该软件作者 : "/>
<str id="HelloPanel.url" txt="主页 : "/>
<str id="LicencePanel.info" txt="请仔细阅读以下许可协议:"/>
<str id="LicencePanel.agree" txt="我接受该许可协议的条款."/>
<str id="LicencePanel.notagree" txt="我不接受该许可协议的条款."/>
<str id="LicencePanel.yes" txt="是"/>
<str id="LicencePanel.no" txt="否"/>
<str id="InfoPanel.info" txt="请阅读以下信息 :"/>
<str id="TargetPanel.info" txt="选择安装路径 :"/>
<str id="TargetPanel.browse" txt="浏览 ..."/>
<str id="TargetPanel.warn"
txt="目录已经存在 ! 可能覆盖现存文件,是否确定在此安装?"/>
<str id="TargetPanel.empty_target"
txt="你没有指定目标路径! 是否正确?"/>
<str id="TargetPanel.createdir" txt="目标目录将创建在 :"/>
<str id="TargetPanel.nodir"
txt="该文件不是目录! 请选择一个目录!"/>
<str id="TargetPanel.notwritable"
txt="目录无法写入! 请选择其他目录!"/>
<str id="PacksPanel.info" txt="选择你要安装的包 :"/>
<str id="PacksPanel.tip" txt="注意: 灰色选项是必选的."/>
<str id="PacksPanel.space" txt="总需求空间: "/>
<str id="PacksPanel.freespace" txt="有效空间: "/>
<str id="PacksPanel.description" txt="描述"/>
<str id="PacksPanel.dependencyList" txt="所选包需要安装以下包"/>
<str id="ImgPacksPanel.dependencyList" txt="依赖"/>
<str id="PacksPanel.notEnoughSpace" txt="安装要求的磁盘空间超出了可用的磁盘空间."/>
<str id="PacksPanel.notAscertainable" txt="not ascertainable"/>
<str id="InstallPanel.info" txt="点击 '安装 !' 开始安装进程"/>
<str id="InstallPanel.install" txt="安装 !"/>
<str id="InstallPanel.tip" txt="包安装过程 :"/>
<str id="InstallPanel.begin" txt="[Nothing]"/>
<str id="InstallPanel.finished" txt="[完成]"/>
<str id="InstallPanel.progress" txt="Overall installation progress :"/>
<str id="InstallPanel.overwrite.title" txt="文件已经存在"/>
<str id="InstallPanel.overwrite.question" txt="以下文件已经存在. 是否进行覆盖?"/>
<str id="FinishPanel.success" txt="安装成功."/>
<str id="FinishPanel.done" txt="完成"/>
<str id="FinishPanel.fail" txt="安装失败!"/>
<str id="FinishPanel.uninst.info" txt="卸载程序已经创建在:"/>
<str id="FinishPanel.auto" txt="生成自动安装脚本"/>
<str id="FinishPanel.auto.tip"
txt="使用该脚本可以在其他计算机上反复本次安装."/>
<str id="ImgPacksPanel.packs" txt="当前可选包如下 :"/>
<str id="ImgPacksPanel.snap" txt="包快照 :"/>
<str id="ImgPacksPanel.checkbox" txt=" 安装该包"/>
<str id="ShortcutPanel.regular.list" txt="选择快捷方式的程序组:"/>
<str id="ShortcutPanel.regular.default" txt="重置"/>
<str id="ShortcutPanel.regular.desktop" txt="在桌面创建快捷方式"/>
<str id="ShortcutPanel.regular.create" txt="创建快捷方式"/>
<str id="ShortcutPanel.regular.userIntro" txt="创建快捷方式:"/>
<str id="ShortcutPanel.regular.currentUser" txt="当前用户"/>
<str id="ShortcutPanel.regular.allUsers" txt="所有用户"/>
<str id="ShortcutPanel.alternate.apology" txt="很遗憾IzPack不支持在当前操作系统上创建快捷方式. 创建快捷方式,请参考操作系统手册."/>
<str id="ShortcutPanel.alternate.targetsLabel"
txt="The following is a list of targets that the manufacturer of this software product wanted you to have access to."/>
<str id="ShortcutPanel.alternate.textFileExplanation" txt="为了以后参考,你可以把应用程序目标的详细信息保存在文本文件."/>
<str id="ShortcutPanel.alternate.saveButton" txt="保存文本文件"/>
<str id="ShortcutPanel.textFile.header"
txt="快捷方式信息\n====================\n\nThe following is a listing of all relevant information about the intended\nshortcuts. 该信息让手动创建快捷方式成为可能.\n"/>
<str id="ShortcutPanel.textFile.name" txt="快捷方式 : "/>
<str id="ShortcutPanel.textFile.location" txt="Intended Location : "/>
<str id="ShortcutPanel.textFile.description" txt="描述 : "/>
<str id="ShortcutPanel.textFile.target" txt="快捷目标 : "/>
<str id="ShortcutPanel.textFile.command" txt="命令行 : "/>
<str id="ShortcutPanel.textFile.iconName" txt="图标文件 : "/>
<str id="ShortcutPanel.textFile.iconIndex" txt="图标索引 : "/>
<str id="ShortcutPanel.textFile.work" txt="工作目录 : "/>
<str id="ShortcutPanel.location.desktop" txt="桌面"/>
<str id="ShortcutPanel.location.applications" txt="应用程序菜单"/>
<str id="ShortcutPanel.location.startMenu" txt="开始菜单"/>
<str id="ShortcutPanel.location.startup" txt="启动程序组"/>
<str id="UserInputPanel.error.caption" txt="录入问题"/>
<str id="UserInputPanel.search.autodetect" txt="自动检测"/>
<!-- more descriptive error message would be cool, like specifying what file we looked for -->
<str id="UserInputPanel.search.autodetect.failed.message" txt="自动检测失败."/>
<str id="UserInputPanel.search.autodetect.failed.caption" txt="自动检测失败."/>
<str id="UserInputPanel.search.autodetect.tooltip" txt="在给定路径中检查文件或目录."/>
<str id="UserInputPanel.search.location" txt="输入{0}的路径."/>
<str id="UserInputPanel.search.location.checkedfile" txt="The existence of {0} is checked."/>
<str id="UserInputPanel.search.browse" txt="浏览..."/>
<str id="UserInputPanel.search.wrongselection.message" txt="你选择的文件或目录不存在或者不正确."/>
<str id="UserInputPanel.search.wrongselection.caption" txt="无效选项."/>
<str id="CompilePanel.heading" txt="编译"/>
<str id="CompilePanel.tip" txt="任务编译进程:"/>
<str id="CompilePanel.browse" txt="浏览..."/>
<str id="CompilePanel.browse.approve" txt="作为编译器使用"/>
<str id="CompilePanel.start" txt="开始"/>
<str id="CompilePanel.progress.initial" txt="[按开始按钮]"/>
<str id="CompilePanel.progress.finished" txt="[完成]"/>
<str id="CompilePanel.progress.overall" txt="Overall compilation progress:"/>
<str id="CompilePanel.error" txt="编译失败"/>
<str id="CompilePanel.error.reconfigure" txt="重新设置"/>
<str id="CompilePanel.error.ignore" txt="忽略"/>
<str id="CompilePanel.error.abort" txt="终止"/>
<str id="CompilePanel.error.seebelow" txt="以下查看出错命令和相关输出."/>
<str id="CompilePanel.error.nofiles" txt="查询编译文件时出现错误."/>
<str id="CompilePanel.error.compilernotfound" txt="编译器不能运行."/>
<str id="CompilePanel.error.invalidarguments" txt="编译器不能处理提供的参数."/>
<str id="CompilePanel.error.noclassfile" txt="编译器没有为源代码文件生成相关类文件 "/>
<str id="CompilePanel.choose_compiler" txt="使用的编译器:"/>
<str id="CompilePanel.additional_arguments" txt="额外的编译器参数:"/>
<str id="ProcessPanel.heading" txt="处理中"/>
<!-- Add your own panels specific strings here if you need -->
</izpack:langpack>
+4
View File
@@ -40,6 +40,8 @@
in override.properties to ensure that Android will build correcly; fix any issues.
Ensure that JAVA_HOME is unset.
- Verify CI is passing on both Gitlab and Github
## A day or two before
@@ -67,6 +69,8 @@
5. Update and check in blocklist-tor.txt with `maketorblocklist.sh`
6. Verify CI is passing on both Gitlab and Github
## On release day
@@ -0,0 +1,449 @@
package net.i2p.util;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import net.i2p.I2PAppContext;
import net.i2p.util.ObjectCounterUnsafe;
/**
* Output translation stats by loading ResourceBundles from jars and wars,
* in html or text format.
*
* Bundles only, does not support external resources (html files, man pages,
* Debian po files) or the gettext properties files.
*
* This is run at build time, so output is not tagged or translated.
*
* @since 0.9.64
*/
public class TranslationStatus {
private final I2PAppContext _context;
private final boolean _html;
private final StringBuilder buf, buf2;
private final List<String> langs;
private final Set<Locale> foundLangs;
private final ObjectCounterUnsafe<Locale> counts;
private final ObjectCounterUnsafe<Locale> bundles;
private static final String[] JARS = { "desktopgui.jar", "i2p.jar",
"i2psnark.war", "i2ptunnel.jar", "i2ptunnel.war",
"mstreaming.jar", "router.jar", "routerconsole.jar",
"susidns.war", "susimail.war" };
// Java lang codes, see notes below
private static final String[] LANGS = { "ar", "az", "bg", "ca", "cs", "da", "de", "el", "es", "es_AR",
"et", "fa", "fi", "fr", "gl", "hi", "hr", "hu", "in", "it", "iw",
"ja", "ko", "ku", "mg", "nb", "nl", "nn", "pl", "pt", "pt_BR",
"ro", "ru", "sk", "sl", "sq", "sr", "sv", "tk", "tr", "uk", "vi",
"zh", "zh_TW" };
private static final String[] FILES = {
"core/java/src/gnu/getopt/MessagesBundle.properties",
"apps/routerconsole/resources/docs/readme.html", // no country variants supported
"installer/resources/eepsite/docroot/help/index.html",
"installer/resources/locale-man/man.po", // non-Java
"installer/resources/locale/po/messages.po", // non-Java
"debian/po/.po" }; // non-Java
public TranslationStatus(I2PAppContext ctx, boolean html) {
_context = ctx;
_html = html;
buf = new StringBuilder(65536);
buf2 = new StringBuilder(4096);
langs = Arrays.asList(LANGS);
counts = new ObjectCounterUnsafe<Locale>();
bundles = new ObjectCounterUnsafe<Locale>();
foundLangs = new HashSet<Locale>(64);
}
/*
only useful if we bundle this at runtime
public String getStatus() throws IOException {
File base = _context.getBaseDir();
File jars = new File(base, "lib");
File wars = new File(base, "webapps");
File[] files = new File[JARS.length];
for (int i = 0; i < JARS.length; i++) {
String f = JARS[i];
files[i] = new File(f.endsWith(".jar") ? jars : wars, f);
}
return getStatus(files);
}
*/
public String getStatus(File[] files) throws IOException {
buf.setLength(0);
buf2.setLength(0);
List<String> classes = new ArrayList<String>(64);
int grandtot = 0;
int resources = 0;
// pass 1: for each file
for (int i = 0; i < files.length; i++) {
// pass 1A: collect the class names in the file
ZipFile zip = null;
try {
zip = new ZipFile(files[i]);
Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
String name = entry.getName();
if (name.contains("messages_") && !name.contains("$")) {
if (name.startsWith("WEB-INF/classes/"))
name = name.substring(16);
classes.add(name);
}
}
Collections.sort(classes);
} catch (IOException ioe) {
ioe.printStackTrace();
continue;
} finally {
if (zip != null) try { zip.close(); } catch (IOException e) {}
}
if (classes.isEmpty()) {
System.err.println("No translations found in " + files[i]);
continue;
}
// pass 1B: setup a classloader, load each class, calculate max strings
// note that to be accurate this requires, for each resource, at least one translation to be at 100%
// this is mostly true or close enough. To do it right would require parsing the English po file,
// since we don't compile it.
URL url;
if (files[i].getName().endsWith(".jar")) {
url = files[i].toURI().toURL();
} else if (files[i].getName().endsWith(".war")) {
try {
url = (new URI("jar:file:" + files[i] + "!/WEB-INF/classes/")).toURL();
} catch (URISyntaxException use) { continue; }
} else {
System.err.println("Not a jar/war file: " + files[i]);
continue;
}
URL[] urls = new URL[] { url };
URLClassLoader cl = new URLClassLoader(urls);
String pclz = "";
int max = 0;
List<ResourceBundle> buns = new ArrayList<ResourceBundle>(64);
for (String name : classes) {
name = name.substring(0, name.length() - 6); // .class
int c = name.indexOf('_');
String clz = name.substring(0, c).replace("/", ".");
if (!clz.equals(pclz)) {
// pass 1C: output a table for the resource
// output goes here, we have to make two passes to find the max
// number of entries to generate a true %
if (!buns.isEmpty()) {
report(pclz, max, buns);
resources++;
}
grandtot += max;
pclz = clz;
max = 0;
buns.clear();
}
String s = name.substring(c + 1);
String lang;
String country;
Locale loc;
c = s.indexOf("_");
if (c < 0) {
lang = s;
country = null;
loc = new Locale(lang);
} else {
lang = s.substring(0, c);
country = s.substring(c + 1);
loc = new Locale(lang, country);
}
foundLangs.add(loc);
ResourceBundle bun;
try {
bun = ResourceBundle.getBundle(clz, loc, cl);
} catch (Exception e) {
System.err.println("FAILED loading class " + clz + " lang " + lang + " country " + country);
continue;
}
// in this pass we just calculate the max strings
buns.add(bun);
Set<String> keys = bun.keySet();
int tot = keys.size() - 1; // exclude header
if (tot > max)
max = tot;
}
if (!buns.isEmpty()) {
report(pclz, max, buns);
grandtot += max;
resources++;
}
classes.clear();
}
nl();
// pass 2: resources not in jars/wars
resources += nonCompiledStatus();
nl();
// pass 3: output summary table
// from here down to buf2 so we can output it first
String h = "Translation Summary (" + resources + " resources, " + langs.size() + " languages, " + grandtot + " strings)";
if (_html) {
buf2.append("<h2>" + h + "</h2>\n");
buf2.append("<p>Note: % translated includes compiled resources only</p>\n");
} else {
buf2.append(h);
buf2.append("\n\nNote: % translated includes compiled resources only\n\n");
}
if (_html) {
buf2.append("<table class=\"debug_tx_total\"><tr><th>Language<th>Language Code<th>% Translated<th>Missing Resources\n");
} else {
buf2.append("Code\t %TX\tMissing\tLanguage");
nl2();
buf2.append("----\t------\t--------\t-------");
nl2();
}
List<Locale> sorted = counts.sortedObjects();
for (Locale loc : sorted) {
String s = loc.getLanguage();
String lang = loc.getDisplayLanguage();
String country = loc.getCountry();
if (country.length() > 0) {
s += '_' + country;
country = '(' + loc.getDisplayCountry() + ')';
}
if (_html)
buf2.append(String.format(Locale.US, "<tr><td>%s %s<td>%s<td>%5.1f%%<td>%d\n", lang, country, s, 100f * counts.count(loc) / grandtot, resources - bundles.count(loc)));
else
buf2.append(String.format("%s\t%5.1f%%\t%s %s\n", s, 100f * counts.count(loc) / grandtot, resources - bundles.count(loc), lang, country));
}
if (_html)
buf2.append("</table>");
nl2();
nl2();
if (_html)
buf2.append("<h2>Compiled Resources</h2>\n");
else
buf2.append("Compiled Resources\n\n");
String rv = buf2.toString() + buf.toString();
buf.setLength(0);
buf2.setLength(0);
return rv;
}
private void report(String clz, int max, List<ResourceBundle> buns) {
nl();
if (clz.endsWith(".messages"))
clz = clz.substring(0, clz.length() - 9);
if (_html)
buf.append("<h3>Translations for " + clz + " (" + max + " strings, " + buns.size() + " translations)</h3>");
else
buf.append("\nTranslations for " + clz + " (" + max + " strings, " + buns.size() + " translations)\n");
nl();
if (_html) {
buf.append("<table class=\"debug_tx_resource\"><tr><th>Language <th>Language Code<th>Translated<th>% Translated");
} else {
buf.append("Code\t TX\t %TX\tLanguage");
nl();
buf.append("----\t----\t------\t--------");
nl();
}
Set<String> missing = new TreeSet<String>(langs);
for (ResourceBundle bun : buns) {
//int not = 0;
//int same = 0;
//int tx = 0;
Set<String> keys = bun.keySet();
int tot = Math.max(0, keys.size() - 1); // exclude header
/*
for (String k : keys) {
try {
String v = bun.getString(k);
if (v.length() == 0)
not++;
else if (v.equals(k))
same++;
else
tx++;
} catch (MissingResourceException e) {
not++;
}
}
*/
Locale loc = bun.getLocale();
String lang = loc.getLanguage();
String country = loc.getCountry();
String dlang = loc.getDisplayLanguage();
if (country.length() > 0) {
lang += '_' + country;
country = '(' + loc.getDisplayCountry() + ')';
}
missing.remove(lang);
counts.add(loc, tot);
bundles.increment(loc);
if (_html)
buf.append(String.format(Locale.US, "<tr><td>%s %s<td>%s<td>%4d<td>%5.1f%%\n", dlang, country, lang, tot, 100f * tot / max));
else
buf.append(String.format("%s\t%4d\t%5.1f%%\t%s %s\n", lang, tot, 100f * tot / max, dlang, country));
}
if (!missing.isEmpty()) {
if (_html)
buf.append("<tr><td class=\"debug_tx_center\" colspan=\"4\"><b>Not Translated</b>\n");
else
buf.append("Not translated:\n");
for (String s : missing) {
String lang;
String country;
Locale loc;
int c = s.indexOf("_");
if (c < 0) {
lang = s;
country = "";
loc = new Locale(lang);
} else {
lang = s.substring(0, c);
country = s.substring(c + 1);
loc = new Locale(lang, country);
country = " (" + loc.getDisplayCountry() + ')';
}
String dlang = loc.getDisplayLanguage();
if (_html)
buf.append("<tr><td>").append(dlang).append(country).append("<td>").append(s).append("<td>--<td>--\n");
else
buf.append(s).append("\t--\t--\t").append(dlang).append(country).append('\n');
}
}
if (_html)
buf.append("</table>");
nl();
}
private int nonCompiledStatus() {
int rv = 0;
if (_html) {
buf.append("<h2>Other Resources</h2>\n");
} else {
buf.append("\nOther Resources\n\n");
}
for (String file : FILES) {
boolean nonJava = file.startsWith("debian/po/") ||
file.startsWith("installer/resources/locale-man/") ||
file.startsWith("installer/resources/locale/po/");
boolean noCountries = file.startsWith("apps/routerconsole/resources/docs/");
int dot = file.lastIndexOf(".");
int slash = file.lastIndexOf("/");
String pfx = file.substring(slash + 1, dot);
String sfx = file.substring(dot);
String sdir = file.substring(0, slash);
// we assume we're in build/
File dir = new File("..", sdir);
if (!dir.exists())
continue;
rv++;
if (_html) {
buf.append("<h3>Translations for " + file + "</h3>\n");
buf.append("<table class=\"debug_tx_file\"><tr><th>Language <th>Language Code<th>Translated?");
} else {
buf.append("\nTranslations for " + file + "\n");
buf.append("Code\tTX\tLanguage\n");
buf.append("----\t--\t--------\n");
}
for (String lg : LANGS) {
String njlg = lg;
if (nonJava) {
// non-java (debian, installer, man) undo conversion
if (lg.equals("in"))
njlg = "id";
if (lg.equals("iw"))
njlg = "he";
}
String sf;
if (pfx.length() > 0)
sf = pfx + '_' + njlg + sfx;
else
sf = njlg + sfx;
File f = new File(dir, sf);
boolean ok = f.exists();
String lang;
String country;
Locale loc;
int c = lg.indexOf("_");
if (c < 0) {
lang = lg;
country = "";
loc = new Locale(lang);
} else {
lang = lg.substring(0, c);
country = lg.substring(c + 1);
loc = new Locale(lang, country);
country = " (" + loc.getDisplayCountry() + ')';
}
String dlang = loc.getDisplayLanguage();
String sok = (noCountries && c >= 0) ? "n/a" : (ok ? (_html ? "&#x2714;" : "yes") : (_html ? "--" : "no"));
if (_html)
buf.append("<tr><td>").append(dlang).append(country).append("<td>").append(lg).append("<td>").append(sok).append("\n");
else
buf.append(lg).append('\t').append(sok).append('\t').append(dlang).append(country).append("\n");
if (ok || (noCountries && c >= 0))
bundles.increment(loc);
if (ok)
foundLangs.add(loc);
}
if (_html)
buf.append("</table>");
}
return rv;
}
private void nl() {
buf.append(_html ? "<br>\n" : "\n");
}
private void nl2() {
buf2.append(_html ? "<br>\n" : "\n");
}
public static void main(String[] args) throws IOException {
boolean html = false;
if (args.length > 0 && args[0].equals("-h")) {
html = true;
args = Arrays.copyOfRange(args, 1, args.length);
}
if (args.length == 0)
args = JARS;
File[] files = new File[args.length];
for (int i = 0; i < args.length; i++) {
String f = JARS[i];
files[i] = new File(f);
}
TranslationStatus ts = new TranslationStatus(I2PAppContext.getGlobalContext(), html);
System.out.print(ts.getStatus(files));
}
}
@@ -20,7 +20,7 @@ public class RouterVersion {
public final static String VERSION = CoreVersion.VERSION;
/** for example: "beta", "alpha", "rc" */
public final static String QUALIFIER = "";
public final static long BUILD = 0;
public final static long BUILD = 1;
/** for example "-test" */
public final static String EXTRA = "";
public final static String FULL_VERSION = VERSION + "-" + BUILD + QUALIFIER + EXTRA;