Internationalization of the plugin.

* NEW: the plugin can now be translated.
This commit is contained in:
Amaury Carrade 2016-05-21 18:55:32 +02:00
parent 987efea203
commit 706ca5601d
No known key found for this signature in database
GPG Key ID: 73235214BDBB8752
21 changed files with 285 additions and 297 deletions

View File

@ -35,6 +35,7 @@ import fr.moribus.imageonmap.migration.V3Migrator;
import fr.moribus.imageonmap.ui.MapItemManager;
import fr.zcraft.zlib.components.commands.Commands;
import fr.zcraft.zlib.components.gui.Gui;
import fr.zcraft.zlib.components.i18n.I18n;
import fr.zcraft.zlib.core.ZPlugin;
import fr.zcraft.zlib.tools.PluginLogger;
@ -81,17 +82,19 @@ public final class ImageOnMap extends ZPlugin
}
catch(IOException ex)
{
PluginLogger.error("FATAL : " + ex.getMessage());
PluginLogger.error("FATAL: " + ex.getMessage());
this.setEnabled(false);
return;
}
saveDefaultConfig();
loadComponents(Gui.class, Commands.class, PluginConfiguration.class, ImageIOExecutor.class, ImageRendererExecutor.class);
loadComponents(I18n.class, Gui.class, Commands.class, PluginConfiguration.class, ImageIOExecutor.class, ImageRendererExecutor.class);
//Init all the things !
MetricsLite.startMetrics();
I18n.setPrimaryLocale(PluginConfiguration.LANG.get());
MapManager.init();
MapInitEvent.init();
MapItemManager.init();

View File

@ -21,11 +21,15 @@ package fr.moribus.imageonmap;
import fr.zcraft.zlib.components.configuration.Configuration;
import fr.zcraft.zlib.components.configuration.ConfigurationItem;
import java.util.Locale;
import static fr.zcraft.zlib.components.configuration.ConfigurationItem.item;
public final class PluginConfiguration extends Configuration
{
static public ConfigurationItem<Locale> LANG = item("lang", Locale.class);
static public ConfigurationItem<Boolean> COLLECT_DATA = item("collect-data", true);
static public ConfigurationItem<Integer> MAP_GLOBAL_LIMIT = item("map-global-limit", 0, "Limit-map-by-server");

View File

@ -21,6 +21,7 @@ import fr.moribus.imageonmap.map.ImageMap;
import fr.moribus.imageonmap.map.MapManager;
import fr.zcraft.zlib.components.commands.Command;
import fr.zcraft.zlib.components.commands.CommandException;
import fr.zcraft.zlib.components.i18n.I;
import org.bukkit.entity.Player;
import java.util.ArrayList;
@ -36,7 +37,7 @@ public abstract class IoMCommand extends Command
protected ImageMap getMapFromArgs(Player player, int index, boolean expand) throws CommandException
{
if(args.length <= index) throwInvalidArgument("You need to give a map name.");
if(args.length <= index) throwInvalidArgument(I.t("You need to give a map name."));
ImageMap map;
String mapName = args[index];
@ -53,7 +54,7 @@ public abstract class IoMCommand extends Command
map = MapManager.getMap(player.getUniqueId(), mapName);
if(map == null) error("This map does not exist.");
if(map == null) error(I.t("This map does not exist."));
return map;
}

View File

@ -22,10 +22,11 @@ import fr.moribus.imageonmap.commands.IoMCommand;
import fr.moribus.imageonmap.map.ImageMap;
import fr.zcraft.zlib.components.commands.CommandException;
import fr.zcraft.zlib.components.commands.CommandInfo;
import fr.zcraft.zlib.components.i18n.I;
import fr.zcraft.zlib.components.rawtext.RawText;
import org.bukkit.ChatColor;
import java.util.List;
import org.bukkit.ChatColor;
@CommandInfo (name = "delete", usageParameters = "[tool name]")
public class DeleteConfirmCommand extends IoMCommand
@ -34,22 +35,15 @@ public class DeleteConfirmCommand extends IoMCommand
protected void run() throws CommandException
{
ImageMap map = getMapFromArgs();
RawText hoverText = new RawText("This map will be deleted ")
.style(ChatColor.UNDERLINE)
.then("forever")
.style(ChatColor.RED, ChatColor.UNDERLINE, ChatColor.ITALIC, ChatColor.BOLD)
.then(" !")
.build();
RawText msg = new RawText("You are going to delete ")
RawText msg = new RawText(I.t("You are going to delete") + " ")
.then(map.getId())
.color(ChatColor.GOLD)
.then(". Are you sure ? ")
.then(". " + I.t("Are you sure ? "))
.color(ChatColor.WHITE)
.then("[Confirm]")
.then(I.t("[Confirm]"))
.color(ChatColor.GREEN)
.hover(hoverText)
.hover(new RawText(I.t("{red}This map will be deleted {bold}forever{red}!")))
.command(DeleteNoConfirmCommand.class, map.getId())
.build();

View File

@ -24,13 +24,14 @@ import fr.moribus.imageonmap.map.MapManager;
import fr.moribus.imageonmap.map.MapManagerException;
import fr.zcraft.zlib.components.commands.CommandException;
import fr.zcraft.zlib.components.commands.CommandInfo;
import fr.zcraft.zlib.components.i18n.I;
import fr.zcraft.zlib.tools.PluginLogger;
import org.bukkit.entity.Player;
import java.util.List;
@CommandInfo (name = "delete-noconfirm", usageParameters = "[map name]")
@CommandInfo (name = "delete-noconfirm", usageParameters = "[map name]")
public class DeleteNoConfirmCommand extends IoMCommand
{
@Override
@ -42,12 +43,12 @@ public class DeleteNoConfirmCommand extends IoMCommand
try
{
MapManager.deleteMap(map);
info("Map successfully deleted.");
info(I.t("Map successfully deleted."));
}
catch (MapManagerException ex)
{
PluginLogger.warning("A non-existent map was requested to be deleted", ex);
warning("This map does not exist.");
warning(I.t("This map does not exist."));
}
}
@ -59,4 +60,3 @@ public class DeleteNoConfirmCommand extends IoMCommand
return null;
}
}

View File

@ -21,6 +21,7 @@ package fr.moribus.imageonmap.commands.maptool;
import fr.moribus.imageonmap.commands.IoMCommand;
import fr.zcraft.zlib.components.commands.CommandException;
import fr.zcraft.zlib.components.commands.CommandInfo;
import fr.zcraft.zlib.components.i18n.I;
import org.bukkit.entity.Player;
import java.util.List;
@ -34,8 +35,8 @@ public class GetCommand extends IoMCommand
Player player = playerSender();
if(getMapFromArgs().give(player))
{
info("The requested map was too big to fit in your inventory.");
info("Use '/maptool getremaining' to get the remaining maps.");
info(I.t("The requested map was too big to fit in your inventory."));
info(I.t("Use '/maptool getremaining' to get the remaining maps."));
}
}

View File

@ -22,6 +22,7 @@ import fr.moribus.imageonmap.commands.IoMCommand;
import fr.moribus.imageonmap.ui.MapItemManager;
import fr.zcraft.zlib.components.commands.CommandException;
import fr.zcraft.zlib.components.commands.CommandInfo;
import fr.zcraft.zlib.components.i18n.I;
import org.bukkit.entity.Player;
@CommandInfo (name = "getremaining", aliases = {"getrest"})
@ -34,7 +35,7 @@ public class GetRemainingCommand extends IoMCommand
if(MapItemManager.getCacheSize(player) <= 0)
{
info("You have no remaining map.");
info(I.t("You have no remaining map."));
return;
}
@ -42,11 +43,11 @@ public class GetRemainingCommand extends IoMCommand
if(givenMaps == 0)
{
error("Your inventory is full ! Make some space before requesting the remaining maps.");
error(I.t("Your inventory is full ! Make some space before requesting the remaining maps."));
}
else
{
info("There are " + MapItemManager.getCacheSize(player) + " maps remaining.");
info(I.tn("There is {0} map remaining.", "There are {0} maps remaining.", MapItemManager.getCacheSize(player)));
}
}
}

View File

@ -23,6 +23,7 @@ import fr.moribus.imageonmap.map.ImageMap;
import fr.moribus.imageonmap.map.MapManager;
import fr.zcraft.zlib.components.commands.CommandException;
import fr.zcraft.zlib.components.commands.CommandInfo;
import fr.zcraft.zlib.components.i18n.I;
import org.bukkit.entity.Player;
import java.util.List;
@ -38,11 +39,11 @@ public class ListCommand extends IoMCommand
if(mapList.isEmpty())
{
info("No map found.");
info(I.t("No map found."));
return;
}
info(mapList.size() + " maps found.");
info(I.tn("{0} map found.", "{0} maps found.", mapList.size()));
String sMapList = mapList.get(0).getId();
for(int i = 1, c = mapList.size(); i < c; i++)

View File

@ -22,6 +22,7 @@ import fr.moribus.imageonmap.commands.IoMCommand;
import fr.moribus.imageonmap.migration.MigratorExecutor;
import fr.zcraft.zlib.components.commands.CommandException;
import fr.zcraft.zlib.components.commands.CommandInfo;
import fr.zcraft.zlib.components.i18n.I;
import org.bukkit.command.CommandSender;
@CommandInfo (name = "migrate")
@ -32,11 +33,11 @@ public class MigrateCommand extends IoMCommand
{
if(MigratorExecutor.isRunning())
{
error("A migration process is already running. Check console for details.");
error(I.t("A migration process is already running. Check console for details."));
}
else
{
info("Migration started. See console for details.");
info(I.t("Migration started. See console for details."));
MigratorExecutor.migrate();
}
}

View File

@ -23,6 +23,7 @@ import fr.moribus.imageonmap.image.ImageRendererExecutor;
import fr.moribus.imageonmap.map.ImageMap;
import fr.zcraft.zlib.components.commands.CommandException;
import fr.zcraft.zlib.components.commands.CommandInfo;
import fr.zcraft.zlib.components.i18n.I;
import fr.zcraft.zlib.components.worker.WorkerCallback;
import fr.zcraft.zlib.tools.PluginLogger;
import org.bukkit.entity.Player;
@ -40,7 +41,7 @@ public class NewCommand extends IoMCommand
boolean scaling = false;
URL url;
if(args.length < 1) throwInvalidArgument("You must give an URL to take the image from.");
if(args.length < 1) throwInvalidArgument(I.t("You must give an URL to take the image from."));
try
{
@ -48,7 +49,7 @@ public class NewCommand extends IoMCommand
}
catch(MalformedURLException ex)
{
throwInvalidArgument("Invalid URL.");
throwInvalidArgument(I.t("Invalid URL."));
return;
}
@ -57,25 +58,26 @@ public class NewCommand extends IoMCommand
if(args[1].equals("resize")) scaling = true;
}
info("Rendering ...");
info(I.t("Rendering..."));
ImageRendererExecutor.Render(url, scaling, player.getUniqueId(), new WorkerCallback<ImageMap>()
{
@Override
public void finished(ImageMap result)
{
player.sendMessage("§7Rendering finished !");
player.sendMessage(I.t("{cst}Rendering finished !"));
if(result.give(player))
{
info("The rendered map was too big to fit in your inventory.");
info("Use '/maptool getremaining' to get the remaining maps.");
info(I.t("The rendered map was too big to fit in your inventory."));
info(I.t("Use '/maptool getremaining' to get the remaining maps."));
}
}
@Override
public void errored(Throwable exception)
{
player.sendMessage("§cMap rendering failed : " + exception.getMessage());
PluginLogger.warning("Rendering from {0} failed : {1} : {2}",
player.sendMessage(I.t("{ce}Map rendering failed: {0}", exception.getMessage()));
PluginLogger.warning("Rendering from {0} failed: {1}: {2}",
player.getName(),
exception.getClass().getCanonicalName(),
exception.getMessage());

View File

@ -24,7 +24,9 @@ import fr.moribus.imageonmap.map.MapManagerException;
import fr.zcraft.zlib.components.gui.ActionGui;
import fr.zcraft.zlib.components.gui.Gui;
import fr.zcraft.zlib.components.gui.GuiAction;
import fr.zcraft.zlib.components.i18n.I;
import fr.zcraft.zlib.tools.PluginLogger;
import fr.zcraft.zlib.tools.items.ItemStackBuilder;
import org.bukkit.ChatColor;
import org.bukkit.DyeColor;
import org.bukkit.Material;
@ -96,26 +98,24 @@ public class ConfirmDeleteMapGui extends ActionGui
@Override
protected void onUpdate()
{
setTitle(mapToDelete.getName() + " » " + ChatColor.BLACK + "Confirm deletion");
/// The title of the map deletion GUI. {0}: map name.
setTitle(I.t("{0} » {black}Confirm deletion", mapToDelete.getName()));
setSize(6 * 9);
/* ** Item representation of the image being deleted ** */
ItemStack beingDeleted = new ItemStack(Material.EMPTY_MAP);
ItemMeta meta = beingDeleted.getItemMeta();
meta.setDisplayName(ChatColor.RED + "You're about to destroy this map...");
meta.setLore(Arrays.asList(
ChatColor.RED + "..." + ChatColor.ITALIC + "forever" + ChatColor.RED + ".",
"",
ChatColor.GRAY + "Name: " + ChatColor.WHITE + mapToDelete.getName(),
ChatColor.GRAY + "Map ID: " + ChatColor.WHITE + mapToDelete.getId(),
ChatColor.GRAY + "Maps inside: " + ChatColor.WHITE + mapToDelete.getMapsIDs().length
));
beingDeleted.setItemMeta(meta);
action("", 13, beingDeleted);
action("", 13, new ItemStackBuilder(Material.EMPTY_MAP)
/// The title of the map deletion item
.title(I.t("{red}You're about to destroy this map..."))
/// The end, in the lore, of a title starting with You're about to destroy this map....
.lore(I.t("{red}...{italic}forever{red}."))
.loreLine()
.lore(I.t("{gray}Name: {white}{0}",mapToDelete.getName()))
.lore(I.t("{gray}Map ID: {white}{0}", mapToDelete.getId()))
.lore(I.t("{grayMaps inside: {white}{0}", mapToDelete.getMapsIDs().length))
.hideAttributes()
);
/* ** Buttons ** */
@ -175,7 +175,7 @@ public class ConfirmDeleteMapGui extends ActionGui
try
{
MapManager.deleteMap(mapToDelete);
getPlayer().sendMessage(ChatColor.GRAY + "Map successfully deleted.");
getPlayer().sendMessage(I.t("{gray}Map successfully deleted."));
}
catch (MapManagerException ex)
{
@ -185,7 +185,7 @@ public class ConfirmDeleteMapGui extends ActionGui
// We try to open the map list GUI, if the map was deleted, before the details GUI
// (so the grandparent GUI)..
// (so the grandparent GUI).
if (getParent() != null && getParent().getParent() != null)
Gui.open(getPlayer(), getParent().getParent());
else

View File

@ -25,16 +25,12 @@ import fr.moribus.imageonmap.ui.MapItemManager;
import fr.zcraft.zlib.components.gui.ExplorerGui;
import fr.zcraft.zlib.components.gui.Gui;
import fr.zcraft.zlib.components.gui.GuiAction;
import fr.zcraft.zlib.components.gui.GuiUtils;
import fr.zcraft.zlib.components.gui.PromptGui;
import fr.zcraft.zlib.components.i18n.I;
import fr.zcraft.zlib.tools.Callback;
import org.bukkit.ChatColor;
import fr.zcraft.zlib.tools.items.ItemStackBuilder;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Arrays;
import java.util.Collections;
public class MapDetailGui extends ExplorerGui
@ -52,20 +48,14 @@ public class MapDetailGui extends ExplorerGui
Material partMaterial = Material.PAPER;
if((y % 2 == 0 && x % 2 == 0) || (y % 2 == 1 && x % 2 == 1))
partMaterial = Material.EMPTY_MAP;
ItemStack part = new ItemStack(partMaterial);
ItemMeta meta = part.getItemMeta();
meta.setDisplayName(ChatColor.GREEN + "Map part");
meta.setLore(Arrays.asList(
ChatColor.GRAY + "Column: " + ChatColor.WHITE + (y + 1),
ChatColor.GRAY + "Row: " + ChatColor.WHITE + (x + 1),
"",
ChatColor.GRAY + "» Click to get only this part"
));
part.setItemMeta(meta);
return part;
return new ItemStackBuilder(partMaterial)
.title(I.t("{green}Map part"))
.lore(I.t("{gray}Column: {white}{0}", y + 1))
.lore(I.t("{gray}Row: {white}{0}", x + 1))
.loreLine()
.lore(I.t("{gray}» {white}Click{gray} to get only this part"))
.item();
}
@Override
@ -80,7 +70,7 @@ public class MapDetailGui extends ExplorerGui
return MapItemManager.createMapItem((PosterMap)map, x, y);
}
throw new IllegalStateException("Unsupported map type : " + map.getType());
throw new IllegalStateException("Unsupported map type: " + map.getType());
}
@Override
@ -96,7 +86,8 @@ public class MapDetailGui extends ExplorerGui
@Override
protected void onUpdate()
{
setTitle("Your maps » " + ChatColor.BLACK + map.getName());
/// Title of the map details GUI
setTitle(I.t("Your maps » {black}{0}", map.getName()));
setKeepHorizontalScrollingSpace(true);
if(map instanceof PosterMap)
@ -105,18 +96,17 @@ public class MapDetailGui extends ExplorerGui
setData(null); // Fallback to the empty view item.
action("rename", getSize() - 7, GuiUtils.makeItem(Material.BOOK_AND_QUILL, ChatColor.BLUE + "Rename this image", Arrays.asList(
ChatColor.GRAY + "Click here to rename this image;",
ChatColor.GRAY + "this is used for your own organization."
)));
action("rename", getSize() - 7, new ItemStackBuilder(Material.BOOK_AND_QUILL)
.title(I.t("{blue}Rename this image"))
.longLore(I.t("{gray}Click here to rename this image; this is used for your own organization."))
);
action("delete", getSize() - 6, GuiUtils.makeItem(Material.BARRIER, ChatColor.RED + "Delete this image", Arrays.asList(
ChatColor.GRAY + "Deletes this map " + ChatColor.WHITE + "forever" + ChatColor.GRAY + ".",
ChatColor.GRAY + "This action cannot be undone!",
"",
ChatColor.GRAY + "You will be asked to confirm your",
ChatColor.GRAY + "choice if you click here."
)));
action("delete", getSize() - 6, new ItemStackBuilder(Material.BARRIER)
.title("{red}Delete this image")
.longLore(I.t("{gray}Deletes this map {white}forever{gray}. This action cannot be undone!"))
.loreLine()
.longLore(I.t("{gray}You will be asked to confirm your choice if you click here."))
);
// To keep the controls centered, the back button is shifted to the right when the
@ -126,9 +116,10 @@ public class MapDetailGui extends ExplorerGui
if(map instanceof PosterMap && ((PosterMap) map).getColumnCount() <= INVENTORY_ROW_SIZE)
backSlot++;
action("back", backSlot, GuiUtils.makeItem(Material.EMERALD, ChatColor.GREEN + "« Back", Collections.singletonList(
ChatColor.GRAY + "Go back to the list."
)));
action("back", backSlot, new ItemStackBuilder(Material.EMERALD)
.title(I.t("{green}« Back"))
.lore(I.t("{gray}Go back to the list."))
);
}
@ -142,12 +133,12 @@ public class MapDetailGui extends ExplorerGui
{
if (newName == null || newName.isEmpty())
{
getPlayer().sendMessage(ChatColor.RED + "Map names can't be empty.");
getPlayer().sendMessage(I.t("{ce}Map names can't be empty."));
return;
}
map.rename(newName);
getPlayer().sendMessage(ChatColor.GRAY + "Map successfully renamed.");
getPlayer().sendMessage(I.t("{cs}Map successfully renamed."));
}
}, map.getName(), this);
}

View File

@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.moribus.imageonmap.gui;
import fr.moribus.imageonmap.PluginConfiguration;
@ -27,153 +26,128 @@ import fr.moribus.imageonmap.ui.MapItemManager;
import fr.moribus.imageonmap.ui.SplatterMapManager;
import fr.zcraft.zlib.components.gui.ExplorerGui;
import fr.zcraft.zlib.components.gui.Gui;
import fr.zcraft.zlib.components.gui.GuiUtils;
import fr.zcraft.zlib.components.i18n.I;
import fr.zcraft.zlib.tools.items.ItemStackBuilder;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Locale;
public class MapListGui extends ExplorerGui<ImageMap>
{
private final NumberFormat bigNumbersFormatter = new DecimalFormat("###,###,###,###", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
@Override
protected ItemStack getViewItem(ImageMap map)
{
String mapDescription;
if (map instanceof SingleMap)
/// Displayed subtitle description of a single map on the list GUI
mapDescription = I.t("{white}Single map");
else
/// Displayed subtitle description of a poster map on the list GUI (columns × rows in english)
mapDescription = I.t("{white}Poster map ({0} × {1})", ((PosterMap) map).getColumnCount(), ((PosterMap) map).getRowCount());
return new ItemStackBuilder(Material.MAP)
/// Displayed title of a map on the list GUI
.title(I.t("{green}{bold}{0}", map.getName()))
@Override
protected ItemStack getViewItem(ImageMap map)
{
String mapDescription;
if (map instanceof SingleMap)
mapDescription = "Single map";
else
mapDescription = "Poster map (" + ((PosterMap) map).getColumnCount() + "×" + ((PosterMap) map).getRowCount() + ")";
.lore(mapDescription)
.loreLine()
/// Map ID displayed in the tooltip of a map on the list GUI
.lore(I.t("{gray}Map ID: {0}", map.getId()))
.loreLine()
.lore(I.t("{gray}» {white}Left-click{gray} to get this map"))
.lore(I.t("{gray}» {white}Right-click{gray} for details and options"))
ItemStack icon = GuiUtils.makeItem(Material.MAP, ChatColor.GREEN + "" + ChatColor.BOLD + map.getName(), Arrays.asList(
ChatColor.WHITE + mapDescription,
"",
ChatColor.GRAY + "Map ID: " + map.getId(),
"",
ChatColor.GRAY + "» Left-click to get this map",
ChatColor.GRAY + "» Right-click for details and options"
));
.item();
}
return GuiUtils.hideItemAttributes(icon);
}
@Override
protected ItemStack getEmptyViewItem()
{
return new ItemStackBuilder(Material.BARRIER)
.title(I.t("{red}You don't have any map."))
.longLore(I.t("{gray}Get started by creating a new one using {white}/tomap <URL> [resize]{gray}!"))
.item();
}
@Override
protected ItemStack getEmptyViewItem()
{
ItemStack empty = new ItemStack(Material.BARRIER);
ItemMeta meta = empty.getItemMeta();
@Override
protected void onRightClick(ImageMap data)
{
Gui.open(getPlayer(), new MapDetailGui(data), this);
}
meta.setDisplayName(ChatColor.RED + "You don't have any map.");
meta.setLore(Arrays.asList(
ChatColor.GRAY + "Get started by creating a new one",
ChatColor.GRAY + "using " + ChatColor.WHITE + "/tomap <URL> [resize]" + ChatColor.GRAY + "!"
));
@Override
protected ItemStack getPickedUpItem(ImageMap map)
{
if (map instanceof SingleMap)
{
return MapItemManager.createMapItem(map.getMapsIDs()[0], map.getName());
}
else if (map instanceof PosterMap)
{
return SplatterMapManager.makeSplatterMap((PosterMap) map);
}
empty.setItemMeta(meta);
return empty;
}
MapItemManager.give(getPlayer(), map);
return null;
}
@Override
protected void onRightClick(ImageMap data)
{
Gui.open(getPlayer(), new MapDetailGui(data), this);
}
@Override
protected void onUpdate()
{
ImageMap[] maps = MapManager.getMaps(getPlayer().getUniqueId());
setData(maps);
/// The maps list GUI title
setTitle(I.t("{black}Your maps {reset}({0})", maps.length));
@Override
protected ItemStack getPickedUpItem(ImageMap map)
{
if (map instanceof SingleMap)
{
return MapItemManager.createMapItem(map.getMapsIDs()[0], map.getName());
}
else if(map instanceof PosterMap)
{
return SplatterMapManager.makeSplatterMap((PosterMap) map);
}
MapItemManager.give(getPlayer(), map);
return null;
}
@Override
protected void onUpdate()
{
ImageMap[] maps = MapManager.getMaps(getPlayer().getUniqueId());
setData(maps);
setTitle(ChatColor.BLACK + "Your maps " + ChatColor.RESET + "(" + maps.length + ")");
setKeepHorizontalScrollingSpace(true);
setKeepHorizontalScrollingSpace(true);
/* ** Statistics ** */
int imagesCount = MapManager.getMapList(getPlayer().getUniqueId()).size();
int mapPartCount = MapManager.getMapPartCount(getPlayer().getUniqueId());
int imagesCount = MapManager.getMapList(getPlayer().getUniqueId()).size();
int mapPartCount = MapManager.getMapPartCount(getPlayer().getUniqueId());
int mapGlobalLimit = PluginConfiguration.MAP_GLOBAL_LIMIT.get();
int mapPersonalLimit = PluginConfiguration.MAP_PLAYER_LIMIT.get();
int mapGlobalLimit = PluginConfiguration.MAP_GLOBAL_LIMIT.get();
int mapPersonalLimit = PluginConfiguration.MAP_PLAYER_LIMIT.get();
int mapPartGloballyLeft = mapGlobalLimit - MapManager.getMapCount();
int mapPartPersonallyLeft = mapPersonalLimit - mapPartCount;
int mapPartGloballyLeft = mapGlobalLimit - MapManager.getMapCount();
int mapPartPersonallyLeft = mapPersonalLimit - mapPartCount;
int mapPartLeft;
if (mapGlobalLimit <= 0 && mapPersonalLimit <= 0)
mapPartLeft = -1;
else if (mapGlobalLimit <= 0)
mapPartLeft = mapPartPersonallyLeft;
else if (mapPersonalLimit <= 0)
mapPartLeft = mapPartGloballyLeft;
else
mapPartLeft = Math.min(mapPartGloballyLeft, mapPartPersonallyLeft);
int mapPartLeft;
if (mapGlobalLimit <= 0 && mapPersonalLimit <= 0)
mapPartLeft = -1;
else if (mapGlobalLimit <= 0)
mapPartLeft = mapPartPersonallyLeft;
else if (mapPersonalLimit <= 0)
mapPartLeft = mapPartGloballyLeft;
else
mapPartLeft = Math.min(mapPartGloballyLeft, mapPartPersonallyLeft);
double percentageUsed = mapPartLeft < 0 ? 0 : ((double) mapPartCount) / ((double) (mapPartCount + mapPartLeft)) * 100;
double percentageUsed = mapPartLeft < 0 ? 0 : ((double) mapPartCount) / ((double) (mapPartCount + mapPartLeft)) * 100;
ItemStackBuilder statistics = new ItemStackBuilder(Material.ENCHANTED_BOOK)
.title(ChatColor.BLUE, "Usage statistics")
.lore( "",
getStatisticText("Images rendered", imagesCount),
getStatisticText("Minecraft maps used", mapPartCount));
if(mapPartLeft >= 0)
{
statistics.lore("", ChatColor.BLUE + "Minecraft maps limits");
statistics.lore("",
getStatisticText("Server-wide limit", mapGlobalLimit, true),
getStatisticText("Per-player limit", mapPersonalLimit, true))
.lore("",
getStatisticText("Current consumption", ((int) Math.rint(percentageUsed)) + " %"),
getStatisticText("Maps left", mapPartLeft));
}
statistics.hideAttributes();
ItemStackBuilder statistics = new ItemStackBuilder(Material.ENCHANTED_BOOK)
.title(I.t("{blue}Usage statistics"))
.loreLine()
.lore(I.tn("{white}{0}{gray} image rendered", "{white}{0}{gray} images rendered", imagesCount))
.lore(I.tn("{white}{0}{gray} Minecraft map used", "{white}{0}{gray} Minecraft maps used", mapPartCount));
action("", getSize() - 5, statistics);
}
if(mapPartLeft >= 0)
{
statistics
.lore("", I.t("{blue}Minecraft maps limits"), "")
.lore(mapGlobalLimit == 0
? I.t("{gray}Server-wide limit: {white}unlimited")
: I.t("{gray}Server-wide limit: {white}{0}", mapGlobalLimit))
.lore(mapPersonalLimit == 0
? I.t("{gray}Per-player limit: {white}unlimited")
: I.t("{gray}Per-player limit: {white}{0}", mapPersonalLimit))
.loreLine()
.lore(I.t("{white}{0} %{gray} of your quota used", (int) Math.rint(percentageUsed)))
.lore(I.tn("{white}{0}{gray} map left", "{white}{0}{gray} maps left", mapPartLeft));
}
private String getStatisticText(String title, Integer value)
{
return getStatisticText(title, value, false);
}
statistics.hideAttributes();
private String getStatisticText(String title, Integer value, boolean zeroIsUnlimited)
{
return getStatisticText(title, zeroIsUnlimited && value <= 0 ? "unlimited" : bigNumbersFormatter.format(value));
}
private String getStatisticText(String title, String value)
{
return ChatColor.GRAY + title + ": " + ChatColor.WHITE + value;
}
action("", getSize() - 5, statistics);
}
}

View File

@ -20,6 +20,7 @@ package fr.moribus.imageonmap.image;
import fr.moribus.imageonmap.map.ImageMap;
import fr.moribus.imageonmap.map.MapManager;
import fr.zcraft.zlib.components.i18n.I;
import fr.zcraft.zlib.components.worker.Worker;
import fr.zcraft.zlib.components.worker.WorkerAttributes;
import fr.zcraft.zlib.components.worker.WorkerCallback;
@ -69,13 +70,13 @@ public class ImageRendererExecutor extends Worker
final int httpCode = httpConnection.getResponseCode();
if((httpCode / 100) != 2)
{
throw new IOException("HTTP error : " + httpCode + " " + httpConnection.getResponseMessage());
throw new IOException(I.t("HTTP error : {0} {1}", httpCode, httpConnection.getResponseMessage()));
}
}
final InputStream stream = connection.getInputStream();
final BufferedImage image = ImageIO.read(stream);
if (image == null) throw new IOException("The given URL is not a valid image");
if (image == null) throw new IOException(I.t("The given URL is not a valid image"));
if (scaling) return RenderSingle(image, playerUUID);
else return RenderPoster(image, playerUUID);

View File

@ -18,25 +18,30 @@
package fr.moribus.imageonmap.map;
import fr.moribus.imageonmap.ui.*;
import org.bukkit.*;
import org.bukkit.configuration.*;
import org.bukkit.configuration.serialization.*;
import org.bukkit.entity.*;
import org.bukkit.inventory.*;
import fr.moribus.imageonmap.ui.MapItemManager;
import fr.zcraft.zlib.components.i18n.I;
import org.bukkit.Material;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.*;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public abstract class ImageMap implements ConfigurationSerializable
{
static public enum Type
public enum Type
{
SINGLE, POSTER;
};
SINGLE, POSTER
}
static public final int WIDTH = 128;
static public final int HEIGHT = 128;
static public final String DEFAULT_NAME = "Map";
/// The default display name of a map
static public final String DEFAULT_NAME = I.t("Map");
private String id;
private final UUID userUUID;

View File

@ -18,18 +18,21 @@
package fr.moribus.imageonmap.map;
import fr.zcraft.zlib.components.i18n.I;
import java.text.MessageFormat;
public class MapManagerException extends Exception
{
public enum Reason
{
MAXIMUM_PLAYER_MAPS_EXCEEDED("You have too many maps (maximum : {0})."),
MAXIMUM_SERVER_MAPS_EXCEEDED("The server ImageOnMap limit has been reached."),
IMAGEMAP_DOES_NOT_EXIST("The given map does not exist.");
MAXIMUM_PLAYER_MAPS_EXCEEDED(I.t("You have too many maps (maximum : {0}).")),
MAXIMUM_SERVER_MAPS_EXCEEDED(I.t("The server ImageOnMap limit has been reached.")),
IMAGEMAP_DOES_NOT_EXIST(I.t("The given map does not exist."));
private final String reasonString;
private Reason(String reasonString)
Reason(String reasonString)
{
this.reasonString = reasonString;
}
@ -39,7 +42,8 @@ public class MapManagerException extends Exception
return MessageFormat.format(reasonString, arguments);
}
}
private final Reason reason;
public MapManagerException(Reason reason, Object ...arguments)
@ -49,5 +53,4 @@ public class MapManagerException extends Exception
}
public Reason getReason() { return reason; }
}

View File

@ -19,6 +19,7 @@
package fr.moribus.imageonmap.migration;
import fr.moribus.imageonmap.ImageOnMap;
import fr.zcraft.zlib.components.i18n.I;
import fr.zcraft.zlib.tools.PluginLogger;
@ -30,7 +31,7 @@ public class MigratorExecutor
{
if(isRunning())
{
PluginLogger.error("Migration is already running.");
PluginLogger.error(I.t("Migration is already running."));
return;
}
migratorThread = new Thread(new V3Migrator(ImageOnMap.getPlugin()), "ImageOnMap-Migration");
@ -46,14 +47,15 @@ public class MigratorExecutor
{
if(isRunning())
{
PluginLogger.info("Waiting for migration to finish ...");
PluginLogger.info(I.t("Waiting for migration to finish..."));
try
{
migratorThread.join();
}
catch(InterruptedException ex)
{
PluginLogger.error("Migration thread has been interrupted while wating to finish. It may not have ended correctly.");
PluginLogger.error(I.t("Migration thread has been interrupted while waiting to finish. It may not have ended correctly."));
}
}
}

View File

@ -20,6 +20,7 @@ package fr.moribus.imageonmap.migration;
import fr.moribus.imageonmap.ImageOnMap;
import fr.moribus.imageonmap.map.MapManager;
import fr.zcraft.zlib.components.i18n.I;
import fr.zcraft.zlib.tools.PluginLogger;
import fr.zcraft.zlib.tools.mojang.UUIDFetcher;
import org.bukkit.configuration.InvalidConfigurationException;
@ -41,8 +42,6 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This class represents and executes the ImageOnMap v3.x migration process
@ -171,8 +170,8 @@ public class V3Migrator implements Runnable
}
catch(Exception ex)
{
PluginLogger.error("Error while preparing migration");
PluginLogger.error("Aborting migration. No change has been made.", ex);
PluginLogger.error(I.t("Error while preparing migration"));
PluginLogger.error(I.t("Aborting migration. No change has been made."), ex);
return;
}
@ -184,11 +183,9 @@ public class V3Migrator implements Runnable
}
catch(Exception ex)
{
PluginLogger.error("Error while migrating", ex);
PluginLogger.error("Aborting migration. Some changes may already have been made.");
PluginLogger.error("Before trying to migrate again, you must recover player files from the backups, and then move the backups away from the plugin directory to avoid overwriting them.");
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
PluginLogger.error(I.t("Error while migrating"), ex);
PluginLogger.error(I.t("Aborting migration. Some changes may already have been made."));
PluginLogger.error(I.t("Before trying to migrate again, you must recover player files from the backups, and then move the backups away from the plugin directory to avoid overwriting them."));
}
}
@ -200,22 +197,22 @@ public class V3Migrator implements Runnable
*/
private boolean spotFilesToMigrate()
{
PluginLogger.info("Looking for configuration files to migrate ...");
PluginLogger.info(I.t("Looking for configuration files to migrate..."));
if(!oldPostersFile.exists()) oldPostersFile = null;
else PluginLogger.info("Detected former posters file {0}", OLD_POSTERS_FILE_NAME);
else PluginLogger.info(I.t("Detected former posters file {0}", OLD_POSTERS_FILE_NAME));
if(!oldMapsFile.exists()) oldMapsFile = null;
else PluginLogger.info("Detected former maps file {0}", OLD_MAPS_FILE_NAME);
else PluginLogger.info(I.t("Detected former maps file {0}", OLD_MAPS_FILE_NAME));
if(oldPostersFile == null && oldMapsFile == null)
{
PluginLogger.info("There is nothing to migrate. Stopping.");
PluginLogger.info(I.t("There is nothing to migrate. Stopping."));
return false;
}
else
{
PluginLogger.info("Done.");
PluginLogger.info(I.t("Done."));
return true;
}
}
@ -229,9 +226,9 @@ public class V3Migrator implements Runnable
if((backupsPrev3Directory.exists() && backupsPrev3Directory.list().length == 0)
|| (backupsPostv3Directory.exists() && backupsPostv3Directory.list().length == 0))
{
PluginLogger.error("Backup directories already exists.");
PluginLogger.error("This means that a migration has already been done, or may not have ended well.");
PluginLogger.error("To start a new migration, you must move away the backup directories so they are not overwritten.");
PluginLogger.error(I.t("Backup directories already exists."));
PluginLogger.error(I.t("This means that a migration has already been done, or may not have ended well."));
PluginLogger.error(I.t("To start a new migration, you must move away the backup directories so they are not overwritten."));
return true;
}
@ -345,22 +342,22 @@ public class V3Migrator implements Runnable
*/
private void fetchUUIDs() throws IOException, InterruptedException
{
PluginLogger.info("Fetching UUIDs from Mojang ...");
PluginLogger.info(I.t("Fetching UUIDs from Mojang ..."));
try
{
usersUUIDs = UUIDFetcher.fetch(new ArrayList<String>(userNamesToFetch));
}
catch(IOException ex)
{
PluginLogger.error("An error occurred while fetching the UUIDs from Mojang", ex);
PluginLogger.error(I.t("An error occurred while fetching the UUIDs from Mojang"), ex);
throw ex;
}
catch(InterruptedException ex)
{
PluginLogger.error("The migration worker has been interrupted", ex);
PluginLogger.error(I.t("The migration worker has been interrupted"), ex);
throw ex;
}
PluginLogger.info("Fetching done. {0} UUIDs have been retrieved.", usersUUIDs.size());
PluginLogger.info(I.tn("Fetching done. {0} UUID have been retrieved.", "Fetching done. {0} UUIDs have been retrieved.", usersUUIDs.size()));
}
/**
@ -371,8 +368,8 @@ public class V3Migrator implements Runnable
{
if(usersUUIDs.size() == userNamesToFetch.size()) return true;
int remainingUsersCount = userNamesToFetch.size() - usersUUIDs.size();
PluginLogger.info("Mojang did not find UUIDs for {0} players at the current time.", remainingUsersCount);
PluginLogger.info("The Mojang servers limit requests rate at one per second, this may take some time...");
PluginLogger.info(I.tn("Mojang did not find UUIDs for {0} player at the current time.", "Mojang did not find UUIDs for {0} players at the current time.", remainingUsersCount));
PluginLogger.info(I.t("The Mojang servers limit requests rate at one per second, this may take some time..."));
try
{
@ -380,35 +377,36 @@ public class V3Migrator implements Runnable
}
catch(IOException ex)
{
PluginLogger.error("An error occurred while fetching the UUIDs from Mojang");
PluginLogger.error(I.t("An error occurred while fetching the UUIDs from Mojang"));
throw ex;
}
catch(InterruptedException ex)
{
PluginLogger.error("The migration worker has been interrupted");
PluginLogger.error(I.t("The migration worker has been interrupted"));
throw ex;
}
if(usersUUIDs.size() != userNamesToFetch.size())
{
PluginLogger.warning("Mojang did not find player data for {0} players",
userNamesToFetch.size() - usersUUIDs.size());
PluginLogger.warning("The following players do not exist or do not have paid accounts :");
PluginLogger.warning(I.tn("Mojang did not find player data for {0} player", "Mojang did not find player data for {0} players",
userNamesToFetch.size() - usersUUIDs.size()));
PluginLogger.warning(I.t("The following players do not exist or do not have paid accounts :"));
String missingUsersList = "";
for(String user : userNamesToFetch)
{
if(!usersUUIDs.containsKey(user)) missingUsersList += user + ",";
if(!usersUUIDs.containsKey(user)) missingUsersList += user + ", ";
}
missingUsersList = missingUsersList.substring(0, missingUsersList.length());
PluginLogger.info(missingUsersList);
}
if(usersUUIDs.size() <= 0)
{
PluginLogger.info("Mojang could not find any of the registered players.");
PluginLogger.info("There is nothing to migrate. Stopping.");
PluginLogger.info(I.t("Mojang could not find any of the registered players."));
PluginLogger.info(I.t("There is nothing to migrate. Stopping."));
return false;
}
@ -417,7 +415,7 @@ public class V3Migrator implements Runnable
private void mergeMapData()
{
PluginLogger.info("Merging map data ...");
PluginLogger.info(I.t("Merging map data ..."));
ArrayDeque<OldSavedMap> remainingMaps = new ArrayDeque<>();
ArrayDeque<OldSavedPoster> remainingPosters = new ArrayDeque<>();
@ -458,25 +456,25 @@ public class V3Migrator implements Runnable
private void saveChanges()
{
PluginLogger.info("Saving changes ...");
PluginLogger.info(I.t("Saving changes ..."));
MapManager.save();
}
private void cleanup() throws IOException
{
PluginLogger.info("Cleaning up old data files ...");
PluginLogger.info(I.t("Cleaning up old data files ..."));
//Cleaning maps file
if(oldMapsFile != null)
{
if(mapsToMigrate.isEmpty())
{
PluginLogger.info("Deleting old map data file ...");
PluginLogger.info(I.t("Deleting old map data file ..."));
oldMapsFile.delete();
}
else
{
PluginLogger.info("{0} maps could not be migrated.", mapsToMigrate.size());
PluginLogger.info(I.tn("{0} map could not be migrated.", "{0} maps could not be migrated.", mapsToMigrate.size()));
YamlConfiguration mapConfig = new YamlConfiguration();
mapConfig.set("IdCount", mapsToMigrate.size());
@ -494,12 +492,12 @@ public class V3Migrator implements Runnable
{
if(postersToMigrate.isEmpty())
{
PluginLogger.info("Deleting old poster data file ...");
PluginLogger.info(I.t("Deleting old poster data file ..."));
oldPostersFile.delete();
}
else
{
PluginLogger.info("{0} posters could not be migrated.", postersToMigrate.size());
PluginLogger.info(I.tn("{0} poster could not be migrated.", "{0} posters could not be migrated.", postersToMigrate.size()));
YamlConfiguration posterConfig = new YamlConfiguration();
posterConfig.set("IdCount", postersToMigrate.size());
@ -512,7 +510,7 @@ public class V3Migrator implements Runnable
}
}
PluginLogger.info("Data that has not been migrated will be kept in the old data files.");
PluginLogger.info(I.t("Data that has not been migrated will be kept in the old data files."));
}
/* ****** Utils ***** */

View File

@ -22,12 +22,18 @@ import fr.moribus.imageonmap.map.ImageMap;
import fr.moribus.imageonmap.map.MapManager;
import fr.moribus.imageonmap.map.PosterMap;
import fr.moribus.imageonmap.map.SingleMap;
import fr.zcraft.zlib.components.i18n.I;
import fr.zcraft.zlib.core.ZLib;
import fr.zcraft.zlib.tools.items.ItemStackBuilder;
import fr.zcraft.zlib.tools.items.ItemUtils;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
@ -35,11 +41,6 @@ import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.Queue;
import java.util.UUID;
import org.bukkit.GameMode;
import org.bukkit.entity.ItemFrame;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
public class MapItemManager implements Listener
{
@ -113,9 +114,8 @@ public class MapItemManager implements Listener
String mapName;
if(map.hasColumnData())
{
mapName = map.getName() +
" (row " + x +
", column " + y + ")";
/// The name of a map item given to a player, if splatter maps are not used. 0 = map name; 1 = row; 2 = column.
mapName = I.t("{0} (row {1}, column {2})", map.getName(), x, y);
}
else
{
@ -150,9 +150,7 @@ public class MapItemManager implements Listener
{
return MapItemManager.createMapItem(
((PosterMap) map).getMapIdAt(x, y),
map.getName() +
" (row " + (y + 1) +
", column " + (x + 1) + ")"
I.t("{0} (row {1}, column {2})", map.getName(), y + 1, x + 1)
);
}
else
@ -193,8 +191,7 @@ public class MapItemManager implements Listener
{
PosterMap poster = (PosterMap) map;
int index = poster.getIndex(item.getDurability());
return map.getName() + " (row " + (poster.getRowAt(index)) +
", column " + (poster.getColumnAt(index)) + ")";
return I.t("{0} (row {1}, column {2})", map.getName(), poster.getRowAt(index), poster.getColumnAt(index));
}
}

View File

@ -22,6 +22,7 @@ import fr.moribus.imageonmap.map.ImageMap;
import fr.moribus.imageonmap.map.MapManager;
import fr.moribus.imageonmap.map.PosterMap;
import fr.zcraft.zlib.components.gui.GuiUtils;
import fr.zcraft.zlib.components.i18n.I;
import fr.zcraft.zlib.tools.items.GlowEffect;
import fr.zcraft.zlib.tools.items.ItemStackBuilder;
import fr.zcraft.zlib.tools.world.FlatLocation;
@ -40,16 +41,19 @@ abstract public class SplatterMapManager
{
return new ItemStackBuilder(Material.MAP)
.data(map.getMapIdAt(0))
.title(ChatColor.GOLD, map.getName()).title(ChatColor.DARK_GRAY, " - ").title(ChatColor.GRAY, "Splatter Map")
.title(ChatColor.GOLD, map.getName()).title(ChatColor.DARK_GRAY, " - ").title(ChatColor.GRAY, I.t("Splatter Map"))
.loreLine(ChatColor.GRAY, map.getId())
.loreLine()
.loreLine(ChatColor.BLUE, "Item frames needed")
.loreLine(ChatColor.GRAY, map.getColumnCount() + " × " + map.getRowCount())
/// Title in a splatter map tooltip
.loreLine(ChatColor.BLUE, I.t("Item frames needed"))
/// Size of a map stored in a splatter map
.loreLine(ChatColor.GRAY, I.t("{0} × {1}", map.getColumnCount(), map.getRowCount()))
.loreLine()
.loreLine(ChatColor.BLUE, "How to use this?")
.lore(GuiUtils.generateLore(ChatColor.GRAY + "Place empty item frames on a wall, enough to host the whole map. Then, right-click on the bottom-left frame with this map."))
/// Title in a splatter map tooltip
.loreLine(ChatColor.BLUE, I.t("How to use this?"))
.lore(GuiUtils.generateLore(ChatColor.GRAY + I.t("Place empty item frames on a wall, enough to host the whole map. Then, right-click on the bottom-left frame with this map.")))
.loreLine()
.lore(GuiUtils.generateLore(ChatColor.GRAY + "Shift-click one of the placed maps to remove the whole poster at a single time."))
.lore(GuiUtils.generateLore(ChatColor.GRAY + I.t("Shift-click one of the placed maps to remove the whole poster at a single time.")))
.glow()
.hideAttributes()
.item();
@ -94,7 +98,7 @@ abstract public class SplatterMapManager
if(!wall.isValid())
{
player.sendMessage(ChatColor.RED + "There is not enough space to place this map (" + poster.getColumnCount() + "x" + poster.getRowCount() + ")");
player.sendMessage(I.t("{ce}There is not enough space to place this map ({0} × {1}).", poster.getColumnCount(), poster.getRowCount()));
return false;
}

View File

@ -1,6 +1,11 @@
### ImageOnMap configuration file
# Plugin language. Empty: system language.
# Available: en_US (default, fallback) and fr_FR.
lang:
# Allows collection of anonymous statistics on plugin environment and usage
# The statistics are publicly visible here: http://mcstats.org/plugin/ImageOnMap
collect-data: true