*/
public final class SprintfCommand implements Translatable {
- private final String text;
+ /**
+ * The pattern to fill. Containing placeholders of pattern
+ * {@link #placeholder}. This is the string that will be translated.
+ */
+ private final String pattern;
- private final String[] store;
+ /**
+ * A regex that matches the replacement patterns like "{0}" or "{1}".
+ */
+ private static final Pattern placeholder = Pattern.compile("\\{([0-9]+)\\}");
+
+ /**
+ * The values describing what to put into the {@link #placeholder}s of
+ * {@link #pattern}.
+ */
+ private final String[] replacements;
/**
- * Creates a new SprintfCommand based on its pre-parsed contents.
+ * Regex for detecting processing instructions in a in-template
+ * SprintfCommand.
+ */
+ private static final Pattern processingInstruction = Pattern.compile("(?:(\\$!?\\{[a-zA-Z0-9_-]+)\\})|(?:(!'[^{}'\\$]*)')|(?:(!\\([^{})\\$]*)\\))");
+
+ /**
+ * Creates a new SprintfCommand based on its pre-parsed contents. This is
+ * the variant that the data is stored internally in this class. So the
+ * <code>pattern</code> has numbers as placeholders and the replacement list
+ * contains the instructions on what to put in there (without closing
+ * brackets, etc.).
*
- * @param text
+ * @param pattern
* a string with <code>{0},{1},..</code> as placeholders.
- * @param store
- * the data to put into the placeholders: ${var}, $!{var},
- * !'plain', !(/link).
+ * @param replacements
+ * instructions for what data to put into the placeholders:
+ * <code>${var</code>, <code>$!{var</code>, <code>!'plain</code>,
+ * <code>!(/link</code>.
*/
- public SprintfCommand(String text, List<String> store) {
- this.text = text;
- this.store = store.toArray(new String[store.size()]);
+ public SprintfCommand(String pattern, List<String> replacements) {
+ this.pattern = pattern;
+ this.replacements = replacements.toArray(new String[replacements.size()]);
}
- private static final String VARIABLE = "\\$!?\\{[a-zA-Z0-9_-]+\\}";
-
- private static final Pattern processingInstruction = Pattern.compile("(" + VARIABLE + ")|(?:(!'[^{}'\\$]*)')|(?:(!\\([^{})\\$]*)\\))");
-
/**
- * Creates a new SprintfCommand that is parsed as from template source.
+ * Creates a new SprintfCommand that is parsed as from template source. This
+ * version is internally used to create {@link SprintfCommand}s from the
+ * literals specified in {@link Template}s.
*
* @param content
* the part from the template that is to be parsed.
*/
protected SprintfCommand(String content) {
- StringBuffer raw = new StringBuffer();
- List<String> var = new LinkedList<String>();
+ StringBuffer pattern = new StringBuffer();
+ List<String> replacements = new LinkedList<String>();
int counter = 0;
Matcher m = processingInstruction.matcher(content);
int last = 0;
while (m.find()) {
- raw.append(content.substring(last, m.start()));
+ pattern.append(content.substring(last, m.start()));
String group = null;
if ((group = m.group(1)) != null) {
- var.add(group);
+ replacements.add(group);
} else if ((group = m.group(2)) != null) {
- var.add(group);
+ replacements.add(group);
} else if ((group = m.group(3)) != null) {
- var.add(group);
+ replacements.add(group);
} else {
throw new Error("Regex is broken??");
}
last = m.end();
- raw.append("{" + (counter++) + "}");
+ pattern.append("{" + (counter++) + "}");
}
- raw.append(content.substring(last));
- text = raw.toString();
- store = var.toArray(new String[var.size()]);
+ pattern.append(content.substring(last));
+ this.pattern = pattern.toString();
+ this.replacements = replacements.toArray(new String[replacements.size()]);
}
- private static final Pattern replacant = Pattern.compile("\\{([0-9]+)\\}");
-
@Override
- public void output(PrintWriter out, Language l, Map<String, Object> vars) {
- String parts = l.getTranslation(text);
- Matcher m = replacant.matcher(parts);
+ public void output(PrintWriter out, Language l, Map<String, Object> externalVariables) {
+ String parts = l.getTranslation(pattern);
+ Matcher m = placeholder.matcher(parts);
int pos = 0;
while (m.find()) {
- out.print(escape(vars, parts.substring(pos, m.start())));
- String var = store[Integer.parseInt(m.group(1))];
- if (var.startsWith("$!")) {
- Template.outputVar(out, l, vars, var.substring(3, var.length() - 1), true);
- } else if (var.startsWith("!'")) {
- out.print(var.substring(2));
- } else if (var.startsWith("!(")) {
- String host = (String) vars.get(Gigi.LINK_HOST);
+ out.print(escape(externalVariables, parts.substring(pos, m.start())));
+ String replacement = replacements[Integer.parseInt(m.group(1))];
+ if (replacement.startsWith("$!")) {
+ Template.outputVar(out, l, externalVariables, replacement.substring(3), true);
+ } else if (replacement.startsWith("!'")) {
+ out.print(replacement.substring(2));
+ } else if (replacement.startsWith("!(")) {
+ String host = (String) externalVariables.get(Gigi.LINK_HOST);
if (host == null) {
throw new Error("Unconfigured link-host while interpreting link-syntax.");
}
- if (var.charAt(2) != '/') {
+ if (replacement.charAt(2) != '/') {
throw new Error("Need an absolute link for the link service.");
}
- String link = "//" + host + var.substring(2);
+ String link = "//" + host + replacement.substring(2);
out.print("<a href='" + HTMLEncoder.encodeHTML(link) + "'>");
- } else if (var.startsWith("$")) {
- Template.outputVar(out, l, vars, var.substring(2, var.length() - 1), false);
+ } else if (replacement.startsWith("$")) {
+ Template.outputVar(out, l, externalVariables, replacement.substring(2), false);
} else {
throw new Error("Processing error in template.");
}
pos = m.end();
}
- out.print(escape(vars, parts.substring(pos)));
+ out.print(escape(externalVariables, parts.substring(pos)));
}
private String escape(Map<String, Object> vars, String target) {
@Override
public void addTranslations(Collection<String> s) {
- s.add(text);
+ s.add(pattern);
}
/**
* the message (to be translated) with <code>{0},{1},...</code>
* as placeholders.
* @param vars
- * the variables to put into the placeholders.
+ * the contents of the variables to put into the placeholders.
* @return the constructed {@link Outputable}.
*/
public static Outputable createSimple(String msg, Object... vars) {
String[] store = new String[vars.length];
for (int i = 0; i < vars.length; i++) {
scope.put("autoVar" + i, vars[i]);
- store[i] = "${autoVar" + i + "}";
+ store[i] = "${autoVar" + i;
}
return new Scope(new SprintfCommand(msg, Arrays.asList(store)), scope);
}