From 706ca5601d3632dc14b5dba3f89b1e87d6790b0f Mon Sep 17 00:00:00 2001
From: Amaury Carrade <amaury@carrade.eu>
Date: Sat, 21 May 2016 18:55:32 +0200
Subject: [PATCH 1/3] Internationalization of the plugin.

* NEW: the plugin can now be translated.
---
 .../fr/moribus/imageonmap/ImageOnMap.java     |   7 +-
 .../imageonmap/PluginConfiguration.java       |   4 +
 .../imageonmap/commands/IoMCommand.java       |   5 +-
 .../maptool/DeleteConfirmCommand.java         |  20 +-
 .../maptool/DeleteNoConfirmCommand.java       |   8 +-
 .../commands/maptool/GetCommand.java          |   5 +-
 .../commands/maptool/GetRemainingCommand.java |   7 +-
 .../commands/maptool/ListCommand.java         |   5 +-
 .../commands/maptool/MigrateCommand.java      |   5 +-
 .../commands/maptool/NewCommand.java          |  18 +-
 .../imageonmap/gui/ConfirmDeleteMapGui.java   |  38 +--
 .../moribus/imageonmap/gui/MapDetailGui.java  |  65 +++---
 .../fr/moribus/imageonmap/gui/MapListGui.java | 218 ++++++++----------
 .../image/ImageRendererExecutor.java          |   5 +-
 .../fr/moribus/imageonmap/map/ImageMap.java   |  27 ++-
 .../imageonmap/map/MapManagerException.java   |  15 +-
 .../migration/MigratorExecutor.java           |   8 +-
 .../imageonmap/migration/V3Migrator.java      |  76 +++---
 .../moribus/imageonmap/ui/MapItemManager.java |  23 +-
 .../imageonmap/ui/SplatterMapManager.java     |  18 +-
 src/main/resources/config.yml                 |   5 +
 21 files changed, 285 insertions(+), 297 deletions(-)

diff --git a/src/main/java/fr/moribus/imageonmap/ImageOnMap.java b/src/main/java/fr/moribus/imageonmap/ImageOnMap.java
index e030b1f..428b00d 100644
--- a/src/main/java/fr/moribus/imageonmap/ImageOnMap.java
+++ b/src/main/java/fr/moribus/imageonmap/ImageOnMap.java
@@ -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();
diff --git a/src/main/java/fr/moribus/imageonmap/PluginConfiguration.java b/src/main/java/fr/moribus/imageonmap/PluginConfiguration.java
index 9e317a7..3dff18e 100644
--- a/src/main/java/fr/moribus/imageonmap/PluginConfiguration.java
+++ b/src/main/java/fr/moribus/imageonmap/PluginConfiguration.java
@@ -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");
diff --git a/src/main/java/fr/moribus/imageonmap/commands/IoMCommand.java b/src/main/java/fr/moribus/imageonmap/commands/IoMCommand.java
index 480502a..4497d8e 100644
--- a/src/main/java/fr/moribus/imageonmap/commands/IoMCommand.java
+++ b/src/main/java/fr/moribus/imageonmap/commands/IoMCommand.java
@@ -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;
 	}
diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteConfirmCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteConfirmCommand.java
index 102d1b9..d7c169b 100644
--- a/src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteConfirmCommand.java
+++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteConfirmCommand.java
@@ -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();
         
diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteNoConfirmCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteNoConfirmCommand.java
index d796967..6c21183 100644
--- a/src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteNoConfirmCommand.java
+++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteNoConfirmCommand.java
@@ -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;
     }
 }
-
diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/GetCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/GetCommand.java
index 3aa4058..51c47ff 100644
--- a/src/main/java/fr/moribus/imageonmap/commands/maptool/GetCommand.java
+++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/GetCommand.java
@@ -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."));
         }
     }
     
diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/GetRemainingCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/GetRemainingCommand.java
index 9fcac59..f0d7803 100644
--- a/src/main/java/fr/moribus/imageonmap/commands/maptool/GetRemainingCommand.java
+++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/GetRemainingCommand.java
@@ -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)));
         }
     }
 }
diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/ListCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/ListCommand.java
index cead4e9..50b53bc 100644
--- a/src/main/java/fr/moribus/imageonmap/commands/maptool/ListCommand.java
+++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/ListCommand.java
@@ -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++)
diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/MigrateCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/MigrateCommand.java
index 27d1c26..9f4fdcc 100644
--- a/src/main/java/fr/moribus/imageonmap/commands/maptool/MigrateCommand.java
+++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/MigrateCommand.java
@@ -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();
         }
     }
diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java
index c5bba85..54595ca 100644
--- a/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java
+++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java
@@ -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());
diff --git a/src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java b/src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java
index c824a7c..a094fd8 100644
--- a/src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java
+++ b/src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java
@@ -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
diff --git a/src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java b/src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java
index a1f2cc1..10e4454 100644
--- a/src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java
+++ b/src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java
@@ -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);
     }
diff --git a/src/main/java/fr/moribus/imageonmap/gui/MapListGui.java b/src/main/java/fr/moribus/imageonmap/gui/MapListGui.java
index f39791d..f8b70a7 100644
--- a/src/main/java/fr/moribus/imageonmap/gui/MapListGui.java
+++ b/src/main/java/fr/moribus/imageonmap/gui/MapListGui.java
@@ -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);
+    }
 }
diff --git a/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java b/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java
index f689f2d..a4bb967 100644
--- a/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java
+++ b/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java
@@ -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);
diff --git a/src/main/java/fr/moribus/imageonmap/map/ImageMap.java b/src/main/java/fr/moribus/imageonmap/map/ImageMap.java
index ef46e64..bd71fad 100644
--- a/src/main/java/fr/moribus/imageonmap/map/ImageMap.java
+++ b/src/main/java/fr/moribus/imageonmap/map/ImageMap.java
@@ -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;
diff --git a/src/main/java/fr/moribus/imageonmap/map/MapManagerException.java b/src/main/java/fr/moribus/imageonmap/map/MapManagerException.java
index b7cf91a..7fc3c49 100644
--- a/src/main/java/fr/moribus/imageonmap/map/MapManagerException.java
+++ b/src/main/java/fr/moribus/imageonmap/map/MapManagerException.java
@@ -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; }
-    
 }
diff --git a/src/main/java/fr/moribus/imageonmap/migration/MigratorExecutor.java b/src/main/java/fr/moribus/imageonmap/migration/MigratorExecutor.java
index 84909d2..c9d1fab 100644
--- a/src/main/java/fr/moribus/imageonmap/migration/MigratorExecutor.java
+++ b/src/main/java/fr/moribus/imageonmap/migration/MigratorExecutor.java
@@ -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."));
             }
         }
     }
diff --git a/src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java b/src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java
index 047a428..6f5f716 100644
--- a/src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java
+++ b/src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java
@@ -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 ***** */
diff --git a/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java b/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java
index 01ae66f..9131539 100644
--- a/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java
+++ b/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java
@@ -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));
         }
     }
     
diff --git a/src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java b/src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java
index c693c7d..8d93952 100644
--- a/src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java
+++ b/src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java
@@ -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;
         }
         
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 0aa0f21..5ffe7d4 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -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

From 79004336a0cd538b3d88c1bde8424087c690c11f Mon Sep 17 00:00:00 2001
From: Amaury Carrade <amaury@carrade.eu>
Date: Sat, 21 May 2016 20:55:03 +0200
Subject: [PATCH 2/3] Fixed some typos in texts.

* BUG: fixed typography errors and things like this.
---
 .../commands/maptool/GetRemainingCommand.java      |  2 +-
 .../imageonmap/commands/maptool/NewCommand.java    |  2 +-
 .../imageonmap/gui/ConfirmDeleteMapGui.java        |  2 +-
 .../moribus/imageonmap/migration/V3Migrator.java   | 14 +++++++-------
 .../moribus/imageonmap/ui/SplatterMapManager.java  |  2 +-
 5 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/GetRemainingCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/GetRemainingCommand.java
index f0d7803..7bd1b72 100644
--- a/src/main/java/fr/moribus/imageonmap/commands/maptool/GetRemainingCommand.java
+++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/GetRemainingCommand.java
@@ -43,7 +43,7 @@ public class GetRemainingCommand extends IoMCommand
         
         if(givenMaps == 0)
         {
-            error(I.t("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
         {
diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java
index 54595ca..c478f8d 100644
--- a/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java
+++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java
@@ -64,7 +64,7 @@ public class NewCommand  extends IoMCommand
             @Override
             public void finished(ImageMap result)
             {
-                player.sendMessage(I.t("{cst}Rendering finished !"));
+                player.sendMessage(I.t("{cst}Rendering finished!"));
                 if(result.give(player))
                 {
                     info(I.t("The rendered map was too big to fit in your inventory."));
diff --git a/src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java b/src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java
index a094fd8..184ea90 100644
--- a/src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java
+++ b/src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java
@@ -113,7 +113,7 @@ public class ConfirmDeleteMapGui extends ActionGui
                 .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))
+                .lore(I.t("{gray}Maps inside: {white}{0}", mapToDelete.getMapsIDs().length))
                 .hideAttributes()
         );
 
diff --git a/src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java b/src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java
index 6f5f716..ffee2d2 100644
--- a/src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java
+++ b/src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java
@@ -241,7 +241,7 @@ public class V3Migrator implements Runnable
      */
     private void backupMapData() throws IOException
     {
-        PluginLogger.info("Backing up map data before migrating ...");
+        PluginLogger.info("Backing up map data before migrating...");
         
         if(!backupsPrev3Directory.exists()) backupsPrev3Directory.mkdirs();
         if(!backupsPostv3Directory.exists()) backupsPostv3Directory.mkdirs();
@@ -342,7 +342,7 @@ public class V3Migrator implements Runnable
      */
     private void fetchUUIDs() throws IOException, InterruptedException
     {
-        PluginLogger.info(I.t("Fetching UUIDs from Mojang ..."));
+        PluginLogger.info(I.t("Fetching UUIDs from Mojang..."));
         try
         {
             usersUUIDs = UUIDFetcher.fetch(new ArrayList<String>(userNamesToFetch));
@@ -415,7 +415,7 @@ public class V3Migrator implements Runnable
     
     private void mergeMapData()
     {
-        PluginLogger.info(I.t("Merging map data ..."));
+        PluginLogger.info(I.t("Merging map data..."));
         
         ArrayDeque<OldSavedMap> remainingMaps = new ArrayDeque<>();
         ArrayDeque<OldSavedPoster> remainingPosters = new ArrayDeque<>();
@@ -456,20 +456,20 @@ public class V3Migrator implements Runnable
     
     private void saveChanges()
     {
-        PluginLogger.info(I.t("Saving changes ..."));
+        PluginLogger.info(I.t("Saving changes..."));
         MapManager.save();
     }
     
     private void cleanup() throws IOException
     {
-        PluginLogger.info(I.t("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(I.t("Deleting old map data file ..."));
+                PluginLogger.info(I.t("Deleting old map data file..."));
                 oldMapsFile.delete();
             }
             else
@@ -492,7 +492,7 @@ public class V3Migrator implements Runnable
         {
             if(postersToMigrate.isEmpty())
             {
-                PluginLogger.info(I.t("Deleting old poster data file ..."));
+                PluginLogger.info(I.t("Deleting old poster data file..."));
                 oldPostersFile.delete();
             }
             else
diff --git a/src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java b/src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java
index 8d93952..9b4c335 100644
--- a/src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java
+++ b/src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java
@@ -53,7 +53,7 @@ abstract public class SplatterMapManager
                 .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 + I.t("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 in one shot.")))
                 .glow()
                 .hideAttributes()
                 .item();

From 8fd31f298e962d55b99fc36754bb1aec513b5f34 Mon Sep 17 00:00:00 2001
From: Amaury Carrade <amaury@carrade.eu>
Date: Sat, 21 May 2016 20:56:07 +0200
Subject: [PATCH 3/3] Added fr_FR translation.

---
 src/main/resources/i18n/fr_FR.po | 560 +++++++++++++++++++++++++++++++
 1 file changed, 560 insertions(+)
 create mode 100644 src/main/resources/i18n/fr_FR.po

diff --git a/src/main/resources/i18n/fr_FR.po b/src/main/resources/i18n/fr_FR.po
new file mode 100644
index 0000000..7dd9019
--- /dev/null
+++ b/src/main/resources/i18n/fr_FR.po
@@ -0,0 +1,560 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2016-05-21 20:34+0200\n"
+"PO-Revision-Date: 2016-05-21 20:38+0100\n"
+"Last-Translator: Amaury Carrade\n"
+"Language-Team: \n"
+"Language: fr_FR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Poedit 1.7.5\n"
+
+#: src/main/java/fr/moribus/imageonmap/commands/IoMCommand.java:40
+msgid "You need to give a map name."
+msgstr "Vous devez donner un nom à la carte."
+
+#: src/main/java/fr/moribus/imageonmap/commands/IoMCommand.java:57
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteNoConfirmCommand.java:51
+msgid "This map does not exist."
+msgstr "Cette carte n'existe pas."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteConfirmCommand.java:39
+msgid "You are going to delete"
+msgstr "Vous êtes sur le point de supprimer"
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteConfirmCommand.java:42
+msgid "Are you sure ? "
+msgstr "Êtes-vous sûr ?"
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteConfirmCommand.java:44
+msgid "[Confirm]"
+msgstr "[Confirmer]"
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteConfirmCommand.java:46
+msgid "{red}This map will be deleted {bold}forever{red}!"
+msgstr "{red}Cette carte sera supprimée {bold}définitivement{red} !"
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteNoConfirmCommand.java:46
+msgid "Map successfully deleted."
+msgstr "Carte supprimée avec succès."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/GetCommand.java:38
+msgid "The requested map was too big to fit in your inventory."
+msgstr ""
+"La carte demandée est trop grosse et ne rentre pas dans votre inventaire."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/GetCommand.java:39
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java:71
+msgid "Use '/maptool getremaining' to get the remaining maps."
+msgstr "Utilisez “/maptool getremaining” pour récupérer les cartes restantes."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/GetRemainingCommand.java:38
+msgid "You have no remaining map."
+msgstr "Vous n'avez aucune carte restante."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/GetRemainingCommand.java:46
+msgid ""
+"Your inventory is full! Make some space before requesting the remaining maps."
+msgstr ""
+"Votre inventaire est plein ! Faites de la place avant de demander les cartes "
+"supplémentaires."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/GetRemainingCommand.java:50
+#, java-format
+msgid "There is {0} map remaining."
+msgid_plural "There are {0} maps remaining."
+msgstr[0] "Il y a {0} carte restante."
+msgstr[1] "Il y a {0} cartes restantes."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/ListCommand.java:49
+msgid "No map found."
+msgstr "Aucune carte."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/ListCommand.java:53
+msgid "{white}{bold}{0} map found."
+msgid_plural "{white}{bold}{0} maps found."
+msgstr[0] "{white}{bold}{0} carte."
+msgstr[1] "{white}{bold}{0} cartes."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/ListCommand.java:79
+msgid "{white}Click{gray} to get this map"
+msgstr "{white}Cliquez{gray} pour obtenir cette carte"
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/MigrateCommand.java:36
+msgid "A migration process is already running. Check console for details."
+msgstr ""
+"Un processus de migration est déjà en cours. Consultez la console pour plus "
+"de détails."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/MigrateCommand.java:40
+msgid "Migration started. See console for details."
+msgstr "Migration démarrée. Consultez la console pour plus de détails."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java:44
+msgid "You must give an URL to take the image from."
+msgstr "Vous devez fournir l'URL de l'image."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java:52
+msgid "Invalid URL."
+msgstr "URL invalide."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java:61
+msgid "Rendering..."
+msgstr "Rendu en cours..."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java:67
+msgid "{cst}Rendering finished!"
+msgstr "{cst}Rendu achevé !"
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java:70
+msgid "The rendered map was too big to fit in your inventory."
+msgstr ""
+"La carte rendue est trop grosse et ne rentre pas dans votre inventaire."
+
+#: src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java:78
+msgid "{ce}Map rendering failed: {0}"
+msgstr "{ce}Impossible de faire le rendu de la carte : {0}"
+
+#. The title of the map deletion GUI. {0}: map name.
+#: src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java:102
+msgid "{0} » {black}Confirm deletion"
+msgstr "{0} » {black}Confirmation de suppression"
+
+#. The title of the map deletion item
+#: src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java:110
+msgid "{red}You're about to destroy this map..."
+msgstr "{red}Vous êtes sur le point de supprimer cette carte..."
+
+#. The end, in the lore, of a title starting with “You're about to destroy this map...”.
+#: src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java:112
+msgid "{red}...{italic}forever{red}."
+msgstr "{red}...{italic}pour toujours{red}."
+
+#: src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java:114
+msgid "{gray}Name: {white}{0}"
+msgstr "{gray}Nom : {white}{0}"
+
+#: src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java:115
+msgid "{gray}Map ID: {white}{0}"
+msgstr "{gray}Identifiant : {white}{0}"
+
+#: src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java:116
+msgid "{gray}Maps inside: {white}{0}"
+msgstr "{gray}Cartes : {white}{0}"
+
+#: src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java:178
+msgid "{gray}Map successfully deleted."
+msgstr "{gray}Carte supprimée avec succès."
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:53
+msgid "{green}Map part"
+msgstr "{green}Extrait de carte"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:54
+msgid "{gray}Column: {white}{0}"
+msgstr "{gray}Colonne : {white}{0}"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:55
+msgid "{gray}Row: {white}{0}"
+msgstr "{gray}Ligne : {white}{0}"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:57
+msgid "{gray}» {white}Click{gray} to get only this part"
+msgstr "{gray}» {white}Cliquez{gray} pour récupérer cette partie"
+
+#. Title of the map details GUI
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:90
+msgid "Your maps » {black}{0}"
+msgstr "Vos cartes » {black}{0}"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:100
+msgid "{blue}Rename this image"
+msgstr "{blue}Renommer cette image"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:101
+msgid ""
+"{gray}Click here to rename this image; this is used for your own "
+"organization."
+msgstr ""
+"{gray}Cliquez ici pour renommer cette image ; ceci ne sert qu'à votre "
+"organisation personnelle."
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:106
+msgid ""
+"{gray}Deletes this map {white}forever{gray}. This action cannot be undone!"
+msgstr ""
+"{gray}Supprime cette carte {white}pour toujours{gray}. Cette action ne peut "
+"être annulée !"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:108
+msgid "{gray}You will be asked to confirm your choice if you click here."
+msgstr "{gray}Une confirmation sera demandée si vous cliquez ici."
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:120
+msgid "{green}« Back"
+msgstr "{green}« Retour"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:121
+msgid "{gray}Go back to the list."
+msgstr "{gray}Retourner à la liste."
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:136
+msgid "{ce}Map names can't be empty."
+msgstr "{ce}Les noms de cartes ne peuvent être vide."
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java:141
+msgid "{cs}Map successfully renamed."
+msgstr "{cs}Carte renommée avec succès."
+
+#. Displayed subtitle description of a single map on the list GUI
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:43
+msgid "{white}Single map"
+msgstr "{white}Carte unique"
+
+#. Displayed subtitle description of a poster map on the list GUI (columns × rows in english)
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:46
+msgid "{white}Poster map ({0} × {1})"
+msgstr "{white}Poster ({0} × {1})"
+
+#. Displayed title of a map on the list GUI
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:50
+msgid "{green}{bold}{0}"
+msgstr "{green}{bold}{0}"
+
+#. Map ID displayed in the tooltip of a map on the list GUI
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:55
+msgid "{gray}Map ID: {0}"
+msgstr "{gray}Identifiant : {white}{0}"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:57
+msgid "{gray}» {white}Left-click{gray} to get this map"
+msgstr "{gray}» {white}Cliquez droit{gray} pour récupérer cette carte"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:58
+msgid "{gray}» {white}Right-click{gray} for details and options"
+msgstr "{gray}» {white}Cliquez droit{gray} pour détails et options"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:67
+msgid "{red}You don't have any map."
+msgstr "{red}Vous n'avez aucune carte."
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:68
+msgid ""
+"{gray}Get started by creating a new one using {white}/tomap <URL> [resize]"
+"{gray}!"
+msgstr ""
+"{gray}Commencez par en créer une nouvelle avec {white}/tomap <URL> [resize]"
+"{gray} !"
+
+#. The maps list GUI title
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:100
+msgid "{black}Your maps {reset}({0})"
+msgstr "{black}Vos cartes {reset}({0})"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:129
+msgid "{blue}Usage statistics"
+msgstr "{blue}Statistiques d'utilisation"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:131
+msgid "{white}{0}{gray} image rendered"
+msgid_plural "{white}{0}{gray} images rendered"
+msgstr[0] "{white}{0}{gray} image rendue"
+msgstr[1] "{white}{0}{gray} images rendues"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:132
+msgid "{white}{0}{gray} Minecraft map used"
+msgid_plural "{white}{0}{gray} Minecraft maps used"
+msgstr[0] "{white}{0}{gray} carte Minecraft utilisée"
+msgstr[1] "{white}{0}{gray} cartes Minecraft utilisées"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:137
+msgid "{blue}Minecraft maps limits"
+msgstr "{blue}Limites de cartes Minecraft"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:139
+msgid "{gray}Server-wide limit: {white}unlimited"
+msgstr "{gray}Limite du serveur : {white}illimité"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:140
+msgid "{gray}Server-wide limit: {white}{0}"
+msgstr "{gray}Limite du serveur : {white}{0}"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:142
+msgid "{gray}Per-player limit: {white}unlimited"
+msgstr "{gray}Limite individuelle : {white}illimité"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:143
+msgid "{gray}Per-player limit: {white}{0}"
+msgstr "{gray}Limite individuelle : {white}{0}"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:145
+msgid "{white}{0} %{gray} of your quota used"
+msgstr "{white}{0} %{gray} de votre quota utilisé"
+
+#: src/main/java/fr/moribus/imageonmap/gui/MapListGui.java:146
+msgid "{white}{0}{gray} map left"
+msgid_plural "{white}{0}{gray} maps left"
+msgstr[0] "{white}{0}{gray} carte restante"
+msgstr[1] "{white}{0}{gray} cartes restantes"
+
+#: src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java:73
+#, java-format
+msgid "HTTP error : {0} {1}"
+msgstr "Erreur HTTP : {0} {1}"
+
+#: src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java:79
+msgid "The given URL is not a valid image"
+msgstr "L'URL donnée n'est pas une image valide."
+
+#. The default display name of a map
+#: src/main/java/fr/moribus/imageonmap/map/ImageMap.java:44
+msgid "Map"
+msgstr "Carte"
+
+#: src/main/java/fr/moribus/imageonmap/map/MapManagerException.java:29
+#, java-format
+msgid "You have too many maps (maximum : {0})."
+msgstr "Vous avez trop de cartes (maximum : {0})."
+
+#: src/main/java/fr/moribus/imageonmap/map/MapManagerException.java:30
+msgid "The server ImageOnMap limit has been reached."
+msgstr "La limite serveur de cartes a été atteinte."
+
+#: src/main/java/fr/moribus/imageonmap/map/MapManagerException.java:31
+msgid "The given map does not exist."
+msgstr "La carte donnée n'existe pas."
+
+#: src/main/java/fr/moribus/imageonmap/migration/MigratorExecutor.java:34
+msgid "Migration is already running."
+msgstr "La migration est déjà en cours."
+
+#: src/main/java/fr/moribus/imageonmap/migration/MigratorExecutor.java:50
+msgid "Waiting for migration to finish..."
+msgstr "Attente de la fin de la migration..."
+
+#: src/main/java/fr/moribus/imageonmap/migration/MigratorExecutor.java:58
+msgid ""
+"Migration thread has been interrupted while waiting to finish. It may not "
+"have ended correctly."
+msgstr ""
+"Le thread a été interrompu durant l'attente de la fin de la migration. Cette "
+"dernière pourrait s'être achevée anormalement."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:173
+msgid "Error while preparing migration"
+msgstr "Une erreur est survenue lors de la préparation de la migration."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:174
+msgid "Aborting migration. No change has been made."
+msgstr "La migration est annulée. Aucun changement n'a été effectué."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:186
+msgid "Error while migrating"
+msgstr "Erreur lors de la migration"
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:187
+msgid "Aborting migration. Some changes may already have been made."
+msgstr ""
+"La migration est annulée. Certains changements ont pu être effectués malgré "
+"tout."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:188
+msgid ""
+"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."
+msgstr ""
+"Avant de re-tenter la migration, vous devez récupérer les fichiers des "
+"joueurs depuis la sauvegarde qu'a été effectuée automatiquement, puis "
+"déplacer les sauvegardes hors du dossier du plugin afin d'éviter de les "
+"écraser."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:200
+msgid "Looking for configuration files to migrate..."
+msgstr "Recherche de fichiers de configuration à migrer..."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:203
+#, java-format
+msgid "Detected former posters file {0}"
+msgstr "Vieux fichier de posters détecté : {0}"
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:206
+#, java-format
+msgid "Detected former maps file {0}"
+msgstr "Vieux fichier de carte détecté : {0}"
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:210
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:409
+msgid "There is nothing to migrate. Stopping."
+msgstr "Il n'y a rien à migrer. Le processus est arrêté."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:215
+msgid "Done."
+msgstr "Terminé."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:229
+msgid "Backup directories already exists."
+msgstr "Les répertoires de sauvegarde existe déjà."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:230
+msgid ""
+"This means that a migration has already been done, or may not have ended "
+"well."
+msgstr ""
+"Cela signifie qu'une migration a déjà été faite, ou qu'elle n'a possiblement "
+"pas terminé correctement."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:231
+msgid ""
+"To start a new migration, you must move away the backup directories so they "
+"are not overwritten."
+msgstr ""
+"Pour démarrer une nouvelle migration, vous devez déplacer les répertoires de "
+"sauvegarde afin qu'ils ne soit pas écrasés."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:345
+msgid "Fetching UUIDs from Mojang..."
+msgstr "Récupération des UUID depuis Mojang..."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:352
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:380
+msgid "An error occurred while fetching the UUIDs from Mojang"
+msgstr ""
+"Une erreur est survenue lors de la récupération des UUIDs depuis Mojang."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:357
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:385
+msgid "The migration worker has been interrupted"
+msgstr "Le processus de migration a été interrompu."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:360
+#, java-format
+msgid "Fetching done. {0} UUID have been retrieved."
+msgid_plural "Fetching done. {0} UUIDs have been retrieved."
+msgstr[0] "Récupération achevée. {0} UUID a été retrouvé."
+msgstr[1] "Récupération achevée. {0} UUID ont été retrouvé."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:371
+#, java-format
+msgid "Mojang did not find UUIDs for {0} player at the current time."
+msgid_plural "Mojang did not find UUIDs for {0} players at the current time."
+msgstr[0] "Mojang n'a pas trouvé d'UUID pour {0} joueur à l'heure actuelle."
+msgstr[1] "Mojang n'a pas trouvé d'UUID pour {0} joueurs à l'heure actuelle."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:372
+msgid ""
+"The Mojang servers limit requests rate at one per second, this may take some "
+"time..."
+msgstr ""
+"Les serveurs de Mojang limitent les requêtes à une par seconde, cette étape "
+"risque de durer un petit moment..."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:391
+#, java-format
+msgid "Mojang did not find player data for {0} player"
+msgid_plural "Mojang did not find player data for {0} players"
+msgstr[0] "Mojang n'a pas trouvé de données pour {0} joueur."
+msgstr[1] "Mojang n'a pas trouvé de données pour {0} joueurs."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:393
+msgid "The following players do not exist or do not have paid accounts :"
+msgstr "Les joueurs suivant n'existent pas ou n'ont pas de compte payant :"
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:408
+msgid "Mojang could not find any of the registered players."
+msgstr "Mojang n'a pu trouver aucun des joueurs enregistrés."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:418
+msgid "Merging map data..."
+msgstr "Fusion des données des cartes..."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:459
+msgid "Saving changes..."
+msgstr "Sauvegarde des changements..."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:465
+msgid "Cleaning up old data files..."
+msgstr "Nettoyage des vieux fichiers de données..."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:472
+msgid "Deleting old map data file..."
+msgstr "Suppression du vieux fichier de données des cartes..."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:477
+#, java-format
+msgid "{0} map could not be migrated."
+msgid_plural "{0} maps could not be migrated."
+msgstr[0] "{0} carte n'a pas pu être migrée."
+msgstr[1] "{0} cartes n'ont pas pu être migrées."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:495
+msgid "Deleting old poster data file..."
+msgstr "Suppression du vieux fichier de données des posters..."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:500
+#, java-format
+msgid "{0} poster could not be migrated."
+msgid_plural "{0} posters could not be migrated."
+msgstr[0] "{0} poster n'a pas pu être migré."
+msgstr[1] "{0} posters n'ont pas pu être migrés."
+
+#: src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java:513
+msgid "Data that has not been migrated will be kept in the old data files."
+msgstr ""
+"Les données qui n'ont pas été migrées seront conservées dans les vieux "
+"fichiers de donnée."
+
+#. The name of a map item given to a player, if splatter maps are not used. 0 = map name; 1 = row; 2 = column.
+#: src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java:118
+#: src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java:153
+#: src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java:194
+#, java-format
+msgid "{0} (row {1}, column {2})"
+msgstr "{0} (ligne {1}, colonne {2})"
+
+#: src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java:44
+msgid "Splatter Map"
+msgstr "Poster auto-dépliant"
+
+#. Title in a splatter map tooltip
+#: src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java:48
+msgid "Item frames needed"
+msgstr "Cadres requis"
+
+#. Size of a map stored in a splatter map
+#: src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java:50
+#, java-format
+msgid "{0} × {1}"
+msgstr "{0} × {1}"
+
+#. Title in a splatter map tooltip
+#: src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java:53
+msgid "How to use this?"
+msgstr "Comment l'utiliser ?"
+
+#: src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java:54
+msgid ""
+"Place empty item frames on a wall, enough to host the whole map. Then, right-"
+"click on the bottom-left frame with this map."
+msgstr ""
+"Placez des cadres vides sur un mur, en quantité suffisante pour accueillir "
+"la carte entière. Ensuite, cliquez-droit sur le cadre en bas à gauche avec "
+"cette carte."
+
+#: src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java:56
+msgid ""
+"Shift-click one of the placed maps to remove the whole poster in one shot."
+msgstr "Cliquez accroupi l'une des cartes du poster pour le retirer d'un coup."
+
+#: src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java:101
+msgid "{ce}There is not enough space to place this map ({0} × {1})."
+msgstr "{ce}Il n'y a pas assez d'espace pour accueillir ce poster ({0} × {1})."