mirror of
https://github.com/alexcrea/CustomAnvil.git
synced 2026-08-28 08:25:56 +02:00
better translation system
This commit is contained in:
parent
c636767078
commit
cb6040df10
11 changed files with 257 additions and 83 deletions
|
|
@ -2,7 +2,7 @@ package xyz.alexcrea.cuanvil.dependency.util
|
|||
|
||||
import net.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.inventory.meta.ItemMeta
|
||||
|
||||
// Mostly made for paper, spigot and folia support
|
||||
|
|
@ -100,4 +100,19 @@ object PlatformUtil {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to send paper component to the player
|
||||
*
|
||||
* @param component The used component
|
||||
* @return true if sent, else otherwise
|
||||
*/
|
||||
fun CommandSender.sendPaperMessage(component: Component): Boolean {
|
||||
if(isPaper) {
|
||||
this.sendMessage(component)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,7 +16,8 @@ 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.lang.Lang.translate
|
||||
import xyz.alexcrea.cuanvil.lang.MsgError
|
||||
import xyz.alexcrea.cuanvil.lang.MsgWarning
|
||||
import xyz.alexcrea.cuanvil.listener.AnvilCloseListener
|
||||
import xyz.alexcrea.cuanvil.listener.AnvilResultListener
|
||||
import xyz.alexcrea.cuanvil.listener.ChatEventListener
|
||||
|
|
@ -111,12 +112,12 @@ open class CustomAnvil : JavaPlugin() {
|
|||
/**
|
||||
* Error Logging handler
|
||||
*/
|
||||
@JvmStatic fun logError(message: String, throwable: Throwable? = null, track: Boolean = true) {
|
||||
instance.logger.log(Level.SEVERE, message, throwable)
|
||||
addToLogQueue(message)
|
||||
@JvmStatic fun logError(message: String, throwable: Throwable? = null, track: Boolean = true, level: Level = Level.SEVERE) {
|
||||
instance.logger.log(level, message, throwable)
|
||||
addToLogQueue("Error: $message")
|
||||
|
||||
if(track && throwable != null) {
|
||||
MetricsUtil.trackError(throwable)
|
||||
if(track) {
|
||||
MetricsUtil.trackError(message, throwable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -168,7 +169,7 @@ open class CustomAnvil : JavaPlugin() {
|
|||
try {
|
||||
legacyCheck()
|
||||
} catch (e: Exception) {
|
||||
logError("error.load.legacy.failed".translate(), e)
|
||||
MsgError.LOAD_LEGACY_FAILED.log(e)
|
||||
if(trySafeStart()) return
|
||||
}
|
||||
|
||||
|
|
@ -177,7 +178,7 @@ open class CustomAnvil : JavaPlugin() {
|
|||
try {
|
||||
CustomAnvilCommand(this)
|
||||
} catch (e: Exception) {
|
||||
logError("error.load.command-register".translate(), e)
|
||||
MsgError.LOAD_COMMAND_REGISTER.log(e)
|
||||
if(trySafeStart()) return
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +187,7 @@ open class CustomAnvil : JavaPlugin() {
|
|||
try {
|
||||
DependencyManager.loadDependency()
|
||||
} catch (e: Exception) {
|
||||
logError("error.load.compatibility".translate(), e)
|
||||
MsgError.LOAD_COMPATIBILITY.log(e)
|
||||
if(tryDirtyStart()) return
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +195,7 @@ open class CustomAnvil : JavaPlugin() {
|
|||
try {
|
||||
registerListeners()
|
||||
} catch (e: Exception) {
|
||||
logError("error.load.listeners".translate(), e)
|
||||
MsgError.LOAD_LISTENERS.log(e)
|
||||
if(tryDirtyStart()) return
|
||||
}
|
||||
|
||||
|
|
@ -215,18 +216,15 @@ open class CustomAnvil : JavaPlugin() {
|
|||
val potentialPlugin = Bukkit.getPluginManager().getPlugin("UnsafeEnchantsPlus")
|
||||
if (potentialPlugin != null) {
|
||||
Bukkit.getPluginManager().disablePlugin(potentialPlugin)
|
||||
logger.warning("warning.load.legacy.old-name.1".translate())
|
||||
logger.warning("warning.load.legacy.old-name.2".translate())
|
||||
MsgWarning.LOAD_LEGACY_OLD_NAME.log()
|
||||
}
|
||||
|
||||
val isPaper = PlatformUtil.isPaper
|
||||
if(!isPaper) {
|
||||
logger.warning("warning.load.legacy.spigot.1".translate())
|
||||
logger.warning("warning.load.legacy.spigot.2".translate())
|
||||
if(MinecraftVersionUtil.isTooNewForSpigot) {
|
||||
logger.warning("warning.load.legacy.spigot-old.1".translate())
|
||||
logger.warning("warning.load.legacy.spigot-old.1".translate())
|
||||
}
|
||||
MsgWarning.LOAD_LEGACY_SPIGOT.log()
|
||||
if(MinecraftVersionUtil.isTooNewForSpigot)
|
||||
MsgWarning.LOAD_LEGACY_SPIGOT_OLD.log()
|
||||
|
||||
}
|
||||
|
||||
val loader = if(isPaper) "paper" else "spigot"
|
||||
|
|
@ -238,13 +236,13 @@ open class CustomAnvil : JavaPlugin() {
|
|||
UpdateUtils.currentMinecraftVersion().toString())
|
||||
.setFeatured(featured)
|
||||
.setOnError {
|
||||
logger.log(Level.WARNING, "error.load.update.check-fail".translate(), it)
|
||||
MsgError.LOAD_UPDATE_CHECK_FAIL.log(it, level = Level.WARNING, track = false)
|
||||
}
|
||||
.checkVersion { latestVer: String? ->
|
||||
CustomAnvil.latestVer = latestVer
|
||||
if(latestVer == null || version.contains(latestVer)) return@checkVersion
|
||||
|
||||
logger.warning("warning.load.update.available".translate(Pair("version", latestVer)))
|
||||
MsgWarning.LOAD_UPDATE_AVAILABLE.log(latestVer)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,7 +261,7 @@ open class CustomAnvil : JavaPlugin() {
|
|||
try {
|
||||
loadEnchantmentSystem()
|
||||
} catch (e: Exception) {
|
||||
logError("error.load.enchant-system".translate(), e)
|
||||
MsgError.LOAD_ENCHANT_SYSTEM.log(e)
|
||||
tryDirtyStart()
|
||||
}
|
||||
}
|
||||
|
|
@ -278,7 +276,7 @@ open class CustomAnvil : JavaPlugin() {
|
|||
|
||||
// Load config
|
||||
if (!ConfigHolder.loadNonDefaultConfig()) {
|
||||
logError("error.load.non-default-config".translate())
|
||||
MsgError.LOAD_NON_DEFAULT_CONFIG.log()
|
||||
server.pluginManager.disablePlugin(this)
|
||||
return
|
||||
}
|
||||
|
|
@ -332,16 +330,15 @@ open class CustomAnvil : JavaPlugin() {
|
|||
try {
|
||||
val configReader = FileReader(resourceFile)
|
||||
yamlConfig.load(configReader)
|
||||
} catch (_: Exception) {
|
||||
} catch (e: Exception) {
|
||||
MsgError.RELOAD_FAIL.log(e, resourceFile.path)
|
||||
if (hardFailSafe) {
|
||||
// This is important and may impact gameplay if it does not load.
|
||||
// Failsafe is to stop the plugin
|
||||
logError("error.reload.resource.fail".translate(Pair("path", resourceFile.path)))
|
||||
logError("error.reload.resource.hard-fail".translate())
|
||||
MsgError.RELOAD_HARD_FAIL.log()
|
||||
Bukkit.getPluginManager().disablePlugin(this)
|
||||
} else {
|
||||
logError("error.reload.resource.fail".translate(Pair("path", resourceFile.path)))
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
return yamlConfig
|
||||
|
|
|
|||
|
|
@ -122,8 +122,7 @@ class DiagnosticExecutor : CASubCommand {
|
|||
|
||||
if (sender is HumanEntity) {
|
||||
if (hasError)
|
||||
sender.spigot()
|
||||
.sendMessage(TextComponent(ChatColor.RED.toString() + "There was an error running the diagnostic"))
|
||||
sender.sendMessage(ChatColor.RED.toString() + "There was an error running the diagnostic")
|
||||
val message = TextComponent(ChatColor.GREEN.toString() + "Click to copy diagnostic data")
|
||||
|
||||
message.clickEvent = ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, stb.toString())
|
||||
|
|
|
|||
|
|
@ -18,60 +18,13 @@ object Lang {
|
|||
if(default != lang) default.reload()
|
||||
}
|
||||
|
||||
fun String.translate(): String {
|
||||
val value = lang.get(this)
|
||||
fun getTranslated(key: String): String {
|
||||
val value = lang.get(key)
|
||||
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, Any>): String {
|
||||
return translate(
|
||||
params.asSequence()
|
||||
.map { Pair(it.first, it.second.toString()) }
|
||||
.toMap()
|
||||
)
|
||||
}
|
||||
|
||||
fun String.translate(vararg params: Pair<Char, Any>): String {
|
||||
return translate(
|
||||
params.asSequence()
|
||||
.map { Pair(it.first.toString(), it.second.toString()) }
|
||||
.toMap()
|
||||
)
|
||||
}
|
||||
|
||||
fun String.translate(vararg params: Pair<String, String>): String {
|
||||
return translate(params.toMap())
|
||||
}
|
||||
|
||||
fun String.translate(vararg params: Pair<Char, String>): String {
|
||||
return translate(
|
||||
params.asSequence()
|
||||
.map { Pair(it.first.toString(), it.second) }
|
||||
.toMap()
|
||||
)
|
||||
}
|
||||
|
||||
fun String.translate(params: Map<String, String>): 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()
|
||||
return default.get(key) ?: key
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ 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
|
||||
|
|
|
|||
128
src/main/kotlin/xyz/alexcrea/cuanvil/lang/Message.kt
Normal file
128
src/main/kotlin/xyz/alexcrea/cuanvil/lang/Message.kt
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
package xyz.alexcrea.cuanvil.lang
|
||||
|
||||
import io.delilaheve.CustomAnvil
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.command.CommandSender
|
||||
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.sendPaperMessage
|
||||
import xyz.alexcrea.cuanvil.util.MiniMessageUtil
|
||||
import java.util.logging.Level
|
||||
import kotlin.math.min
|
||||
|
||||
interface MessageLike {
|
||||
|
||||
fun log(vararg params: Any)
|
||||
|
||||
fun send(destination: CommandSender, vararg params: Any)
|
||||
}
|
||||
|
||||
enum class MessageType {
|
||||
DEFAULT,
|
||||
WARNING,
|
||||
ERROR,
|
||||
}
|
||||
|
||||
open class Message(val key: String, vararg val params: String) : MessageLike {
|
||||
|
||||
protected fun replaceParameters(stb: StringBuilder, vararg values: Any) {
|
||||
// replace all placeholder thingy %key -> value
|
||||
|
||||
for(i in 0 until min(params.size, values.size)) {
|
||||
val key = params[i]
|
||||
val replacement = values[i].toString()
|
||||
|
||||
var current = 0
|
||||
while(true) {
|
||||
current = stb.indexOf('%', current) + 1
|
||||
if(current < 0 || current + key.length > stb.length) break // may be able to be removed if bound checked in startsWith ?
|
||||
if(!stb.startsWith(key, current, false)) continue
|
||||
|
||||
stb.replace(current - 1, current + key.length, replacement)
|
||||
current = current - 1 + replacement.length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun unformatted(vararg params: Any): String {
|
||||
val translated = Lang.getTranslated(key)
|
||||
if(params.isEmpty()) return translated
|
||||
|
||||
val stb = StringBuilder(translated)
|
||||
replaceParameters(stb, *params)
|
||||
return stb.toString()
|
||||
}
|
||||
|
||||
fun formatted(vararg params: Any): Component {
|
||||
val unformatted = unformatted(*params)
|
||||
|
||||
return MiniMessageUtil.mm.deserialize(unformatted)
|
||||
}
|
||||
|
||||
override fun log(vararg params: Any) {
|
||||
val text = unformatted(*params)
|
||||
|
||||
CustomAnvil.instance.logger.info(text)
|
||||
}
|
||||
|
||||
override fun send(destination: CommandSender, vararg params: Any) {
|
||||
val message = formatted(*params)
|
||||
if(!destination.sendPaperMessage(message))
|
||||
destination.sendMessage(MiniMessageUtil.legacy_mm.serialize(message))
|
||||
}
|
||||
}
|
||||
|
||||
class WarningMessage(key: String, vararg params: String) : Message("warning.$key", *params) {
|
||||
|
||||
override fun log(vararg params: Any) {
|
||||
val text = unformatted(*params)
|
||||
|
||||
CustomAnvil.instance.logger.warning(text)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ErrorMessage(key: String, vararg params: String) : Message("error.$key", *params) {
|
||||
|
||||
override fun log(vararg params: Any) {
|
||||
val text = unformatted(*params)
|
||||
|
||||
CustomAnvil.logError(text)
|
||||
}
|
||||
|
||||
fun log(e: Throwable, vararg params: Any, level: Level = Level.SEVERE, track: Boolean = true) {
|
||||
val text = unformatted(*params)
|
||||
|
||||
CustomAnvil.logError(text, e, track, level)
|
||||
}
|
||||
}
|
||||
|
||||
class MultiLineMessage(type: MessageType, baseKey: String, count: Int, vararg params: String) : MessageLike {
|
||||
|
||||
private val messages = ArrayList<MessageLike>()
|
||||
|
||||
init {
|
||||
for(i in 1 until count + 1) {
|
||||
val message = createNew(type, "$baseKey.$i", *params)
|
||||
messages.add(message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createNew(type: MessageType, key: String, vararg params: String): MessageLike {
|
||||
return when(type) {
|
||||
MessageType.DEFAULT -> Message(key, *params)
|
||||
MessageType.WARNING -> WarningMessage(key, *params)
|
||||
MessageType.ERROR -> ErrorMessage(key, *params)
|
||||
}
|
||||
}
|
||||
|
||||
override fun log(vararg params: Any) {
|
||||
for(message in messages) {
|
||||
message.log(*params)
|
||||
}
|
||||
}
|
||||
|
||||
override fun send(destination: CommandSender, vararg params: Any) {
|
||||
for(message in messages) {
|
||||
message.send(destination, *params)
|
||||
}
|
||||
}
|
||||
}
|
||||
4
src/main/kotlin/xyz/alexcrea/cuanvil/lang/Msg.kt
Normal file
4
src/main/kotlin/xyz/alexcrea/cuanvil/lang/Msg.kt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
package xyz.alexcrea.cuanvil.lang
|
||||
|
||||
object Msg {
|
||||
}
|
||||
26
src/main/kotlin/xyz/alexcrea/cuanvil/lang/MsgError.kt
Normal file
26
src/main/kotlin/xyz/alexcrea/cuanvil/lang/MsgError.kt
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
package xyz.alexcrea.cuanvil.lang
|
||||
|
||||
object MsgError {
|
||||
|
||||
/*
|
||||
* -----------------
|
||||
* Load and reload
|
||||
* -----------------
|
||||
*/
|
||||
val LOAD_UPDATE_CHECK_FAIL = ErrorMessage("load.update.check-fail")
|
||||
val LOAD_LEGACY_FAILED = ErrorMessage("load.legacy.failed")
|
||||
val LOAD_COMMAND_REGISTER = ErrorMessage("load.command-register")
|
||||
val LOAD_COMPATIBILITY = ErrorMessage("load.compatibility")
|
||||
val LOAD_LISTENERS = ErrorMessage("load.listeners")
|
||||
val LOAD_ENCHANT_SYSTEM = ErrorMessage("load.enchant-system")
|
||||
val LOAD_NON_DEFAULT_CONFIG = ErrorMessage("load.non-default-config")
|
||||
|
||||
val RELOAD_FAIL = ErrorMessage("reload.resource.fail", "path")
|
||||
val RELOAD_HARD_FAIL = ErrorMessage("reload.resource.hardfail")
|
||||
|
||||
/*
|
||||
* ----------
|
||||
* Commands
|
||||
* ----------
|
||||
*/
|
||||
}
|
||||
17
src/main/kotlin/xyz/alexcrea/cuanvil/lang/MsgWarning.kt
Normal file
17
src/main/kotlin/xyz/alexcrea/cuanvil/lang/MsgWarning.kt
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package xyz.alexcrea.cuanvil.lang
|
||||
|
||||
object MsgWarning {
|
||||
|
||||
/*
|
||||
* ---------------
|
||||
* Load and reload
|
||||
* ---------------
|
||||
*/
|
||||
val LOAD_UPDATE_AVAILABLE = WarningMessage("load.update.available", "version")
|
||||
|
||||
val LOAD_LEGACY_OLD_NAME = MultiLineMessage(MessageType.WARNING, "load.legacy.old-name", 2)
|
||||
val LOAD_LEGACY_SPIGOT = MultiLineMessage(MessageType.WARNING, "load.legacy.spigot", 2)
|
||||
val LOAD_LEGACY_SPIGOT_OLD = MultiLineMessage(MessageType.WARNING, "load.legacy.spigot", 2)
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -74,8 +74,8 @@ object MetricsUtil {
|
|||
lastError = e
|
||||
}
|
||||
|
||||
fun trackError(message: String) {
|
||||
ERROR_TRACKER?.trackError(message)
|
||||
fun trackError(message: String, cause: Throwable? = null) {
|
||||
trackError(RuntimeException(message, cause))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
name: English
|
||||
last-updated: 2.1.0
|
||||
|
||||
warning:
|
||||
load:
|
||||
|
|
@ -27,3 +28,38 @@ error:
|
|||
resource:
|
||||
fail: "Resource %path Could not be loaded or reloaded."
|
||||
hard-fail: "Disabling plugin."
|
||||
|
||||
command:
|
||||
shared:
|
||||
no-diag-permission: "<red>You do not have permission to diagnostic this server"
|
||||
# I try to avoid using & for color but this is for a bungee text component
|
||||
hover-copy: "§7Click to copy"
|
||||
warning:
|
||||
missing-subcmd: "Need to specify a subcommand. for example %example1 or %example2"
|
||||
root:
|
||||
warning:
|
||||
unknown-sub: "<red>Invalid subcommand. run <yellow>`%command help` <red>to see available commands"
|
||||
error:
|
||||
generic: "<red>Error running this command"
|
||||
debug:
|
||||
description: "Used to toggle debug logs and retrieve them"
|
||||
log-cleared: "Log Cleared"
|
||||
toggled: "Debug toggled to %type"
|
||||
# I try to avoid using & for color but this is for a bungee text component
|
||||
copy: "§aClick to copy log data"
|
||||
data:
|
||||
header: "Debug Log data:"
|
||||
line-count: "Found %count lines"
|
||||
warning:
|
||||
unspecified-type: "Need to specify which type of debug to toggle: \"default\" or \"verbose\""
|
||||
no-log: "No log to show ? make sure you tried with debug log toggled (%command)"
|
||||
diagnostic:
|
||||
description: "Basic diagnostic of this plugin"
|
||||
had-error: "<red>There was an error running the diagnostic"
|
||||
# I try to avoid using & for color but this is for a bungee text component
|
||||
copy: "§aClick to copy diagnostic data"
|
||||
config:
|
||||
description: "Used to edit the configuration of the plugin"
|
||||
|
||||
warning:
|
||||
legacy-name: "<red>/ca gui has been moved to /ca config"
|
||||
Loading…
Add table
Add a link
Reference in a new issue