/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.clients.http;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import freenet.client.HighLevelSimpleClient;
import freenet.l10n.BaseL10n;
import freenet.l10n.NodeL10n;
import freenet.l10n.PluginL10n;
import freenet.node.NodeClientCore;
import freenet.pluginmanager.FredPluginBaseL10n;
import freenet.pluginmanager.PluginInfoWrapper;
import freenet.support.HTMLNode;
import freenet.support.MultiValueTable;
import freenet.support.SimpleFieldSet;
import freenet.support.SimpleFieldSet.KeyIterator;
import freenet.support.api.HTTPRequest;
import freenet.support.io.BucketTools;
/**
* A toadlet dedicated to translations ... and easing the work of translators
*
* @author Florent Daignière <nextgens@freenetproject.org>
* @author Artefact2
*/
public class TranslationToadlet extends Toadlet {
public static final String TOADLET_URL = "/translation/";
private final NodeClientCore core;
private BaseL10n base;
private String translatingFor;
TranslationToadlet(HighLevelSimpleClient client, NodeClientCore core) {
super(client);
this.core = core;
this.base = NodeL10n.getBase();
this.translatingFor = "Node";
}
public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx) throws ToadletContextClosedException, IOException {
if(!ctx.checkFullAccess(this))
return;
boolean showEverything = !request.isParameterSet("toTranslateOnly");
if (request.isParameterSet("getOverrideTranlationFile")) {
SimpleFieldSet sfs = this.base.getOverrideForCurrentLanguageTranslation();
if(sfs == null) {
super.sendErrorPage(ctx, 503 /* Service Unavailable */, "Service Unavailable", l10n("noCustomTranslations"));
return;
}
byte[] data = sfs.toOrderedString().getBytes("UTF-8");
MultiValueTable<String, String> head = new MultiValueTable<String, String>();
head.put("Content-Disposition", "attachment; filename=\"" + this.base.getL10nOverrideFileName(this.base.getSelectedLanguage()) + '"');
ctx.sendReplyHeaders(200, "Found", head, "text/plain; charset=utf-8", data.length);
ctx.writeData(data);
return;
} else if (request.isParameterSet("translation_updated")) {
String key = request.getParam("translation_updated");
PageNode page = ctx.getPageMaker().getPageNode(l10n("translationUpdatedTitle"), ctx);
HTMLNode pageNode = page.outer;
HTMLNode contentNode = page.content;
HTMLNode translationNode = contentNode.addChild("div", "class", "translation");
HTMLNode legendTable = translationNode.addChild("table", "class", "translation");
HTMLNode legendRow = legendTable.addChild("tr").addChild("b");
legendRow.addChild("td", "class", "translation-key", l10n("translationKeyLabel"));
legendRow.addChild("td", "class", "translation-key", l10n("originalVersionLabel"));
legendRow.addChild("td", "class", "translation-key", l10n("currentTranslationLabel"));
HTMLNode contentRow = legendTable.addChild("tr");
contentRow.addChild("td", "class", "translation-key",
key
);
contentRow.addChild("td", "class", "translation-orig",
this.base.getDefaultString(key)
);
contentRow.addChild("td", "class", "translation-new",
this.base.getString(key)
);
HTMLNode footer = translationNode.addChild("div", "class", "warning");
footer.addChild("a", "href", TOADLET_URL+"?getOverrideTranlationFile").addChild("#", l10n("downloadTranslationsFile"));
footer.addChild("%", " ");
footer.addChild("a", "href", TOADLET_URL+"?translate="+key+ (showEverything ? "" : "&toTranslateOnly")).addChild("#", l10n("reEdit"));
footer.addChild("%", " ");
footer.addChild("a", "href", TOADLET_URL + (showEverything ? "" : "?toTranslateOnly")).addChild("#", l10n("returnToTranslations"));
this.writeHTMLReply(ctx, 200, "OK", pageNode.generate());
return;
} else if (request.isParameterSet("translate")) {
boolean gotoNext = request.isParameterSet("gotoNext");
String key = request.getParam("translate");
PageNode page = ctx.getPageMaker().getPageNode(l10n("translationUpdateTitle"), ctx);
HTMLNode pageNode = page.outer;
HTMLNode contentNode = page.content;
HTMLNode translationNode = contentNode.addChild("div", "class", "translation");
HTMLNode updateForm = ctx.addFormChild(translationNode, TOADLET_URL, "trans_update");
HTMLNode legendTable = updateForm.addChild("table", "class", "translation");
HTMLNode legendRow = legendTable.addChild("tr");
legendRow.addChild("td", "class", "translation-key", l10n("translationKeyLabel"));
legendRow.addChild("td", "class", "translation-key", l10n("originalVersionLabel"));
legendRow.addChild("td", "class", "translation-key", l10n("currentTranslationLabel"));
HTMLNode contentRow = legendTable.addChild("tr");
contentRow.addChild("td", "class", "translation-key",
key
);
contentRow.addChild("td", "class", "translation-orig",
this.base.getDefaultString(key)
);
contentRow.addChild("td", "class", "translation-new").addChild(
"textarea",
new String[] { "name", "rows", "cols" },
new String[] { "trans", "20", "80" },
this.base.getString(key));
contentRow.addChild("input",
new String[] { "type", "name", "value" },
new String[] { "hidden", "key", key
});
updateForm.addChild("input",
new String[] { "type", "name", "value" },
new String[] { "submit", "translation_update", l10n("updateTranslationCommand")
});
updateForm.addChild("input", new String[] { "type", "name" , (gotoNext ? "checked" : "unchecked") } , new String[] { "checkbox", "gotoNext", ""}, l10n("gotoNext"));
if(!showEverything)
updateForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "hidden", "toTranslateOnly", key });
updateForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "submit", "cancel", NodeL10n.getBase().getString("Toadlet.cancel") });
this.writeHTMLReply(ctx, 200, "OK", pageNode.generate());
return;
} else if (request.isParameterSet("remove")) {
String key = request.getParam("remove");
PageNode page = ctx.getPageMaker().getPageNode(l10n("removeOverrideTitle"), ctx);
HTMLNode pageNode = page.outer;
HTMLNode contentNode = page.content;
HTMLNode content = ctx.getPageMaker().getInfobox("infobox-warning", l10n("removeOverrideWarningTitle"), contentNode, "translation-override", true);
content.addChild("p").addChild("#",
NodeL10n.getBase().getString("TranslationToadlet.confirmRemoveOverride", new String[] { "key", "value" },
new String[] { key, this.base.getString(key) }));
HTMLNode removeForm = ctx.addFormChild(content.addChild("p"), TOADLET_URL, "remove_confirmed");
if(!showEverything)
removeForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "hidden", "toTranslateOnly", key });
removeForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "hidden", "remove_confirm", key });
removeForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "submit", "remove_confirmed", l10n("remove") });
removeForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "submit", "cancel", NodeL10n.getBase().getString("Toadlet.cancel") });
this.writeHTMLReply(ctx, 200, "OK", pageNode.generate());
return;
}
PageNode page = ctx.getPageMaker().getPageNode(l10n("translationUpdateTitle"), ctx);
HTMLNode pageNode = page.outer;
HTMLNode contentNode = page.content;
final HTMLNode translatingForBox = ctx.getPageMaker().getInfobox(null, l10n("selectTranslation"), contentNode);
ArrayList<String> elementsToTranslate = new ArrayList<String>();
elementsToTranslate.add("Node");
for(PluginInfoWrapper pluginInfo : this.core.node.pluginManager.getPlugins()) {
if(!pluginInfo.isBaseL10nPlugin()) {
continue;
}
elementsToTranslate.add(pluginInfo.getPluginClassName());
}
final HTMLNode translatingForForm = ctx.addFormChild(translatingForBox, TOADLET_URL, "ChooseWhatToTranslate").addChild("p", l10n("showTranslationOf"));
final HTMLNode translatingForOption = translatingForForm.addChild("select", "name", "translating_for");
for(String element : elementsToTranslate) {
final HTMLNode option = translatingForOption.addChild("option", "name", element, element);
if(element.equals(this.translatingFor)) {
option.addAttribute("selected", "selected");
}
}
translatingForForm.addChild("input", "type", "submit");
HTMLNode translationNode = contentNode.addChild("div", "class", "translation");
HTMLNode translationHeaderNode = translationNode.addChild("p");
translationHeaderNode.addChild("#", l10n("contributingToLabelWithLang", "lang", this.base.getSelectedLanguage().fullName));
translationHeaderNode.addChild("a", "href", TOADLET_URL+"?getOverrideTranlationFile").addChild("#", l10n("downloadTranslationsFile"));
translationHeaderNode.addChild("#", " ");
if(showEverything)
translationHeaderNode.addChild("a", "href", TOADLET_URL+"?toTranslateOnly").addChild("#", l10n("hideAlreadyTranslated"));
else
translationHeaderNode.addChild("a", "href", TOADLET_URL).addChild("#", l10n("showEverything"));
HTMLNode legendTable = translationNode.addChild("table", "class", "translation");
HTMLNode legendRow = legendTable.addChild("tr");
legendRow.addChild("td", "class", "translation-key", l10n("translationKeyLabel"));
legendRow.addChild("td", "class", "translation-key", l10n("originalVersionLabel"));
legendRow.addChild("td", "class", "translation-key", l10n("currentTranslationLabel"));
KeyIterator it = this.base.getDefaultLanguageTranslation().keyIterator("");
while(it.hasNext()) {
String key = it.nextKey();
boolean isOverriden = this.base.isOverridden(key);
if(!showEverything && (isOverriden || (this.base.getString(key, true) != null))) continue;
HTMLNode contentRow = legendTable.addChild("tr");
contentRow.addChild("td", "class", "translation-key",
key
);
contentRow.addChild("td", "class", "translation-orig",
this.base.getDefaultString(key)
);
contentRow.addChild("td", "class", "translation-new").addChild(_setOrRemoveOverride(key, isOverriden, showEverything));
}
this.writeHTMLReply(ctx, 200, "OK", pageNode.generate());
}
public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) throws ToadletContextClosedException, IOException {
if(!ctx.checkFullAccess(this))
return;
if(request.isPartSet("translating_for")) {
final String translateFor = request.getPartAsStringFailsafe("translating_for", 255);
for(PluginInfoWrapper pluginInfo : this.core.node.pluginManager.getPlugins()) {
if(translateFor.equals(pluginInfo.getPluginClassName()) && pluginInfo.isBaseL10nPlugin()) {
FredPluginBaseL10n plugin = (FredPluginBaseL10n) pluginInfo.getPlugin();
this.translatingFor = translateFor;
this.base = new PluginL10n(plugin).getBase();
}
}
if(translateFor.equals("Node")) {
this.translatingFor = "Node";
this.base = NodeL10n.getBase();
}
redirectTo(ctx, TOADLET_URL);
return;
}
boolean toTranslateOnly = request.isPartSet("toTranslateOnly");
if(request.getPartAsStringFailsafe("translation_update", 32).length() > 0){
String key = request.getPartAsStringFailsafe("key", 256);
this.base.setOverride(key, new String(BucketTools.toByteArray(request.getPart("trans")), "UTF-8").trim());
if("on".equalsIgnoreCase(request.getPartAsStringFailsafe("gotoNext", 7))) {
KeyIterator it = base.getDefaultLanguageTranslation().keyIterator("");
while(it.hasNext()) {
String newKey = it.nextKey();
boolean isOverriden = this.base.isOverridden(newKey);
if(isOverriden || (this.base.getString(newKey, true) != null))
continue;
redirectTo(ctx, TOADLET_URL+"?gotoNext&translate="+newKey+ (toTranslateOnly ? "&toTranslateOnly" : ""));
return;
}
}
redirectTo(ctx, TOADLET_URL+"?translation_updated="+key+ (toTranslateOnly ? "&toTranslateOnly" : ""));
return;
} else if(request.getPartAsStringFailsafe("remove_confirmed", 32).length() > 0) {
String key = request.getPartAsStringFailsafe("remove_confirm", 256).trim();
this.base.setOverride(key, "");
redirectTo(ctx, TOADLET_URL+"?translation_updated="+key+ (toTranslateOnly ? "&toTranslateOnly" : ""));
return;
}else // Shouldn't reach that point!
redirectTo(ctx, "/");
}
private void redirectTo(ToadletContext ctx, String target) throws ToadletContextClosedException, IOException {
MultiValueTable<String, String> headers = new MultiValueTable<String, String>();
headers.put("Location", target);
ctx.sendReplyHeaders(302, "Found", headers, null, 0);
return;
}
private HTMLNode _setOrRemoveOverride(String key, boolean isOverriden, boolean showEverything) {
String value = this.base.getString(key, true);
HTMLNode translationField = new HTMLNode("span", "class", isOverriden ? "translate_d" : "translate_it");
if(value == null) {
translationField.addChild("#", this.base.getDefaultString(key));
translationField.addChild("a", "href", TranslationToadlet.TOADLET_URL+"?translate=" + key + (showEverything ? "" : "&toTranslateOnly")).addChild("small", l10n("bracketTranslateIt"));
} else {
translationField.addChild("#", this.base.getString(key));
translationField.addChild("a", "href", TranslationToadlet.TOADLET_URL+"?translate=" + key + (showEverything ? "" : "&toTranslateOnly")).addChild("small", l10n("bracketUpdateTranslation"));
if(isOverriden)
translationField.addChild("a", "href", TranslationToadlet.TOADLET_URL+"?remove=" + key + (showEverything ? "" : "&toTranslateOnly")).addChild("small", l10n("bracketRemoveOverride"));
}
return translationField;
}
private String l10n(String key) {
return NodeL10n.getBase().getString("TranslationToadlet."+key);
}
private String l10n(String key, String pattern, String value) {
return NodeL10n.getBase().getString("TranslationToadlet."+key, new String[] { pattern }, new String[] { value });
}
@Override
public String path() {
return TOADLET_URL;
}
}