diff --git a/src/main/kotlin/net/trivernis/chunkmaster/Chunkmaster.kt b/src/main/kotlin/net/trivernis/chunkmaster/Chunkmaster.kt index 55459bf..91bf6e7 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/Chunkmaster.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/Chunkmaster.kt @@ -74,7 +74,7 @@ class Chunkmaster: JavaPlugin() { config.addDefault("generation.max-loaded-chunks", 10) config.addDefault("generation.ignore-worldborder", false) config.addDefault("database.filename", "chunkmaster.db") - config.addDefault("language", "EN") + config.addDefault("language", "en") config.options().copyDefaults(true) saveConfig() } diff --git a/src/main/kotlin/net/trivernis/chunkmaster/commands/CmdGenerate.kt b/src/main/kotlin/net/trivernis/chunkmaster/commands/CmdGenerate.kt index 9ea4dde..8d07447 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/commands/CmdGenerate.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/commands/CmdGenerate.kt @@ -79,8 +79,7 @@ class CmdGenerate(private val chunkmaster: Chunkmaster): Subcommand { stopAfter = getStopAfter(stopAfter, args[2]) } } else { - sender.spigot().sendMessage( - *ComponentBuilder("You need to provide a world name").color(ChatColor.RED).create()) + sender.sendMessage(chunkmaster.langManager.getLocalized("WORLD_NAME_REQUIRED")) return false } } @@ -126,7 +125,7 @@ class CmdGenerate(private val chunkmaster: Chunkmaster): Subcommand { .append(worldName).color(ChatColor.GREEN).append(" not found!").color(ChatColor.RED).create()) false } else { - sender.spigot().sendMessage(*ComponentBuilder("Task already exists!").color(ChatColor.RED).create()) + sender.sendMessage(chunkmaster.langManager.getLocalized("TASK_ALREADY_EXISTS", worldName)) return false } } diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/LanguageManager.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/LanguageManager.kt index 2e4923e..e72d2e5 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/lib/LanguageManager.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/LanguageManager.kt @@ -3,19 +3,23 @@ import net.trivernis.chunkmaster.Chunkmaster import java.io.File import java.lang.Exception import java.util.Properties -import java.util.logging.Level class LanguageManager(private val plugin: Chunkmaster) { private val langProps = Properties() private val languageFolder = "${plugin.dataFolder.absolutePath}/i18n" private var langFileLoaded = false + /** + * Loads the default properties file and then the language specific ones. + * If no lang-specific file is found in the plugins directory under i18n an attempt is made to + * load the file from inside the jar in i18n. + */ fun loadProperties() { val language = plugin.config.getString("language") val langFile = "$languageFolder/$language.i18n.properties" val file = File(langFile) val loader = Thread.currentThread().contextClassLoader - val defaultStream = this.javaClass.getResourceAsStream("/DEFAULT.i18n.properties") + val defaultStream = this.javaClass.getResourceAsStream("/i18n/DEFAULT.i18n.properties") if (defaultStream != null) { langProps.load(defaultStream) defaultStream.close() @@ -35,11 +39,22 @@ class LanguageManager(private val plugin: Chunkmaster) { plugin.logger.fine(e.toString()) } } else { - plugin.logger.warning("Language File $langFile could not be found!") + val inputStream = this.javaClass.getResourceAsStream("/i18n/$language.i18n.properties") + if (inputStream != null) { + langProps.load(inputStream) + langFileLoaded = true + inputStream.close() + } else { + plugin.logger.warning("Language File $langFile could not be found!") + } } } - fun getLocalized(key: String) { - langProps.getProperty(key) + /** + * Returns a localized message with replacements + */ + fun getLocalized(key: String, vararg replacements: Any): String { + val localizedString = langProps.getProperty(key) + return String.format(localizedString, *replacements) } } \ No newline at end of file diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationManager.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationManager.kt index ee5fa6d..81b69ab 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationManager.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationManager.kt @@ -55,7 +55,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server } generationTask.onEndReached { - chunkmaster.logger.info("Task #${id} finished after ${it.count} chunks.") + chunkmaster.logger.info(chunkmaster.langManager.getLocalized("TASK_FINISHED", id, it.count)) removeTask(id) } @@ -86,7 +86,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server stopAfter: Int = -1 ) { if (!paused) { - chunkmaster.logger.info("Resuming chunk generation task for world \"${world.name}\"") + chunkmaster.logger.info(chunkmaster.langManager.getLocalized("RESUME_FOR_WORLD", world.name)) val generationTask = createGenerationTask(world, center, last, stopAfter) val task = server.scheduler.runTaskTimer( chunkmaster, generationTask, 200, // 10 sec delay @@ -94,7 +94,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server ) tasks.add(RunningTaskEntry(id, task, generationTask)) generationTask.onEndReached { - chunkmaster.logger.info("Task #${id} finished after ${generationTask.count} chunks.") + chunkmaster.logger.info(chunkmaster.langManager.getLocalized("TASK_FINISHED", id, generationTask.count)) removeTask(id) } } @@ -134,7 +134,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server * Loads tasks from the database and resumes them */ fun init() { - chunkmaster.logger.info("Creating task to load chunk generation Tasks later...") + chunkmaster.logger.info(chunkmaster.langManager.getLocalized("CREATE_DELAYED_LOAD")) server.scheduler.runTaskTimer(chunkmaster, Runnable { saveProgress() // save progress every 30 seconds }, 600, 600) @@ -157,7 +157,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server if (task.task.isCancelled) { removalSet.add(task) } - chunkmaster.logger.info("Canceled task #${task.id}") + chunkmaster.logger.info(chunkmaster.langManager.getLocalized("TASK_CANCELED", task.id)) } tasks.removeAll(removalSet) } @@ -178,13 +178,13 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server resumeTask(world!!, center, last, id, stopAfter) } } catch (error: NullPointerException) { - chunkmaster.logger.severe("Failed to load Task ${res.getInt("id")}.") + chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("TASK_LOAD_FAILED", res.getInt("id"))) } } } if (tasks.isNotEmpty()) { - chunkmaster.logger.info("${tasks.size} saved tasks loaded.") + chunkmaster.logger.info(chunkmaster.langManager.getLocalized("TASK_LOAD_SUCCESS", tasks.size)) } } @@ -215,16 +215,18 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server for (task in tasks) { try { val genTask = task.generationTask - chunkmaster.logger.info( - """Task #${task.id} running for "${genTask.world.name}". - |Progress ${task.generationTask.count} chunks - |${if (task.generationTask.stopAfter > 0) "(${"%.2f".format( - (task.generationTask.count.toDouble() / - task.generationTask.stopAfter.toDouble()) * 100 - )}%)" else ""}. - | Speed: ${"%.1f".format(task.generationSpeed)} chunks/sec, - |Last Chunk: ${genTask.lastChunk.x}, ${genTask.lastChunk.z}""".trimMargin("|").replace('\n', ' ') - ) + val percentage = if (genTask.stopAfter > 0) "(${"%.2f".format( + (genTask.count.toDouble() / genTask.stopAfter.toDouble()) * 100 + )}%)" else "" + chunkmaster.logger.info(chunkmaster.langManager.getLocalized( + "TASK_PERIODIC_REPORT", + task.id, + genTask.world.name, + genTask.count, + percentage, + task.generationSpeed!!, + genTask.lastChunk.x, + genTask.lastChunk.z)) chunkmaster.sqliteManager.executeStatement( """ UPDATE generation_tasks SET last_x = ?, last_z = ? @@ -234,7 +236,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server null ) } catch (error: Exception) { - chunkmaster.logger.warning("Exception when saving task progress ${error.message}") + chunkmaster.logger.warning(chunkmaster.langManager.getLocalized("TASK_SAVE_FAILED", error.toString())) } } } diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTask.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTask.kt index d089772..92f3ea5 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTask.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTask.kt @@ -4,13 +4,11 @@ import net.trivernis.chunkmaster.Chunkmaster import net.trivernis.chunkmaster.lib.Spiral import org.bukkit.Chunk import org.bukkit.World - /** * Interface for generation tasks. */ abstract class GenerationTask(plugin: Chunkmaster, centerChunk: ChunkCoordinates, startChunk: ChunkCoordinates) : Runnable { - abstract val stopAfter: Int abstract val world: World abstract val count: Int diff --git a/src/main/resources/DEFAULT.i18n.properties b/src/main/resources/DEFAULT.i18n.properties deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/resources/i18n/DEFAULT.i18n.properties b/src/main/resources/i18n/DEFAULT.i18n.properties new file mode 100644 index 0000000..0376e0b --- /dev/null +++ b/src/main/resources/i18n/DEFAULT.i18n.properties @@ -0,0 +1,11 @@ +RESUME_FOR_WORLD = Resuming chunk generation task for world '%s'... +TASK_FINISHED = Task #%d finished after %d chunks. +TASK_CANCELED = Canceled task #%d. +TASK_LOAD_FAILED = Failed to load task #%d. +TASK_LOAD_SUCCESS = %d saved tasks loaded. +TASK_PERIODIC_REPORT = Task #%d running for '%s'. Progress: %d chunks %s, Speed: %.1f ch/s, Last Chunk: %d, %d +TASK_SAVE_FAILED = Exception when saving tasks: %s +CREATE_DELAYED_LOAD = Creating task to load chunk generation Tasks later... + +WORLD_NAME_REQUIRED = \u00A7cYou need to provide a world name! +TASK_ALREADY_EXISTS = \u00A7cA task for '%s' already exists! \ No newline at end of file diff --git a/src/main/resources/i18n/de.i18n.properties b/src/main/resources/i18n/de.i18n.properties new file mode 100644 index 0000000..4d55794 --- /dev/null +++ b/src/main/resources/i18n/de.i18n.properties @@ -0,0 +1,11 @@ +RESUME_FOR_WORLD = Setze das Chunk-Generieren für Welt '%s' fort... +TASK_FINISHED = Aufgabe #%d wurde nach %d chunks beendet. +TASK_CANCELED = Aufgabe #%d wurde abgebrochen. +TASK_LOAD_FAILED = Aufgabe #%d konnte nicht geladen werden. +TASK_LOAD_SUCCESS = %d gespeicherte Aufgaben wurden geladen. +CREATE_DELAYED_LOAD = Erstelle einen Bukkit-Task zum verzögerten Laden von Aufgaben... +TASK_PERIODIC_REPORT = Aufgabe #%d für Welt '%s'. Fortschritt: %d chunks %s, Geschwindigkeit: %.1f ch/s, Letzer Chunk: %d, %d +TASK_SAVE_FAILED = Exception beim Speichern der Aufgaben: %s + +WORLD_NAME_REQUIRED = \u00A7cDu musst einen Weltennamen angeben! +TASK_ALREADY_EXISTS = \u00A7cEs existiert bereits eine Aufgabe für '%s'! \ No newline at end of file diff --git a/src/main/resources/i18n/en.i18n.properties b/src/main/resources/i18n/en.i18n.properties new file mode 100644 index 0000000..0376e0b --- /dev/null +++ b/src/main/resources/i18n/en.i18n.properties @@ -0,0 +1,11 @@ +RESUME_FOR_WORLD = Resuming chunk generation task for world '%s'... +TASK_FINISHED = Task #%d finished after %d chunks. +TASK_CANCELED = Canceled task #%d. +TASK_LOAD_FAILED = Failed to load task #%d. +TASK_LOAD_SUCCESS = %d saved tasks loaded. +TASK_PERIODIC_REPORT = Task #%d running for '%s'. Progress: %d chunks %s, Speed: %.1f ch/s, Last Chunk: %d, %d +TASK_SAVE_FAILED = Exception when saving tasks: %s +CREATE_DELAYED_LOAD = Creating task to load chunk generation Tasks later... + +WORLD_NAME_REQUIRED = \u00A7cYou need to provide a world name! +TASK_ALREADY_EXISTS = \u00A7cA task for '%s' already exists! \ No newline at end of file