Started localizing the Chat Messages and GUI

This commit is contained in:
CrushedPixel
2015-04-26 01:47:27 +02:00
parent e585e343e4
commit 79be2bd0d5
11 changed files with 123 additions and 107 deletions

View File

@@ -29,11 +29,12 @@ public class ReplayMod {
//TODO: Set ReplayHandler replaying to false when replay is exited
//TODO: Hide Titles upon hurrying
//TODO: Override Enchantment Rendering for items when replaying (to adjust speed of animation)
//TODO: Show the player whether he has already uploaded a replay
//TODO: Hinting to the b/v key feature
//TODO: Hinting to the b/v key feature (help page)
//TODO: Add "Miscellaneous" Replay Category
//XXX
//Known Bugs
@@ -108,7 +109,7 @@ public class ReplayMod {
//clean up replay_recordings folder
removeTmcprFiles();
/*
/*
boolean auth = false;
try {
auth = AuthenticationHandler.hasDonated(Minecraft.getMinecraft().getSession().getPlayerID());
@@ -121,7 +122,7 @@ public class ReplayMod {
JOptionPane.showMessageDialog(null, "It seems like you didn't donate, so you can't use the Replay Mod yet.");
FMLCommonHandler.instance().exitJava(0, false);
}
*/
*/
}
private void removeTmcprFiles() {

View File

@@ -1,13 +1,17 @@
package eu.crushedpixel.replaymod.api.client.holders;
import net.minecraft.client.resources.I18n;
public enum Category {
SURVIVAL(0), MINIGAME(1), BUILD(2);
SURVIVAL(0, "replaymod.category.survival"), MINIGAME(1, "replaymod.category.minigame"), BUILD(2, "replaymod.category.build");
private int id;
private String name;
Category(int id) {
Category(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
@@ -22,7 +26,7 @@ public enum Category {
}
public String toNiceString() {
return ("" + this).charAt(0) + ("" + this).substring(1).toLowerCase();
return I18n.format(this.name);
}
public Category next() {

View File

@@ -3,6 +3,7 @@ package eu.crushedpixel.replaymod.chat;
import eu.crushedpixel.replaymod.ReplayMod;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.IChatComponent;
import net.minecraftforge.fml.relauncher.Side;
@@ -56,7 +57,8 @@ public class ChatMessageHandler {
t.start();
}
public void addChatMessage(String message, ChatMessageType type) {
public void addLocalizedChatMessage(String message, ChatMessageType type, Object... options) {
message = I18n.format(message, options);
if(ReplayMod.replaySettings.isShowNotifications()) {
message = prefix + toColor(message, type);
ChatComponentText cct = new ChatComponentText(message);

View File

@@ -57,7 +57,7 @@ public class TickAndRenderListener {
mc.addScheduledTask(new Runnable() {
@Override
public void run() {
ReplayMod.chatMessageHandler.addChatMessage("Saving Thumbnail...", ChatMessageHandler.ChatMessageType.INFORMATION);
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.savingthumb", ChatMessageHandler.ChatMessageType.INFORMATION);
ReplayScreenshot.prepareScreenshot();
requestScreenshot = 2;
}

View File

@@ -7,6 +7,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.resources.I18n;
import org.lwjgl.input.Keyboard;
import java.awt.*;
@@ -25,8 +26,6 @@ public class GuiLoginPrompt extends GuiScreen {
private PasswordTextField password;
private GuiButton loginButton;
private GuiButton cancelButton;
private int lastMouseX, lastMouseY;
private float lastPartialTicks;
public GuiLoginPrompt(GuiScreen parent, GuiScreen successScreen) {
this.parent = parent;
@@ -45,12 +44,12 @@ public class GuiLoginPrompt extends GuiScreen {
password.setEnabled(true);
password.setFocused(false);
loginButton = new GuiButton(GuiConstants.LOGIN_OKAY_BUTTON, this.width / 2 - 150 - 2, 110, "Login");
loginButton = new GuiButton(GuiConstants.LOGIN_OKAY_BUTTON, this.width / 2 - 150 - 2, 110, I18n.format("replaymod.gui.login"));
loginButton.width = 150;
loginButton.enabled = false;
buttonList.add(loginButton);
cancelButton = new GuiButton(GuiConstants.LOGIN_CANCEL_BUTTON, this.width / 2 + 2, 110, "Cancel");
cancelButton = new GuiButton(GuiConstants.LOGIN_CANCEL_BUTTON, this.width / 2 + 2, 110, I18n.format("replaymod.gui.cancel"));
cancelButton.width = 150;
buttonList.add(cancelButton);
}
@@ -92,28 +91,24 @@ public class GuiLoginPrompt extends GuiScreen {
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
lastMouseX = mouseX;
lastMouseY = mouseY;
lastPartialTicks = partialTicks;
this.drawDefaultBackground();
drawCenteredString(fontRendererObj, "Login to ReplayMod.com", this.width / 2, 10, Color.WHITE.getRGB());
drawCenteredString(fontRendererObj, I18n.format("replaymod.gui.login.title"), this.width / 2, 10, Color.WHITE.getRGB());
drawString(fontRendererObj, "Username", this.width / 2 - 100, 37, Color.WHITE.getRGB());
drawString(fontRendererObj, I18n.format("replaymod.gui.username"), this.width / 2 - 100, 37, Color.WHITE.getRGB());
username.drawTextBox();
drawString(fontRendererObj, "Password", this.width / 2 - 100, 67, Color.WHITE.getRGB());
drawString(fontRendererObj, I18n.format("replaymod.gui.password"), this.width / 2 - 100, 67, Color.WHITE.getRGB());
password.drawTextBox();
switch(textState) {
case INVALID_LOGIN:
drawCenteredString(fontRendererObj, "Incorrect username or password.", this.width / 2, 92, Color.RED.getRGB());
drawCenteredString(fontRendererObj, I18n.format("replaymod.gui.login.incorrect"), this.width / 2, 92, Color.RED.getRGB());
break;
case LOGGING_IN:
drawCenteredString(fontRendererObj, "Logging in...", this.width / 2, 92, Color.WHITE.getRGB());
drawCenteredString(fontRendererObj, I18n.format("replaymod.gui.login.logging"), this.width / 2, 92, Color.WHITE.getRGB());
break;
case NO_CONNECTION:
drawCenteredString(fontRendererObj, "Could not connect to ReplayMod.com", this.width / 2, 92, Color.RED.getRGB());
drawCenteredString(fontRendererObj, I18n.format("replaymod.gui.login.connectionerror"), this.width / 2, 92, Color.RED.getRGB());
break;
}
super.drawScreen(mouseX, mouseY, partialTicks);

View File

@@ -33,8 +33,9 @@ public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
private SearchPagination myFilePagination;
public static GuiYesNo getYesNoGui(GuiYesNoCallback p_152129_0_, int p_152129_2_) {
String s1 = I18n.format("Do you really want to log out?", new Object[0]);
GuiYesNo guiyesno = new GuiYesNo(p_152129_0_, s1, "", "Logout", "Cancel", p_152129_2_);
String s1 = I18n.format("replaymod.gui.center.logoutcallback");
GuiYesNo guiyesno = new GuiYesNo(p_152129_0_, s1, "", I18n.format("replaymod.gui.logout"),
I18n.format("replaymod.gui.cancel"), p_152129_2_);
return guiyesno;
}
@@ -52,17 +53,17 @@ public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
//Top Button Bar
List<GuiButton> buttonBar = new ArrayList<GuiButton>();
GuiButton recentButton = new GuiButton(GuiConstants.CENTER_RECENT_BUTTON, 20, 30, "Newest Replays");
GuiButton recentButton = new GuiButton(GuiConstants.CENTER_RECENT_BUTTON, 20, 30, I18n.format("replaymod.gui.center.newest"));
buttonBar.add(recentButton);
GuiButton bestButton = new GuiButton(GuiConstants.CENTER_BEST_BUTTON, 20, 30, "Best Replays");
GuiButton bestButton = new GuiButton(GuiConstants.CENTER_BEST_BUTTON, 20, 30, I18n.format("replaymod.gui.center.best"));
buttonBar.add(bestButton);
GuiButton ownReplayButton = new GuiButton(GuiConstants.CENTER_MY_REPLAYS_BUTTON, 20, 30, "My Replays");
GuiButton ownReplayButton = new GuiButton(GuiConstants.CENTER_MY_REPLAYS_BUTTON, 20, 30, I18n.format("replaymod.gui.center.my"));
ownReplayButton.enabled = AuthenticationHandler.isAuthenticated();
buttonBar.add(ownReplayButton);
GuiButton searchButton = new GuiButton(GuiConstants.CENTER_SEARCH_BUTTON, 20, 30, "Search");
GuiButton searchButton = new GuiButton(GuiConstants.CENTER_SEARCH_BUTTON, 20, 30, I18n.format("replaymod.gui.center.search"));
buttonBar.add(searchButton);
int i = 0;
@@ -83,13 +84,13 @@ public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
//Bottom Button Bar (dat alliteration)
List<GuiButton> bottomBar = new ArrayList<GuiButton>();
GuiButton exitButton = new GuiButton(GuiConstants.CENTER_BACK_BUTTON, 20, 20, "Main Menu");
GuiButton exitButton = new GuiButton(GuiConstants.CENTER_BACK_BUTTON, 20, 20, I18n.format("replaymod.gui.mainmenu"));
bottomBar.add(exitButton);
GuiButton managerButton = new GuiButton(GuiConstants.CENTER_MANAGER_BUTTON, 20, 20, "Replay Viewer");
GuiButton managerButton = new GuiButton(GuiConstants.CENTER_MANAGER_BUTTON, 20, 20, I18n.format("replaymod.gui.replayviewer"));
bottomBar.add(managerButton);
GuiButton logoutButton = new GuiButton(GuiConstants.CENTER_LOGOUT_BUTTON, 20, 20, "Logout");
GuiButton logoutButton = new GuiButton(GuiConstants.CENTER_LOGOUT_BUTTON, 20, 20, I18n.format("replaymod.gui.logout"));
bottomBar.add(logoutButton);
i = 0;
@@ -150,7 +151,7 @@ public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
this.drawDefaultBackground();
this.drawCenteredString(fontRendererObj, "Replay Center", this.width / 2, 8, Color.WHITE.getRGB());
this.drawCenteredString(fontRendererObj, I18n.format("replaymod.gui.replaycenter"), this.width / 2, 8, Color.WHITE.getRGB());
if(currentList != null) {
currentList.drawScreen(mouseX, mouseY, partialTicks);

View File

@@ -18,10 +18,13 @@ import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.input.Keyboard;
import javax.imageio.ImageIO;
@@ -50,6 +53,8 @@ public class GuiUploadFile extends GuiScreen {
private Minecraft mc = Minecraft.getMinecraft();
private GuiReplayViewer parent;
private final Logger logger = LogManager.getLogger();
public GuiUploadFile(File file, GuiReplayViewer parent) {
this.parent = parent;
@@ -98,7 +103,7 @@ public class GuiUploadFile extends GuiScreen {
}
if(!correctFile) {
System.out.println("Invalid file provided to upload");
logger.error("Invalid file provided to upload");
mc.displayGuiScreen(parent); //TODO: Error message
replayFile = null;
return;
@@ -131,7 +136,7 @@ public class GuiUploadFile extends GuiScreen {
}
if(categoryButton == null) {
categoryButton = new GuiButton(GuiConstants.UPLOAD_CATEGORY_BUTTON, (this.width / 2) + 20 + 10 - 1, 80, "Category: " + category.toNiceString());
categoryButton = new GuiButton(GuiConstants.UPLOAD_CATEGORY_BUTTON, (this.width / 2) + 20 + 10 - 1, 80, I18n.format("replaymod.category")+": " + category.toNiceString());
categoryButton.width = Math.min(202, this.width - 20 - 260 + 2);
buttonList.add(categoryButton);
} else {
@@ -140,14 +145,14 @@ public class GuiUploadFile extends GuiScreen {
if(startUploadButton == null) {
List<GuiButton> bottomBar = new ArrayList<GuiButton>();
startUploadButton = new GuiButton(GuiConstants.UPLOAD_START_BUTTON, 0, 0, "Start Upload");
startUploadButton = new GuiButton(GuiConstants.UPLOAD_START_BUTTON, 0, 0, I18n.format("replaymod.gui.upload.start"));
bottomBar.add(startUploadButton);
cancelUploadButton = new GuiButton(GuiConstants.UPLOAD_CANCEL_BUTTON, 0, 0, "Cancel Upload");
cancelUploadButton = new GuiButton(GuiConstants.UPLOAD_CANCEL_BUTTON, 0, 0, I18n.format("replaymod.gui.upload.cancel"));
cancelUploadButton.enabled = false;
bottomBar.add(cancelUploadButton);
backButton = new GuiButton(GuiConstants.UPLOAD_BACK_BUTTON, 0, 0, "Back");
backButton = new GuiButton(GuiConstants.UPLOAD_BACK_BUTTON, 0, 0, I18n.format("replaymod.gui.back"));
bottomBar.add(backButton);
int i = 0;
@@ -208,7 +213,7 @@ public class GuiUploadFile extends GuiScreen {
if(tagPlaceholder == null) {
tagPlaceholder = new GuiTextField(GuiConstants.UPLOAD_TAG_PLACEHOLDER, fontRendererObj, (this.width / 2) + 20 + 10, 110, Math.min(200, this.width - 20 - 260), 20);
tagPlaceholder.setTextColor(Color.DARK_GRAY.getRGB());
tagPlaceholder.setText("Tags separated by comma");
tagPlaceholder.setText(I18n.format("replaymod.gui.upload.tagshint"));
} else {
tagPlaceholder.xPosition = (this.width / 2) + 20 + 10;
tagPlaceholder.width = Math.min(200, this.width - 20 - 260);
@@ -222,7 +227,7 @@ public class GuiUploadFile extends GuiScreen {
if(!button.enabled) return;
if(button.id == GuiConstants.UPLOAD_CATEGORY_BUTTON) {
category = category.next();
categoryButton.displayString = "Category: " + category.toNiceString();
categoryButton.displayString = I18n.format("replaymod.category")+": " + category.toNiceString();
} else if(button.id == GuiConstants.UPLOAD_BACK_BUTTON) {
mc.displayGuiScreen(parent);
} else if(button.id == GuiConstants.UPLOAD_START_BUTTON) {
@@ -261,13 +266,13 @@ public class GuiUploadFile extends GuiScreen {
this.drawDefaultBackground();
drawString(fontRendererObj, metaData.getServerName(), (this.width / 2) + 20 + 10, 50, Color.GRAY.getRGB());
drawString(fontRendererObj, "Duration: " + String.format("%02dm%02ds",
drawString(fontRendererObj, I18n.format("replaymod.gui.duration")+": " + String.format("%02dm%02ds",
TimeUnit.MILLISECONDS.toMinutes(metaData.getDuration()),
TimeUnit.MILLISECONDS.toSeconds(metaData.getDuration()) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(metaData.getDuration()))
), (this.width / 2) + 20 + 10, 65, Color.GRAY.getRGB());
drawCenteredString(fontRendererObj, "Upload File", this.width / 2, 5, Color.WHITE.getRGB());
drawCenteredString(fontRendererObj, I18n.format("replaymod.gui.upload.title"), this.width / 2, 5, Color.WHITE.getRGB());
//Draw thumbnail
if(thumb != null) {
@@ -364,7 +369,7 @@ public class GuiUploadFile extends GuiScreen {
backButton.enabled = false;
categoryButton.enabled = false;
fileTitleInput.setEnabled(false);
messageTextField.setText("Uploading...");
messageTextField.setText(I18n.format("replaymod.gui.upload.uploading"));
messageTextField.setTextColor(Color.WHITE.getRGB());
}
@@ -375,7 +380,7 @@ public class GuiUploadFile extends GuiScreen {
categoryButton.enabled = true;
fileTitleInput.setEnabled(true);
if(success) {
messageTextField.setText("File has been successfully uploaded");
messageTextField.setText(I18n.format("replaymod.gui.upload.success"));
messageTextField.setTextColor(Color.GREEN.getRGB());
} else {
messageTextField.setText(info);

View File

@@ -12,6 +12,8 @@ import net.minecraft.server.MinecraftServer;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent;
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientDisconnectionFromServerEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.net.InetSocketAddress;
@@ -36,6 +38,8 @@ public class ConnectionEventHandler {
private File currentFile;
private String fileName;
private static final Logger logger = LogManager.getLogger();
public static boolean isRecording() {
return isRecording;
}
@@ -43,7 +47,7 @@ public class ConnectionEventHandler {
public static void insertPacket(Packet packet) {
if(!isRecording || packetListener == null) {
String reason = isRecording ? " (recording)" : " (null)";
System.out.println("Invalid attempt to insert Packet!" + reason);
logger.error("Invalid attempt to insert Packet!" + reason);
return;
}
try {
@@ -55,20 +59,18 @@ public class ConnectionEventHandler {
@SubscribeEvent
public void onConnectedToServerEvent(ClientConnectedToServerEvent event) {
System.out.println("Connected to server");
ReplayMod.chatMessageHandler.initialize();
ReplayMod.recordingHandler.resetVars();
try {
if(event.isLocal) {
if(!ReplayMod.replaySettings.isEnableRecordingSingleplayer()) {
System.out.println("Singleplayer Recording is disabled");
logger.info("Singleplayer Recording is disabled");
return;
}
} else {
if(!ReplayMod.replaySettings.isEnableRecordingServer()) {
System.out.println("Multiplayer Recording is disabled");
logger.info("Multiplayer Recording is disabled");
return;
}
}
@@ -98,7 +100,7 @@ public class ConnectionEventHandler {
pipeline.addBefore(packetHandlerKey, "replay_recorder", insert = new PacketListener
(currentFile, fileName, worldName, System.currentTimeMillis(), event.isLocal));
ReplayMod.chatMessageHandler.addChatMessage("Recording started!", ChatMessageType.INFORMATION);
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.recordingstarted", ChatMessageType.INFORMATION);
isRecording = true;
final PacketListener listener = insert;
@@ -131,14 +133,13 @@ public class ConnectionEventHandler {
packetListener = listener;
} catch(Exception e) {
ReplayMod.chatMessageHandler.addChatMessage("Failed to start recording!", ChatMessageType.WARNING);
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.recordingfailed", ChatMessageType.WARNING);
e.printStackTrace();
}
}
@SubscribeEvent
public void onDisconnectedFromServerEvent(ClientDisconnectionFromServerEvent event) {
System.out.println("Disconnected from server");
isRecording = false;
packetListener = null;
ReplayMod.chatMessageHandler.stop();

View File

@@ -72,7 +72,7 @@ public class ReplayProcess {
ReplayMod.chatMessageHandler.initialize();
if(ReplayHandler.getPosKeyframeCount() < 2 && ReplayHandler.getTimeKeyframeCount() < 2) {
ReplayMod.chatMessageHandler.addChatMessage("At least 2 position or time keyframes required!", ChatMessageType.WARNING);
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.notenoughkeyframes", ChatMessageType.WARNING);
return;
}
@@ -99,7 +99,7 @@ public class ReplayProcess {
ReplayMod.replaySender.jumpToTime(ts);
}
ReplayMod.chatMessageHandler.addChatMessage("Replay started!", ChatMessageType.INFORMATION);
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.pathstarted", ChatMessageType.INFORMATION);
if(isVideoRecording()) {
MCTimerHandler.setTimerSpeed(1f);
@@ -109,9 +109,9 @@ public class ReplayProcess {
public static void stopReplayProcess(boolean finished) {
if(!ReplayHandler.isInPath()) return;
if(finished) ReplayMod.chatMessageHandler.addChatMessage("Replay finished!", ChatMessageType.INFORMATION);
if(finished) ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.pathfinished", ChatMessageType.INFORMATION);
else {
ReplayMod.chatMessageHandler.addChatMessage("Replay stopped!", ChatMessageType.INFORMATION);
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.pathinterrupted", ChatMessageType.INFORMATION);
if(isVideoRecording()) {
VideoWriter.abortRecording();
}

View File

@@ -88,56 +88,7 @@ public class ReplayScreenshot {
tempImage.delete();
/*
File outputFile = File.createTempFile(replayFile.getName(), null);
byte[] buf = new byte[1024];
ZipInputStream zin = new ZipInputStream(new FileInputStream(replayFile));
ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(outputFile));
//copying all of the old Zip Entries to the new file, unless it's a thumb
ZipEntry entry = zin.getNextEntry();
while (entry != null) {
String name = entry.getName();
if(!name.contains("thumb")) {
// Add ZIP entry to output stream.
zout.putNextEntry(new ZipEntry(name));
// Transfer bytes from the ZIP file to the output file
int len;
while ((len = zin.read(buf)) > 0) {
zout.write(buf, 0, len);
}
}
entry = zin.getNextEntry();
}
FileInputStream fis = new FileInputStream(tempImage);
zout.putNextEntry(new ZipEntry("thumb"));
int len;
//Add unique bytes to the end of the file
zout.write(uniqueBytes);
while ((len = fis.read(buf)) > 0) {
zout.write(buf, 0, len);
}
fis.close();
zin.close();
zout.close();
replayFile.delete();
outputFile.renameTo(replayFile);
tempImage.delete();
*/
ReplayMod.chatMessageHandler.addChatMessage("Thumbnail has been successfully saved", ChatMessageType.INFORMATION);
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.savedthumb", ChatMessageType.INFORMATION);
} catch(Exception e) {
e.printStackTrace();
} finally {
@@ -155,7 +106,7 @@ public class ReplayScreenshot {
mc.currentScreen = beforeScreen;
ReplayMod.replaySender.setReplaySpeed(beforeSpeed);
exception.printStackTrace();
ReplayMod.chatMessageHandler.addChatMessage("Thumbnail could not be saved", ChatMessageType.WARNING);
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.failedthumb", ChatMessageType.WARNING);
}
last_finish = System.currentTimeMillis();

View File

@@ -0,0 +1,56 @@
#All of the chat messages
replaymod.chat.recordingstarted=Recording started
replaymod.chat.recordingfailed=Failed to start recording
replaymod.chat.savingthumb=Saving Thumbnail...
replaymod.chat.savedthumb=Thumbnail has been successfully saved
replaymod.chat.failedthumb=Thumbnail could not be saved
#Chat messages displayed in Replay Viewer
replaymod.chat.notenoughkeyframes=At least 2 position or time keyframes required
replaymod.chat.pathstarted=Camera Path started
replaymod.chat.pathfinished=Camera Path finished
replaymod.chat.pathinterrupted=Camera Path canceled
#Replay Categories
replaymod.category=Category
replaymod.category.survival=Survival
replaymod.category.minigame=Minigame
replaymod.category.build=Build
replaymod.category.misc=Miscellaneous
#Common GUI-related strings
replaymod.gui.login=Login
replaymod.gui.logout=Logout
replaymod.gui.cancel=Cancel
replaymod.gui.username=Username
replaymod.gui.password=Password
replaymod.gui.back=Back
replaymod.gui.duration=Duration
replaymod.gui.mainmenu=Main Menu
replaymod.gui.replayviewer=Replay Viewer
replaymod.gui.replaycenter=Replay Center
replaymod.gui.replaysettings=Replay Settings
#Login GUI
replaymod.gui.login.title=Login to ReplayMod.com
replaymod.gui.login.logging=Logging in...
replaymod.gui.login.incorrect=Incorrect username or password
replaymod.gui.login.connectionerror=Could not connect to ReplayMod.com
#Replay Center GUI
replaymod.gui.center.logoutcallback=Do you really want to log out?
replaymod.gui.center.newest=Newest Replays
replaymod.gui.center.best=Best Replays
replaymod.gui.center.my=My Replays
replaymod.gui.center.search=Search Replays
#Upload GUI
replaymod.gui.upload.title=Upload File
replaymod.gui.upload.start=Start Upload
replaymod.gui.upload.cancel=Cancel Upload
replaymod.gui.upload.tagshint=Tags separated by comma
replaymod.gui.upload.uploading=Uploading...
replaymod.gui.upload.success=File has been successfully uploaded