From 1f00a32750175bb6ef99b0ea154f66b9ed14eb57 Mon Sep 17 00:00:00 2001 From: alexcrea Date: Thu, 13 Aug 2026 01:51:03 +0200 Subject: [PATCH] language backend logic --- src/main/kotlin/io/delilaheve/CustomAnvil.kt | 30 ++++-- .../cuanvil/command/ReloadExecutor.kt | 4 + .../kotlin/xyz/alexcrea/cuanvil/lang/Lang.kt | 93 +++++++++++++++++++ .../xyz/alexcrea/cuanvil/lang/Language.kt | 56 +++++++++++ src/main/resources/config.yml | 5 + 5 files changed, 179 insertions(+), 9 deletions(-) create mode 100644 src/main/kotlin/xyz/alexcrea/cuanvil/lang/Lang.kt create mode 100644 src/main/kotlin/xyz/alexcrea/cuanvil/lang/Language.kt diff --git a/src/main/kotlin/io/delilaheve/CustomAnvil.kt b/src/main/kotlin/io/delilaheve/CustomAnvil.kt index a119bfc7..c88acfd3 100644 --- a/src/main/kotlin/io/delilaheve/CustomAnvil.kt +++ b/src/main/kotlin/io/delilaheve/CustomAnvil.kt @@ -17,6 +17,7 @@ import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry import xyz.alexcrea.cuanvil.gui.config.MainConfigGui import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant +import xyz.alexcrea.cuanvil.lang.Lang import xyz.alexcrea.cuanvil.listener.AnvilCloseListener import xyz.alexcrea.cuanvil.listener.AnvilResultListener import xyz.alexcrea.cuanvil.listener.ChatEventListener @@ -135,6 +136,25 @@ open class CustomAnvil : JavaPlugin() { */ override fun onEnable() { instance = this + // Load default configuration + try { + if(!ConfigHolder.loadDefaultConfig()) + throw RuntimeException("Error loading configuration file") + } catch (e: Exception) { + logger.log(Level.SEVERE, "error occurred loading default configuration", e) + MetricsUtil.trackError(e) + if(tryDirtyStart()) return + } + + // Load language + try { + Lang.reload() + } catch (e: Exception) { + logger.log(Level.SEVERE, "error occurred loading language file", e) + MetricsUtil.trackError(e) + if(tryDirtyStart()) return + } + try { legacyCheck() } catch (e: Exception) { @@ -143,6 +163,7 @@ open class CustomAnvil : JavaPlugin() { if(trySafeStart()) return } + // Add commands try { CustomAnvilCommand(this) @@ -152,15 +173,6 @@ open class CustomAnvil : JavaPlugin() { if(trySafeStart()) return } - // Load default configuration - try { - if(!ConfigHolder.loadDefaultConfig()) - throw RuntimeException("Error loading configuration file") - } catch (e: Exception) { - logger.log(Level.SEVERE, "error occurred loading default configuration", e) - MetricsUtil.trackError(e) - if(tryDirtyStart()) return - } // Load dependency try { diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/command/ReloadExecutor.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/command/ReloadExecutor.kt index d3df341a..bc9a80be 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/command/ReloadExecutor.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/command/ReloadExecutor.kt @@ -8,6 +8,7 @@ import xyz.alexcrea.cuanvil.api.event.CAConfigReadyEvent import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.dependency.DependencyManager import xyz.alexcrea.cuanvil.gui.config.global.* +import xyz.alexcrea.cuanvil.lang.Lang import xyz.alexcrea.cuanvil.update.UpdateHandler class ReloadExecutor : CASubCommand { @@ -58,6 +59,9 @@ class ReloadExecutor : CASubCommand { try { if (!ConfigHolder.reloadAllFromDisk(hardfail)) return false + // reload language config + Lang.reload() + // Then update all global gui containing value from config BasicConfigGui.getInstance()?.updateGuiValues() EnchantCostConfigGui.getInstance()?.updateGuiValues() diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/lang/Lang.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/lang/Lang.kt new file mode 100644 index 00000000..b89ca6bd --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/lang/Lang.kt @@ -0,0 +1,93 @@ +package xyz.alexcrea.cuanvil.lang + +import io.delilaheve.CustomAnvil +import xyz.alexcrea.cuanvil.config.ConfigHolder + +object Lang { + + private val default = Language(DEFAULT_LANG, false) + private var lang = default + + fun reload() { + val langID = langID + if(lang.name == langID && lang != default) + lang.reload() + else + lang = Language(langID) + + if(default != lang) default.reload() + } + + fun String.translate(): String { + val value = lang.get(this) + if(value != null) return value + + CustomAnvil.log("Missing language data for ${lang.name} using default") + + return default.get(this) ?: this + } + + fun String.translate(vararg params: Pair): String { + return translate( + params.asSequence() + .map { Pair(it.first, it.second.toString()) } + .toMap() + ) + } + + fun String.translate(vararg params: Pair): String { + return translate( + params.asSequence() + .map { Pair(it.first.toString(), it.second.toString()) } + .toMap() + ) + } + + fun String.translate(vararg params: Pair): String { + return translate(params.toMap()) + } + + fun String.translate(vararg params: Pair): String { + return translate( + params.asSequence() + .map { Pair(it.first.toString(), it.second) } + .toMap() + ) + } + + fun String.translate(params: Map): String { + val builder = StringBuilder(translate()) + + // replace all placeholder thingy %key -> value + for((key, replacement) in params) { + var current = 0 + while(true) { + current = builder.indexOf('%', current) + 1 + if(current < 0 || current + key.length > builder.length) break // may be able to be removed if bound checked in startsWith ? + if(!builder.startsWith(key, current, false)) continue + + builder.replace(current - 1, current + key.length, replacement) + current = current - 1 + replacement.length + } + } + + return builder.toString() + } + + /* + * Config Options & get + */ + const val LANG_PATH = "language" + const val DEFAULT_LANG = "en" + + /** + * Value of an item rename + */ + private val langID: String + get() { + return ConfigHolder.DEFAULT_CONFIG + .config + .getString(LANG_PATH, DEFAULT_LANG)!! + } + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/lang/Language.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/lang/Language.kt new file mode 100644 index 00000000..d06f9aba --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/lang/Language.kt @@ -0,0 +1,56 @@ +package xyz.alexcrea.cuanvil.lang + +import io.delilaheve.CustomAnvil +import org.bukkit.configuration.file.FileConfiguration +import org.bukkit.configuration.file.YamlConfiguration +import java.io.File +import java.io.InputStreamReader +import java.util.logging.Level + + +class Language(private val id: String, private val default: Boolean = false) { + + private val resourcePath: String + private val file: File + + private val conf: FileConfiguration + + init { + conf = YamlConfiguration() + resourcePath = "lang/$id.yml" + file = File(CustomAnvil.instance.dataFolder, resourcePath) + + reload() + } + + fun reload() { + if(file.exists() && !default) try { + conf.load(file) + return + } catch(e: Exception) { + CustomAnvil.instance.logger.log( + Level.SEVERE, + "Could not load custom Anvil config file. using to internal resource", + e + ) + } + + loadInternalResource() + } + + private fun loadInternalResource() { + val input = CustomAnvil.instance.getResource(resourcePath) + if(input != null) + conf.load(InputStreamReader(input)) + else + CustomAnvil.instance.logger.log(Level.SEVERE, "Language $id not found") + + } + + fun get(key: String): String? { + return conf.getString(key) + } + + val name: String + get() = conf.getString("name", id)!! +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 218c3a1f..f67ebb17 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -16,6 +16,11 @@ metric_type: auto # Accept true or false (true by default) metric_collect_errors: true +# Which language should the plugin should be +# If you like to add language yourself see TODO link to guide +# Currently available languages: en +language: en + # All anvil cost will be capped to limit_repair_value if enabled. # # In other words: