diff --git a/pom.xml b/pom.xml index f64399367..aefd1ed0c 100644 --- a/pom.xml +++ b/pom.xml @@ -77,6 +77,7 @@ ${basedir}/src/main/resources plugin.yml + *_en.properties diff --git a/src/main/java/net/citizensnpcs/Citizens.java b/src/main/java/net/citizensnpcs/Citizens.java index 18cef037e..43342347f 100644 --- a/src/main/java/net/citizensnpcs/Citizens.java +++ b/src/main/java/net/citizensnpcs/Citizens.java @@ -185,7 +185,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { npcRegistry = null; } - Messaging.logF("v%s disabled.", getDescription().getVersion()); + Messaging.logTr(Messages.CITIZENS_DISABLED, getDescription().getVersion()); } @Override @@ -194,8 +194,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { String mcVersion = ((CraftServer) getServer()).getServer().getVersion(); compatible = mcVersion.startsWith(COMPATIBLE_MC_VERSION); if (!compatible) { - Messaging.severeF("v%s is not compatible with Minecraft v%s. Disabling.", getDescription() - .getVersion(), mcVersion); + Messaging.severeTr(Messages.CITIZENS_INCOMPATIBLE, getDescription().getVersion(), mcVersion); getServer().getPluginManager().disablePlugin(this); return; } @@ -222,7 +221,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { registerCommands(); enableSubPlugins(); - Messaging.logF("v%s enabled.", getDescription().getVersion()); + Messaging.logTr(Messages.CITIZENS_ENABLED, getDescription().getVersion()); // Setup NPCs after all plugins have been enabled (allows for multiworld // support and for NPCs to properly register external settings) diff --git a/src/main/java/net/citizensnpcs/EventListen.java b/src/main/java/net/citizensnpcs/EventListen.java index 472814c8a..3fdc59f60 100644 --- a/src/main/java/net/citizensnpcs/EventListen.java +++ b/src/main/java/net/citizensnpcs/EventListen.java @@ -20,6 +20,8 @@ import net.citizensnpcs.api.trait.trait.Owner; import net.citizensnpcs.editor.Editor; import net.citizensnpcs.npc.entity.EntityHumanNPC; import net.citizensnpcs.trait.CurrentLocation; +import net.citizensnpcs.util.Messages; +import net.citizensnpcs.util.Messaging; import net.citizensnpcs.util.NMS; import net.minecraft.server.EntityPlayer; @@ -209,7 +211,7 @@ public class EventListen implements Listener { int wouldOwn = owned + 1; if (wouldOwn >= limit) { event.setCancelled(true); - event.setCancelReason(String.format("Over the NPC limit of %d.", limit)); + event.setCancelReason(Messaging.tr(Messages.OVER_NPC_LIMIT, limit)); } } diff --git a/src/main/java/net/citizensnpcs/NPCDataStore.java b/src/main/java/net/citizensnpcs/NPCDataStore.java index 078e66996..085862a04 100644 --- a/src/main/java/net/citizensnpcs/NPCDataStore.java +++ b/src/main/java/net/citizensnpcs/NPCDataStore.java @@ -13,6 +13,7 @@ import net.citizensnpcs.api.util.Storage; import net.citizensnpcs.api.util.YamlStorage; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.CitizensNPCRegistry; +import net.citizensnpcs.util.Messages; import net.citizensnpcs.util.Messaging; import org.bukkit.entity.EntityType; @@ -29,7 +30,7 @@ public class NPCDataStore { for (DataKey key : root.getKey("npc").getIntegerSubKeys()) { int id = Integer.parseInt(key.name()); if (!key.keyExists("name")) { - Messaging.logF("Could not find a name for ID '%s'.", id); + Messaging.logTr(Messages.LOAD_NAME_NOT_FOUND, id); continue; } String unparsedEntityType = key.getString("traits.type", "PLAYER"); @@ -38,8 +39,7 @@ public class NPCDataStore { try { type = EntityType.valueOf(unparsedEntityType); } catch (IllegalArgumentException ex) { - Messaging.logF("NPC type '%s' was not recognized. Did you spell it correctly?", - unparsedEntityType); + Messaging.logTr(Messages.LOAD_UNKNOWN_NPC_TYPE, unparsedEntityType); continue; } } @@ -50,7 +50,7 @@ public class NPCDataStore { if (npc.isSpawned()) spawned++; } - Messaging.logF("Loaded %d NPCs (%d spawned).", created, spawned); + Messaging.logTr(Messages.NUM_LOADED_NOTIFICATION, created, spawned); } public void remove(NPC npc) { @@ -89,7 +89,7 @@ public class NPCDataStore { Setting.DATABASE_PASSWORD.asString()); } catch (SQLException e) { e.printStackTrace(); - Messaging.log("Unable to connect to database, falling back to YAML"); + Messaging.logTr(Messages.DATABASE_CONNECTION_FAILED); } } else if (type.equalsIgnoreCase("nbt")) { saves = new NBTStorage(folder + File.separator + Setting.STORAGE_FILE.asString(), @@ -99,7 +99,7 @@ public class NPCDataStore { saves = new YamlStorage(new File(folder, Setting.STORAGE_FILE.asString()), "Citizens NPC Storage"); if (!saves.load()) return null; - Messaging.logF("Save method set to %s.", saves.toString()); + Messaging.logTr(Messages.SAVE_METHOD_SET_NOTIFICATION, saves.toString()); return new NPCDataStore(saves); } } diff --git a/src/main/java/net/citizensnpcs/PaymentListener.java b/src/main/java/net/citizensnpcs/PaymentListener.java index ea18724ce..d4e494576 100644 --- a/src/main/java/net/citizensnpcs/PaymentListener.java +++ b/src/main/java/net/citizensnpcs/PaymentListener.java @@ -2,6 +2,7 @@ package net.citizensnpcs; import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.api.event.PlayerCreateNPCEvent; +import net.citizensnpcs.util.Messages; import net.citizensnpcs.util.Messaging; import net.citizensnpcs.util.StringHelper; import net.milkbowl.vault.economy.Economy; @@ -28,13 +29,14 @@ public class PaymentListener implements Listener { return; double cost = Setting.NPC_COST.asDouble(); boolean hasEnough = provider.has(name, cost); + String formattedCost = provider.format(cost); if (!hasEnough) { event.setCancelled(true); - event.setCancelReason(String.format("Need at least %s.", provider.format(cost))); + event.setCancelReason(Messaging.tr(Messages.MINIMUM_COST_REQUIRED, formattedCost)); return; } provider.withdrawPlayer(name, cost); - Messaging.sendF(event.getCreator(), ChatColor.GREEN + "Withdrew %s for your NPC.", - StringHelper.wrap(provider.format(cost))); + String message = Messaging.tr(Messages.MONEY_WITHDRAWN, StringHelper.wrap(formattedCost)); + Messaging.send(event.getCreator(), ChatColor.GREEN + message); } } diff --git a/src/main/java/net/citizensnpcs/Settings.java b/src/main/java/net/citizensnpcs/Settings.java index cfb71052e..cad598d5e 100644 --- a/src/main/java/net/citizensnpcs/Settings.java +++ b/src/main/java/net/citizensnpcs/Settings.java @@ -7,6 +7,7 @@ import java.util.List; import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.Storage; import net.citizensnpcs.api.util.YamlStorage; +import net.citizensnpcs.util.Messages; import net.citizensnpcs.util.Messaging; import com.google.common.collect.Lists; @@ -22,7 +23,7 @@ public class Settings { config.load(); for (Setting setting : Setting.values()) { if (!root.keyExists(setting.path)) { - Messaging.logF("Writing default setting: '%s'", setting.path); + Messaging.logTr(Messages.WRITING_DEFAULT_SETTING, setting.path); setting.setAtKey(root); } else setting.loadFromKey(root); diff --git a/src/main/java/net/citizensnpcs/command/Command.java b/src/main/java/net/citizensnpcs/command/Command.java index 42d6048ca..cce64c764 100644 --- a/src/main/java/net/citizensnpcs/command/Command.java +++ b/src/main/java/net/citizensnpcs/command/Command.java @@ -5,7 +5,6 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface Command { - String[] aliases(); String desc(); diff --git a/src/main/java/net/citizensnpcs/command/CommandManager.java b/src/main/java/net/citizensnpcs/command/CommandManager.java index a475ce908..56bf6d0fe 100644 --- a/src/main/java/net/citizensnpcs/command/CommandManager.java +++ b/src/main/java/net/citizensnpcs/command/CommandManager.java @@ -26,6 +26,8 @@ import net.citizensnpcs.command.exception.RequirementMissingException; import net.citizensnpcs.command.exception.ServerCommandException; import net.citizensnpcs.command.exception.UnhandledCommandException; import net.citizensnpcs.command.exception.WrappedCommandException; +import net.citizensnpcs.util.Messages; +import net.citizensnpcs.util.Messaging; import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; @@ -120,11 +122,12 @@ public class CommandManager { if (cmdRequirements.selected()) { boolean canRedefineSelected = context.hasValueFlag("id") && sender.hasPermission("npc.select"); - String error = "You must have an NPC selected to execute that command."; + String error = Messaging.tr(Messages.COMMAND_MUST_HAVE_SELECTED); if (canRedefineSelected) { npc = CitizensAPI.getNPCRegistry().getById(context.getFlagInteger("id")); if (npc == null) - error += " Couldn't find any NPC with ID " + context.getFlagInteger("id") + "."; + error += ' ' + Messaging.tr(Messages.COMMAND_ID_NOT_FOUND, + context.getFlagInteger("id")); } if (npc == null) throw new RequirementMissingException(error); @@ -132,8 +135,7 @@ public class CommandManager { if (cmdRequirements.ownership() && npc != null && !sender.hasPermission("citizens.admin") && !npc.getTrait(Owner.class).isOwnedBy(sender)) - throw new RequirementMissingException( - "You must be the owner of this NPC to execute that command."); + throw new RequirementMissingException(Messaging.tr(Messages.COMMAND_MUST_BE_OWNER)); if (npc != null) { Set types = Sets.newEnumSet(Arrays.asList(cmdRequirements.types()), @@ -144,8 +146,8 @@ public class CommandManager { EntityType type = npc.getTrait(MobType.class).getType(); if (!types.contains(type)) { - throw new RequirementMissingException("The NPC cannot be the mob type '" + type.getName() - + "' to use that command."); + throw new RequirementMissingException(Messaging.tr(Messages.COMMAND_INVALID_MOB_TYPE, + type.getName())); } } } diff --git a/src/main/java/net/citizensnpcs/util/Messages.java b/src/main/java/net/citizensnpcs/util/Messages.java index 6643745f2..46ce8b62a 100644 --- a/src/main/java/net/citizensnpcs/util/Messages.java +++ b/src/main/java/net/citizensnpcs/util/Messages.java @@ -4,55 +4,73 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.util.ListResourceBundle; +import java.util.Map.Entry; import java.util.Properties; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import com.google.common.io.Closeables; -public enum Messages { - CITIZENS_IMPLEMENTATION_DISABLED("citizens.changed-implementation", - "Citizens implementation changed, disabling plugin."), - COMMAND_INVALID_NUMBER("citizens.commands.invalid-number", "That is not a valid number."), - COMMAND_MUST_BE_INGAME("citizens.commands.must-be-ingame", "You must be ingame to use that command."), - COMMAND_REPORT_ERROR("citizens.commands.console-error", "Please report this error: [See console]"), - ERROR_INITALISING_SUB_PLUGIN("citizens.sub-plugins.error-on-load", "{0} initializing {1}"), - ERROR_LOADING_ECONOMY("citizens.economy.error-loading", - "Unable to use economy handling. Has Vault been enabled?"), - FAILED_LOAD_SAVES("citizens.saves.load-failed", "Unable to load saves, disabling..."), - LOAD_TASK_NOT_SCHEDULED("citizens.load-task-error", "NPC load task couldn't be scheduled - disabling..."), - LOADING_SUB_PLUGIN("citizens.sub-plugins.load", "Loading {0}"), - LOCALE_NOTIFICATION("citizens.notifications.locale", "Using locale {0}."), - METRICS_ERROR_NOTIFICATION("citizens.notifications.metrics-load-error", "Unable to start metrics: {0}."), - METRICS_NOTIFICATION("citizens.notifications.metrics-started", "Metrics started."), - UNKNOWN_COMMAND("citizens.commands.unknown-command", "Unknown command. Did you mean:"); - private String defaultTranslation; - private String key; - - Messages(String key, String defaultTranslation) { - this.key = key; - this.defaultTranslation = defaultTranslation; - } - - public String getKey() { - return key; - } - +public class Messages { + public static final String CITIZENS_DISABLED = "citizens.notifications.disabled"; + public static final String CITIZENS_ENABLED = "citizens.notifications.enabled"; + public static final String CITIZENS_IMPLEMENTATION_DISABLED = "citizens.changed-implementation"; + public static final String CITIZENS_INCOMPATIBLE = "citizens.notifications.incompatible-version"; + public static final String COMMAND_ID_NOT_FOUND = "citizens.commands.id-not-found"; + public static final String COMMAND_INVALID_MOB_TYPE = "citizens.commands.disallowed-mobtype"; + public static final String COMMAND_INVALID_NUMBER = "citizens.commands.invalid-number"; + public static final String COMMAND_MUST_BE_INGAME = "citizens.commands.must-be-ingame"; + public static final String COMMAND_MUST_BE_OWNER = "citizens.commands.must-be-owner"; + public static final String COMMAND_MUST_HAVE_SELECTED = "citizens.commands.must-have-selected"; + public static final String COMMAND_REPORT_ERROR = "citizens.commands.console-error"; + public static final String DATABASE_CONNECTION_FAILED = "citizens.notifications.database-connection-failed"; private static ResourceBundle defaultBundle; + public static final String ERROR_INITALISING_SUB_PLUGIN = "citizens.sub-plugins.error-on-load"; + public static final String ERROR_LOADING_ECONOMY = "citizens.economy.error-loading"; + public static final String FAILED_LOAD_SAVES = "citizens.saves.load-failed"; + public static final String LOAD_NAME_NOT_FOUND = "citizens.notifications.npc-name-not-found"; + public static final String LOAD_TASK_NOT_SCHEDULED = "citizens.load-task-error"; + public static final String LOAD_UNKNOWN_NPC_TYPE = "citizens.notifications.unknown-npc-type"; + public static final String LOADING_SUB_PLUGIN = "citizens.sub-plugins.load"; + public static final String LOCALE_NOTIFICATION = "citizens.notifications.locale"; + public static final String METRICS_ERROR_NOTIFICATION = "citizens.notifications.metrics-load-error"; + public static final String METRICS_NOTIFICATION = "citizens.notifications.metrics-started"; + public static final String MINIMUM_COST_REQUIRED = "citizens.economy.minimum-cost-required-message"; + public static final String MONEY_WITHDRAWN = "citizens.economy.money-withdrawn"; + public static final String NUM_LOADED_NOTIFICATION = "citizens.notifications.npcs-loaded"; + public static final String OVER_NPC_LIMIT = "citizens.limits.over-npc-limit"; + public static final String SAVE_METHOD_SET_NOTIFICATION = "citizens.notifications.save-method-set"; + public static final String UNKNOWN_COMMAND = "citizens.commands.unknown-command"; + public static final String WRITING_DEFAULT_SETTING = "citizens.settings.writing-default"; + + private static Properties getDefaultBundleProperties() { + Properties defaults = new Properties(); + InputStream in = null; + try { + in = Messages.class.getResourceAsStream("/" + Translator.PREFIX + "_en.properties"); + defaults.load(in); + } catch (IOException e) { + } finally { + Closeables.closeQuietly(in); + } + return defaults; + } public static ResourceBundle getDefaultResourceBundle(File resourceDirectory, String fileName) { if (defaultBundle == null) { resourceDirectory.mkdirs(); File bundleFile = new File(resourceDirectory, fileName); - if (!bundleFile.exists()) + if (!bundleFile.exists()) { try { bundleFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } + } populateDefaults(bundleFile); FileInputStream stream = null; try { @@ -72,20 +90,14 @@ public enum Messages { return new ListResourceBundle() { @Override protected Object[][] getContents() { - Messages[] values = values(); - Object[][] contents = new Object[values.length][2]; - for (int i = 0; i < values.length; i++) { - Messages message = values[i]; - contents[i] = new Object[] { message.key, message.defaultTranslation }; - } - return contents; + return new Object[0][0]; } }; } private static void populateDefaults(File bundleFile) { Properties properties = new Properties(); - FileInputStream in = null; + InputStream in = null; try { in = new FileInputStream(bundleFile); properties.load(in); @@ -93,13 +105,15 @@ public enum Messages { } finally { Closeables.closeQuietly(in); } - for (Messages message : values()) { - if (!properties.containsKey(message.key)) - properties.put(message.key, message.defaultTranslation); + Properties defaults = getDefaultBundleProperties(); + for (Entry entry : defaults.entrySet()) { + if (!properties.containsKey(entry.getKey())) + properties.put(entry.getKey(), entry.getValue()); } OutputStream stream = null; try { - properties.store(stream = new FileOutputStream(bundleFile), ""); + stream = new FileOutputStream(bundleFile); + properties.store(stream, ""); } catch (Exception e) { e.printStackTrace(); } finally { diff --git a/src/main/java/net/citizensnpcs/util/Messaging.java b/src/main/java/net/citizensnpcs/util/Messaging.java index 2f88025a0..11016f9bf 100644 --- a/src/main/java/net/citizensnpcs/util/Messaging.java +++ b/src/main/java/net/citizensnpcs/util/Messaging.java @@ -46,7 +46,7 @@ public class Messaging { log(getFormatted(msg)); } - public static void logTr(Messages key, Object... msg) { + public static void logTr(String key, Object... msg) { log(Level.INFO, Translator.tr(key, msg)); } @@ -62,7 +62,7 @@ public class Messaging { sendF(sender, ChatColor.RED.toString() + SPACE.join(msg)); } - public static void sendErrorTr(CommandSender sender, Messages key, Object... msg) { + public static void sendErrorTr(CommandSender sender, String key, Object... msg) { sendMessageTo(sender, ChatColor.RED + Translator.tr(key, msg)); } @@ -75,7 +75,7 @@ public class Messaging { sender.sendMessage(msg); } - public static void sendTr(CommandSender sender, Messages key, Object... msg) { + public static void sendTr(CommandSender sender, String key, Object... msg) { sendMessageTo(sender, Translator.tr(key, msg)); } @@ -102,7 +102,11 @@ public class Messaging { log(Level.SEVERE, getFormatted(messages)); } - public static void severeTr(Messages key, Object... messages) { + public static void severeTr(String key, Object... messages) { log(Level.SEVERE, Translator.tr(key, messages)); } + + public static String tr(String key, Object... messages) { + return Translator.tr(key, messages); + } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/util/NMS.java b/src/main/java/net/citizensnpcs/util/NMS.java index d9f2fa379..5191cc952 100644 --- a/src/main/java/net/citizensnpcs/util/NMS.java +++ b/src/main/java/net/citizensnpcs/util/NMS.java @@ -42,6 +42,7 @@ public class NMS { private static Field PATHFINDING_RANGE; private static Field SPEED_FIELD; private static Field THREAD_STOPPER; + public static void attack(EntityLiving handle, EntityLiving target) { handle.k(target); } @@ -54,6 +55,7 @@ public class NMS { List list = (List) NMS.GOAL_FIELD.get(selector); list.clear(); } catch (Exception e) { + Messaging.logF("Could not clear goals: %s", e.getMessage()); } } } @@ -76,6 +78,7 @@ public class NMS { f = clazz.getDeclaredField(field); f.setAccessible(true); } catch (Exception e) { + Messaging.logF("Could not fetch field %s: %s.", field, e.getMessage()); } return f; } @@ -134,8 +137,8 @@ public class NMS { return; try { LAND_SPEED_MODIFIER_FIELD.setFloat(handle, speed); - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) { + } catch (Exception e) { + Messaging.logF("Could not update land speed modifier: %s.", e.getMessage()); } } @@ -147,7 +150,7 @@ public class NMS { Constructor constructor = getCustomEntityConstructor(clazz, type); entity = constructor.newInstance(handle); } catch (Exception e) { - e.printStackTrace(); + Messaging.logF("Could not spawn custom entity: %s.", e.getMessage()); return null; } handle.addEntity(entity); @@ -161,6 +164,7 @@ public class NMS { try { THREAD_STOPPER.set(manager, false); } catch (Exception e) { + Messaging.logF("Could not stop network threads: %s.", e.getMessage()); } } @@ -179,6 +183,7 @@ public class NMS { try { NAVIGATION_WORLD_FIELD.set(handle.getNavigation(), worldHandle); } catch (Exception e) { + Messaging.logF("Could not update navigation world: %s.", e.getMessage()); } } @@ -188,8 +193,8 @@ public class NMS { Navigation navigation = npc.getHandle().getNavigation(); try { PATHFINDING_RANGE.set(navigation, pathfindingRange); - } catch (Exception ex) { - Messaging.logF("Could not update pathfinding range: %s.", ex.getMessage()); + } catch (Exception e) { + Messaging.logF("Could not update pathfinding range: %s.", e.getMessage()); } } @@ -218,12 +223,11 @@ public class NMS { try { Field field = getField(EntityTypes.class, "d"); - field.setAccessible(true); ENTITY_INT_TO_CLASS = (Map>) field.get(null); field = getField(EntityTypes.class, "e"); - field.setAccessible(true); ENTITY_CLASS_TO_INT = (Map, Integer>) field.get(null); } catch (Exception e) { + Messaging.logF("Could not fetch entity id mapping fields: %s", e.getMessage()); } } } diff --git a/src/main/java/net/citizensnpcs/util/Translator.java b/src/main/java/net/citizensnpcs/util/Translator.java index 5c66ff433..dc01d2f0c 100644 --- a/src/main/java/net/citizensnpcs/util/Translator.java +++ b/src/main/java/net/citizensnpcs/util/Translator.java @@ -94,16 +94,13 @@ public class Translator { private static Translator instance; public static final String PREFIX = "messages"; + public static void setInstance(File resourceFile, Locale locale) { instance = new Translator(resourceFile, locale); } - public static String tr(Messages key) { - return tr(key.getKey()); - } - - public static String tr(Messages key, Object... msg) { - return tr(key.getKey(), msg); + public static String tr(String key) { + return tr(key); } public static String tr(String key, Object... msg) { diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties new file mode 100644 index 000000000..6d217b4b5 --- /dev/null +++ b/src/main/resources/messages_en.properties @@ -0,0 +1,29 @@ +citizens.changed-implementation=Citizens implementation changed=disabling plugin. +citizens.commands.console-error=Please report this error: [See console] +citizens.commands.invalid-number=That is not a valid number. +citizens.commands.must-be-ingame=You must be ingame to use that command. +citizens.commands.unknown-command=Unknown command. Did you mean: +citizens.commands.id-not-found=Couldn't find any NPC with ID {0}. +citizens.commands.disallowed-mobtype=The NPC cannot be the mob type '{0}' to use that command. +citizens.commands.must-have-selected=You must have an NPC selected to execute that command. +citizens.commands.must-be-owner=You must be the owner of this NPC to execute that command. +citizens.economy.error-loading=Unable to use economy handling. Has Vault been enabled? +citizens.economy.minimum-cost-required-message=Need at least {0}. +citizens.economy.money-withdrawn=Withdrew {0} for your NPC. +citizens.limits.over-npc-limt=Over the NPC limit of {0}. +citizens.load-task-error=NPC load task couldn't be scheduled - disabling... +citizens.saves.load-failed=Unable to load saves=disabling... +citizens.sub-plugins.load=Loading {0} +citizens.sub-plugins.error-on-load={0} initializing {1} +citizens.settings.writing-default=Writing default setting: '{0}' +citizens.notifications.enabled=v{0} enabled. +citizens.notifications.disabled=v{0} disabled. +citizens.notifications.incompatible-version=v{0} is not compatible with Minecraft v{1}. Disabling. +citizens.notifications.locale=Using locale {0}. +citizens.notifications.metrics-load-error=Unable to start metrics: {0}. +citizens.notifications.metrics-started=Metrics started. +citizens.notifications.npc-name-not-found=Could not find a name for ID '{0}'. +citizens.notifications.npc-loaded=Loaded {0} NPCs ({1} spawned). +citizens.notifications.save-method-set=Save method set to {0}. +citizens.notifications.database-connection-failed=Unable to connect to database, falling back to YAML +citizens.notifications.unknown-npc-type=NPC type '{0}' was not recognized. Did you spell it correctly? \ No newline at end of file