diff --git a/src/main/kotlin/moe/nikky/BotInfoExtension.kt b/src/main/kotlin/moe/nikky/BotInfoExtension.kt index 4aaf28f..a1c20b5 100644 --- a/src/main/kotlin/moe/nikky/BotInfoExtension.kt +++ b/src/main/kotlin/moe/nikky/BotInfoExtension.kt @@ -10,6 +10,7 @@ import dev.kordex.core.extensions.ephemeralSlashCommand import dev.kord.common.entity.Permission import dev.kord.common.entity.Permissions import dev.kord.rest.builder.message.embed +import dev.kordex.core.i18n.toKey import io.klogging.Klogging import io.ktor.http.* import kotlinx.coroutines.flow.count @@ -50,8 +51,8 @@ class BotInfoExtension : Extension(), Klogging { inner class SetAdminRoleArgs : Arguments() { val role by role { - name = "role" - description = "admin role" + name = "role".toKey() + description = "admin role".toKey() } } @@ -59,12 +60,12 @@ class BotInfoExtension : Extension(), Klogging { val self = kord.getSelf() ephemeralSlashCommand { - name = "bot" - description = "${self.username} related commands" + name = "bot".toKey() + description = "${self.username} related commands".toKey() ephemeralSubCommand() { - name = "show-config" - description = "shows the current configuration of (${self.username} ${self.mention})" + name = "show-config".toKey() + description = "shows the current configuration of (${self.username} ${self.mention})".toKey() allowInDms = false check { @@ -110,8 +111,8 @@ class BotInfoExtension : Extension(), Klogging { } ephemeralSubCommand { - name = "invite" - description = "get invite url" + name = "invite".toKey() + description = "get invite url".toKey() action { withLogContextOptionalGuild(event, guild) { guild -> @@ -124,8 +125,8 @@ class BotInfoExtension : Extension(), Klogging { } ephemeralSubCommand { - name = "stats" - description = "shows some numbers about (${self.username} ${self.mention})" + name = "stats".toKey() + description = "shows some numbers about (${self.username} ${self.mention})".toKey() action { val roleManagement: RoleManagementExtension? = getKoin().getOrNull() val twitch: TwitchExtension? = getKoin().getOrNull() diff --git a/src/main/kotlin/moe/nikky/ConfigurationExtension.kt b/src/main/kotlin/moe/nikky/ConfigurationExtension.kt index 58ad526..fe36f92 100644 --- a/src/main/kotlin/moe/nikky/ConfigurationExtension.kt +++ b/src/main/kotlin/moe/nikky/ConfigurationExtension.kt @@ -19,6 +19,7 @@ import dev.kord.core.behavior.GuildBehavior import dev.kord.core.entity.Role import dev.kord.core.event.Event import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kordex.core.i18n.toKey import io.github.xn32.json5k.SerialComment import io.klogging.Klogging import kotlinx.serialization.Serializable @@ -54,22 +55,22 @@ class ConfigurationExtension : Extension(), Klogging { inner class SetAdminRoleArgs : Arguments() { val role by role { - name = "role" - description = "admin role" + name = "role".toKey() + description = "admin role".toKey() } } override suspend fun setup() { val self = kord.getSelf() ephemeralSlashCommand { - name = "config" + name = "config".toKey() // description = "${self.username} related commands" - description = "self.username related commands" + description = "self.username related commands".toKey() allowInDms = false ephemeralSubCommand(::SetAdminRoleArgs) { - name = "adminset" - description = "sets the admin role" + name = "adminset".toKey() + description = "sets the admin role".toKey() check { hasPermission(Permission.Administrator) @@ -90,8 +91,8 @@ class ConfigurationExtension : Extension(), Klogging { } ephemeralSubCommand { - name = "adminunset" - description = "clears admin role" + name = "adminunset".toKey() + description = "clears admin role".toKey() check { hasPermission(Permission.Administrator) } @@ -115,7 +116,7 @@ class ConfigurationExtension : Extension(), Klogging { } suspend fun CheckContext.requiresBotControl(locale: Locale) { - val guild = guildFor(event)?.asGuildOrNull() ?: relayError("cannot load guild") + val guild = guildFor(event)?.asGuildOrNull() ?: relayError("cannot load guild".toKey()) val configUnit = guild.config() val guildConfig = configUnit.get() val adminRole = guildConfig?.adminRole(guild) diff --git a/src/main/kotlin/moe/nikky/DiceExtension.kt b/src/main/kotlin/moe/nikky/DiceExtension.kt index 827bb56..0eb25af 100644 --- a/src/main/kotlin/moe/nikky/DiceExtension.kt +++ b/src/main/kotlin/moe/nikky/DiceExtension.kt @@ -9,14 +9,15 @@ import dev.kordex.core.commands.Arguments import dev.kordex.core.commands.converters.impl.string import dev.kordex.core.extensions.Extension import dev.kordex.core.extensions.publicSlashCommand +import dev.kordex.core.i18n.toKey import io.klogging.Klogging class DiceExtension() : Extension(), Klogging { override val name: String = "dice" override suspend fun setup() { publicSlashCommand(::DiceArgs) { - name = "dice" - description = "rolls dice" + name = "dice".toKey() + description = "rolls dice".toKey() allowInDms = true action { @@ -45,8 +46,8 @@ class DiceExtension() : Extension(), Klogging { inner class DiceArgs : Arguments() { val notation by string { - name = "notation" - description = "dices to roll" + name = "notation".toKey() + description = "dices to roll".toKey() } } } diff --git a/src/main/kotlin/moe/nikky/KloggingExt.kt b/src/main/kotlin/moe/nikky/KloggingExt.kt index 5d5032d..675704e 100644 --- a/src/main/kotlin/moe/nikky/KloggingExt.kt +++ b/src/main/kotlin/moe/nikky/KloggingExt.kt @@ -6,6 +6,7 @@ import dev.kord.core.entity.Guild import dev.kord.core.entity.channel.GuildChannel import dev.kord.core.event.Event import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kordex.core.i18n.toKey import io.klogging.context.logContext import io.klogging.events.LogEvent import io.klogging.logger @@ -141,7 +142,7 @@ suspend fun Extension.withLogContext( guildBehavior: GuildBehavior?, block: suspend CoroutineScope.(Guild) -> T, ): T { - val guild = guildBehavior?.asGuild() ?: relayError("cannot load guild") + val guild = guildBehavior?.asGuild() ?: relayError("cannot load guild".toKey()) val items = mutableListOf>() if (event is InteractionCreateEvent) { items += "channel" to (event.interaction.channel.asChannel() as? GuildChannel)?.name diff --git a/src/main/kotlin/moe/nikky/LocalTimeExtension.kt b/src/main/kotlin/moe/nikky/LocalTimeExtension.kt index 2c5ad95..4fc8176 100644 --- a/src/main/kotlin/moe/nikky/LocalTimeExtension.kt +++ b/src/main/kotlin/moe/nikky/LocalTimeExtension.kt @@ -15,6 +15,7 @@ import dev.kord.common.entity.Snowflake import dev.kord.core.behavior.GuildBehavior import dev.kord.core.entity.User import dev.kord.rest.builder.message.embed +import dev.kordex.core.i18n.toKey import io.klogging.Klogging import io.ktor.client.request.forms.* import io.ktor.utils.io.* @@ -60,12 +61,12 @@ class LocalTimeExtension : Extension(), Klogging { override suspend fun setup() { ephemeralSlashCommand(::TimezoneArgs) { - name = "timezone" - description = "list or set timezones" + name = "timezone".toKey() + description = "list or set timezones".toKey() ephemeralSubCommand(::TimezoneArgs) { - name = "set" - description = "update your timezone" + name = "set".toKey() + description = "update your timezone".toKey() action { withLogContext(event, guild) { guild -> @@ -118,8 +119,8 @@ class LocalTimeExtension : Extension(), Klogging { } ephemeralSubCommand() { - name = "list" - description = "sends a list of valid timezones" + name = "list".toKey() + description = "sends a list of valid timezones".toKey() action { withLogContext(event, guild) { guild -> @@ -144,7 +145,7 @@ class LocalTimeExtension : Extension(), Klogging { } ephemeralUserCommand { - name = "Local Time" + name = "Local Time".toKey() action { withLogContext(event, guild) { guild -> @@ -162,8 +163,8 @@ class LocalTimeExtension : Extension(), Klogging { } } ephemeralSlashCommand(::TimezoneTargetArgs) { - name = "LocalTime" - description = "get the local time for a user" + name = "LocalTime".toKey() + description = "get the local time for a user".toKey() action { withLogContext(event, guild) { guild -> @@ -224,8 +225,8 @@ class LocalTimeExtension : Extension(), Klogging { inner class TimezoneArgs : Arguments() { val timezoneId by string { - name = "timezone" - description = "time zone id" + name = "timezone".toKey() + description = "time zone id".toKey() autoComplete { event -> val now = Clock.System.now() @@ -248,8 +249,8 @@ class LocalTimeExtension : Extension(), Klogging { inner class TimezoneTargetArgs : Arguments() { val user by user { - name = "user" - description = "user to get local time for" + name = "user".toKey() + description = "user to get local time for".toKey() } } } diff --git a/src/main/kotlin/moe/nikky/RoleChooserConfig.kt b/src/main/kotlin/moe/nikky/RoleChooserConfig.kt index 94c2040..a9082c0 100644 --- a/src/main/kotlin/moe/nikky/RoleChooserConfig.kt +++ b/src/main/kotlin/moe/nikky/RoleChooserConfig.kt @@ -10,6 +10,7 @@ import dev.kord.core.entity.ReactionEmoji import dev.kord.core.entity.Role import dev.kord.core.entity.channel.TextChannel import dev.kord.rest.request.KtorRequestException +import dev.kordex.core.i18n.toKey import io.github.xn32.json5k.SerialComment import io.klogging.context.logContext import io.klogging.logger @@ -44,7 +45,7 @@ data class RoleChooserConfig( logContext("guild" to guildBehavior.name) ) { guildBehavior.getChannelOfOrNull(channelId) - ?: relayError("channel $channelId in '${guildBehavior.name}' could not be loaded as TextChannel") + ?: relayError("channel $channelId in '${guildBehavior.name}' could not be loaded as TextChannel".toKey()) } } @@ -56,7 +57,7 @@ data class RoleChooserConfig( channel(guildBehavior).getMessageOrNull(messageId) } catch (e: KtorRequestException) { logger.errorF { e.message } - relayError("cannot access message $messageId") + relayError("cannot access message $messageId".toKey()) } } } diff --git a/src/main/kotlin/moe/nikky/RoleManagementExtension.kt b/src/main/kotlin/moe/nikky/RoleManagementExtension.kt index aea10e9..3aeec38 100644 --- a/src/main/kotlin/moe/nikky/RoleManagementExtension.kt +++ b/src/main/kotlin/moe/nikky/RoleManagementExtension.kt @@ -45,6 +45,7 @@ import dev.kord.core.live.live import dev.kord.core.live.onReactionAdd import dev.kord.core.live.onReactionRemove import dev.kord.rest.request.KtorRequestException +import dev.kordex.core.i18n.toKey import io.github.xn32.json5k.Json5 import io.klogging.Klogging import kotlinx.coroutines.CoroutineName @@ -100,97 +101,97 @@ class RoleManagementExtension : Extension(), Klogging { inner class AddRoleArg : Arguments() { val section by string { - name = "section" - description = "Section Title" + name = "section".toKey() + description = "Section Title".toKey() } val reaction by reactionEmoji { - name = "emoji" - description = "Reaction Emoji" + name = "emoji".toKey() + description = "Reaction Emoji".toKey() } val role by role { - name = "role" - description = "Role" + name = "role".toKey() + description = "Role".toKey() } val channel by optionalChannel { - name = "channel" - description = "channel" + name = "channel".toKey() + description = "channel".toKey() requireChannelType(ChannelType.GuildText) } } inner class ListRoleArg : Arguments() { val channel by optionalChannel { - name = "channel" - description = "channel" + name = "channel".toKey() + description = "channel".toKey() requireChannelType(ChannelType.GuildText) } } inner class RemoveRoleArg : Arguments() { val section by string { - name = "section" - description = "Section Title" + name = "section".toKey() + description = "Section Title".toKey() } val reaction by reactionEmoji { - name = "emoji" - description = "Reaction Emoji" + name = "emoji".toKey() + description = "Reaction Emoji".toKey() } val channel by optionalChannel { - name = "channel" - description = "channel" + name = "channel".toKey() + description = "channel".toKey() requireChannelType(ChannelType.GuildText) } } inner class RenameSectionArg : Arguments() { val oldSection by string { - name = "old" - description = "OLD Section Title" + name = "old".toKey() + description = "OLD Section Title".toKey() } val newSection by string { - name = "section" - description = "NEW Section Title" + name = "section".toKey() + description = "NEW Section Title".toKey() } val channel by optionalChannel { - name = "channel" - description = "channel" + name = "channel".toKey() + description = "channel".toKey() requireChannelType(ChannelType.GuildText) } } inner class CreateRoleArg : Arguments() { val name by string { - name = "name" - description = "role name" + name = "name".toKey() + description = "role name".toKey() } val color by optionalColor { - name = "color" - description = "role color" + name = "color".toKey() + description = "role color".toKey() } val mentionable by defaultingBoolean { - name = "mentionable" - description = "pingable" + name = "mentionable".toKey() + description = "pingable".toKey() defaultValue = false } } inner class ImportRoleArg : Arguments() { val data by string { - name = "data" - description = "json5 encoded role data" + name = "data".toKey() + description = "json5 encoded role data".toKey() } } override suspend fun setup() { ephemeralSlashCommand { - name = "reactionRole" - description = "manage reaction roles" + name = "reactionRole".toKey() + description = "manage reaction roles".toKey() allowInDms = false requireBotPermissions(Permission.ManageRoles) ephemeralSubCommand(::AddRoleArg) { - name = "add" - description = "adds a new reaction to role mapping" + name = "add".toKey() + description = "adds a new reaction to role mapping".toKey() check { with(config) { requiresBotControl() } @@ -217,8 +218,8 @@ class RoleManagementExtension : Extension(), Klogging { } ephemeralSubCommand(::ListRoleArg) { - name = "list" - description = "lists all configured reaction roles" + name = "list".toKey() + description = "lists all configured reaction roles".toKey() check { with(config) { requiresBotControl() } @@ -245,8 +246,8 @@ class RoleManagementExtension : Extension(), Klogging { } ephemeralSubCommand(::RenameSectionArg) { - name = "update-section" - description = "to fix a mistyped section name or such" + name = "update-section".toKey() + description = "to fix a mistyped section name or such".toKey() check { with(config) { requiresBotControl() } @@ -273,8 +274,8 @@ class RoleManagementExtension : Extension(), Klogging { } ephemeralSubCommand(::RemoveRoleArg) { - name = "remove" - description = "removes a role mapping" + name = "remove".toKey() + description = "removes a role mapping".toKey() check { with(config) { requiresBotControl() } @@ -299,8 +300,8 @@ class RoleManagementExtension : Extension(), Klogging { } } ephemeralSubCommand { - name = "check" - description = "check permissions in channel" + name = "check".toKey() + description = "check permissions in channel".toKey() requireBotPermissions( *requiredPermissions, @@ -368,14 +369,14 @@ class RoleManagementExtension : Extension(), Klogging { } ephemeralSlashCommand { - name = "role" - description = "create a new role" + name = "role".toKey() + description = "create a new role".toKey() allowInDms = false requireBotPermissions(Permission.ManageRoles) ephemeralSubCommand(::CreateRoleArg) { - name = "create" - description = "creates a new role" + name = "create".toKey() + description = "creates a new role".toKey() requireBotPermissions( Permission.ManageRoles, @@ -387,7 +388,7 @@ class RoleManagementExtension : Extension(), Klogging { action { withLogContext(event, guild) { guild -> if(guild.roles.any { it.name == arguments.name }) { - relayError("a role with that name already exists") + relayError("a role with that name already exists".toKey()) } val role = guild.createRole { name = arguments.name @@ -405,8 +406,8 @@ class RoleManagementExtension : Extension(), Klogging { ephemeralSubCommand(::ImportRoleArg) { - name = "import" - description = "creates many roles" + name = "import".toKey() + description = "creates many roles".toKey() requireBotPermissions( Permission.ManageRoles, @@ -424,7 +425,7 @@ class RoleManagementExtension : Extension(), Klogging { val duplicates = guild.roles.filter { it.name in data.keys }.toList() if(duplicates.isNotEmpty()) { relayError( - "roles with the following roles already exist: ${duplicates.joinToString(" ") { it.mention }}" + "roles with the following roles already exist: ${duplicates.joinToString(" ") { it.mention }}".toKey() ) } val roles = data.map { (roleName, roleColor) -> @@ -545,7 +546,7 @@ class RoleManagementExtension : Extension(), Klogging { currentChannel: ChannelBehavior, ): String { val channel = (arguments.channel ?: currentChannel).asChannel().let { channel -> - channel as? TextChannel ?: relayError("${channel.mention} is not a Text Channel") + channel as? TextChannel ?: relayError("${channel.mention} is not a Text Channel".toKey()) } val configUnit = guild.config() @@ -563,7 +564,7 @@ class RoleManagementExtension : Extension(), Klogging { it.key(channel) to it }.also { configUnit.save( - configUnit.get()?.update(it.first, it.second) ?: relayError("failed to save config") + configUnit.get()?.update(it.first, it.second) ?: relayError("failed to save config".toKey()) ) } } @@ -574,11 +575,11 @@ class RoleManagementExtension : Extension(), Klogging { configUnit.save( configUnit.get()?.updateRoleMapping(key, arguments.reaction, arguments.role) - ?: relayError("failed to save config") + ?: relayError("failed to save config".toKey()) ) val (_, newRoleChooserConfig) = configUnit.get()?.find(arguments.section, channel.id) - ?: relayError("could not find role chooser section") + ?: relayError("could not find role chooser section".toKey()) val newRoleMapping = newRoleChooserConfig.roleMapping message.edit { @@ -610,13 +611,13 @@ class RoleManagementExtension : Extension(), Klogging { currentChannel: ChannelBehavior, ): String { val channel = (arguments.channel ?: currentChannel).asChannel().let { channel -> - channel as? TextChannel ?: relayError("${channel.mention} is not a Text Channel") + channel as? TextChannel ?: relayError("${channel.mention} is not a Text Channel".toKey()) } val configUnit = guild.config() val roleChoosers = configUnit.get()?.list(channelId = channel.id) - ?: relayError("failed to load config") + ?: relayError("failed to load config".toKey()) return roleChoosers.map { roleChooserConfig -> val message = roleChooserConfig.getMessageOrRelayError(guild) @@ -975,9 +976,8 @@ private suspend fun parseColor(input: String, context: CommandContext): Color? { input.startsWith("0x") -> Color(input.substring(2).toInt(16)) input.all { it.isDigit() } -> Color(input.toInt()) - else -> ColorParser.parse(input, context.getLocale()) ?: throw DiscordRelayedException( - context.translate("converters.color.error.unknown", replacements = arrayOf(input)) - ) + else -> ColorParser.parse(input, context.getLocale()) + ?: throw DiscordRelayedException("converters.color.error.unknown".toKey()) } } diff --git a/src/main/kotlin/moe/nikky/SchedulingExtension.kt b/src/main/kotlin/moe/nikky/SchedulingExtension.kt index 17787e4..652277d 100644 --- a/src/main/kotlin/moe/nikky/SchedulingExtension.kt +++ b/src/main/kotlin/moe/nikky/SchedulingExtension.kt @@ -34,6 +34,7 @@ import dev.kord.core.entity.interaction.followup.EphemeralFollowupMessage import dev.kord.rest.builder.message.actionRow import dev.kord.x.emoji.DiscordEmoji import dev.kord.x.emoji.from +import dev.kordex.core.i18n.toKey import dev.kordex.core.utils.from import io.klogging.Klogging import kotlinx.coroutines.runBlocking @@ -228,36 +229,36 @@ class SchedulingExtension() : Extension(), Klogging { inner class SchedulingCreateArgs : Arguments() { val id by string { - name = "id" - description = "id of the event" + name = "id".toKey() + description = "id of the event".toKey() } val name by string { - name = "name" - description = "name of the event" + name = "name".toKey() + description = "name of the event".toKey() } val description by string { - name = "description" - description = "freeform event description" + name = "description".toKey() + description = "freeform event description".toKey() // defaultValue = "a new cool event" } val startTime by string { - name = "start" - description = "supports discord timestamps hammertime" + name = "start".toKey() + description = "supports discord timestamps hammertime".toKey() validate { - tryParseInstant(value) ?: fail("failed to parse $value") + tryParseInstant(value) ?: fail("failed to parse $value".toKey()) } } val endTime by string { - name = "end" - description = "supports discord timestamps hammertime" + name = "end".toKey() + description = "supports discord timestamps hammertime".toKey() validate { - tryParseInstant(value) ?: fail("failed to parse $value") + tryParseInstant(value) ?: fail("failed to parse $value".toKey()) } } val slotLength by long { - name = "slotlength" - description = "slot length in minutes" + name = "slotlength".toKey() + description = "slot length in minutes".toKey() // choices( // listOf( // 15, @@ -324,8 +325,8 @@ class SchedulingExtension() : Extension(), Klogging { inner class SignupArgs : Arguments() { val event by stringChoice { - name = "event" - description = "Select a event" + name = "event".toKey() + description = "Select a event".toKey() // validate { // val schedulingData = this.context.getGuild()!!.config().get() ?: SchedulingData() // failIfNot("unknown event '$value'") { @@ -367,13 +368,13 @@ class SchedulingExtension() : Extension(), Klogging { override suspend fun setup() { ephemeralSlashCommand { - name = "scheduling" - description = "create and edit open signup events" + name = "scheduling".toKey() + description = "create and edit open signup events".toKey() allowInDms = false ephemeralSubCommand(::SchedulingCreateArgs) { - name = "create" - description = "register a new event" + name = "create".toKey() + description = "register a new event".toKey() requireBotPermissions( @@ -474,8 +475,8 @@ class SchedulingExtension() : Extension(), Klogging { } } ephemeralSubCommand { - name = "list" - description = "list events" + name = "list".toKey() + description = "list events".toKey() action { withLogContext(event, guild) { guild -> diff --git a/src/main/kotlin/moe/nikky/TestExtension.kt b/src/main/kotlin/moe/nikky/TestExtension.kt index 217d1f0..769bb99 100644 --- a/src/main/kotlin/moe/nikky/TestExtension.kt +++ b/src/main/kotlin/moe/nikky/TestExtension.kt @@ -23,6 +23,8 @@ import dev.kord.common.entity.optional.optional import dev.kord.core.behavior.createScheduledEvent import dev.kord.core.entity.Guild import dev.kord.core.event.message.MessageCreateEvent +import dev.kordex.core.i18n.toKey +import dev.kordex.core.i18n.types.Key import io.klogging.Klogging import kotlinx.coroutines.flow.toList import kotlinx.datetime.Clock @@ -42,8 +44,8 @@ class TestExtension : Extension(), Klogging { override suspend fun setup() { publicSlashCommand(::SlapArgs) { - name = "slap" - description = "Get slapped!" + name = "slap".toKey() + description = "Get slapped!".toKey() action { // Because of the DslMarker annotation KordEx uses, we need to grab Kord explicitly @@ -62,8 +64,8 @@ class TestExtension : Extension(), Klogging { } } publicSlashCommand(::BonkArgs) { - name = "bonk" - description = "bonk" + name = "bonk".toKey() + description = "bonk".toKey() action { // Because of the DslMarker annotation KordEx uses, we need to grab Kord explicitly @@ -193,13 +195,13 @@ class TestExtension : Extension(), Klogging { inner class SlapArgs : Arguments() { // A single user argument, required for the command to be able to run val target by optionalUser { - name = "target" - description = "Person you want to slap" + name = "target".toKey() + description = "Person you want to slap".toKey() } private val nullableWeapon by optionalEnumChoice { - name = "weapon" - description = "What you want to slap with" - typeName = "weapon" + name = "weapon".toKey() + description = "What you want to slap with".toKey() + typeName = "weapon".toKey() } val weapon: Weapon get() = nullableWeapon ?: Weapon.Trout } @@ -207,32 +209,32 @@ class TestExtension : Extension(), Klogging { inner class BonkArgs : Arguments() { // A single user argument, required for the command to be able to run val target by user { - name = "target" - description = "Person that needs a bonk" + name = "target".toKey() + description = "Person that needs a bonk".toKey() } } - enum class Weapon(override val readableName: String, val message: String) : ChoiceEnum { - Trout("trout", "their large, smelly trout"), - Stick("stick", "a stick"), + enum class Weapon(override val readableName: Key, val message: String) : ChoiceEnum { + Trout("trout".toKey(), "their large, smelly trout"), + Stick("stick".toKey(), "a stick"), } inner class ScheduleArgs : Arguments() { val title by string { - name = "title" - description = "scheduled event title" + name = "title".toKey() + description = "scheduled event title".toKey() } val description by optionalString { - name = "description" - description = "scheduled event description" + name = "description".toKey() + description = "scheduled event description".toKey() } val location by optionalString { - name = "location" - description = "event location" + name = "location".toKey() + description = "event location".toKey() } val delay: DateTimePeriod? by optionalDuration { - name = "delay" - description = "delay before the event starts" + name = "delay".toKey() + description = "delay before the event starts".toKey() } } diff --git a/src/main/kotlin/moe/nikky/checks/RoleChecks.kt b/src/main/kotlin/moe/nikky/checks/RoleChecks.kt index d2f522c..de81d73 100644 --- a/src/main/kotlin/moe/nikky/checks/RoleChecks.kt +++ b/src/main/kotlin/moe/nikky/checks/RoleChecks.kt @@ -7,6 +7,7 @@ import dev.kordex.core.checks.types.CheckContext import dev.kord.core.behavior.RoleBehavior import dev.kord.core.event.Event import dev.kordex.core.checks.memberFor +import dev.kordex.core.i18n.toKey import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.flow.toList @@ -36,10 +37,7 @@ public suspend fun CheckContext.hasRoleNullable(builder: suspend logger.failed("Member $member does not have role $role") fail( - translate( - "checks.hasRole.failed", - replacements = arrayOf(role.mention), - ) + "checks.hasRole.failed".toKey(), //.translate(role.mention), ) } } else { diff --git a/src/main/kotlin/moe/nikky/converter/ReactionEmojiConverter.kt b/src/main/kotlin/moe/nikky/converter/ReactionEmojiConverter.kt index eb0f0da..602f7ee 100644 --- a/src/main/kotlin/moe/nikky/converter/ReactionEmojiConverter.kt +++ b/src/main/kotlin/moe/nikky/converter/ReactionEmojiConverter.kt @@ -19,8 +19,13 @@ import dev.kord.core.entity.interaction.StringOptionValue import dev.kord.rest.builder.interaction.OptionsBuilder import dev.kord.rest.builder.interaction.StringChoiceBuilder import dev.kord.x.emoji.Emojis +import dev.kordex.core.annotations.InternalAPI import dev.kordex.core.annotations.converters.Converter import dev.kordex.core.annotations.converters.ConverterType +import dev.kordex.core.commands.ChoiceOptionWrapper +import dev.kordex.core.commands.OptionWrapper +import dev.kordex.core.i18n.toKey +import dev.kordex.core.i18n.types.Key import dev.kordex.parser.StringParser import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.mapNotNull @@ -46,7 +51,7 @@ import kotlinx.coroutines.flow.mapNotNull public class ReactionEmojiConverter( override var validator: Validator = null, ) : SingleConverter() { - override val signatureTypeString: String = "converters.reactionemoji.signatureType" + override val signatureType = "converters.reactionemoji.signatureType".toKey() override suspend fun parse(parser: StringParser?, context: CommandContext, named: String?): Boolean { val arg: String = named ?: parser?.parseNext()?.data ?: return false @@ -67,7 +72,7 @@ public class ReactionEmojiConverter( }.firstOrNull() } catch (e: NumberFormatException) { throw DiscordRelayedException( - context.translate("converters.emoji.error.invalid", replacements = arrayOf(id)) + "converters.emoji.error.invalid".toKey() // .translate(id) ) } } else { // ID or name @@ -90,14 +95,14 @@ public class ReactionEmojiConverter( ReactionEmoji.from(guildEmoji) } else { val unicodeEmoji = Emojis[arg] ?: throw DiscordRelayedException( - "Value `$arg` is not a valid emoji." + "Value `$arg` is not a valid emoji.".toKey() ) ReactionEmoji.Unicode(unicodeEmoji.unicode) } } - override suspend fun toSlashOption(arg: Argument<*>): OptionsBuilder = - StringChoiceBuilder(arg.displayName, arg.description).apply { required = true } + @OptIn(InternalAPI::class) + override suspend fun toSlashOption(arg: Argument<*>): OptionWrapper<*> = ChoiceOptionWrapper.String(arg.displayName, arg.description) { required = true } override suspend fun parseOption(context: CommandContext, option: OptionValue<*>): Boolean { val optionValue = (option as? StringOptionValue)?.value ?: return false diff --git a/src/main/kotlin/moe/nikky/relayError.kt b/src/main/kotlin/moe/nikky/relayError.kt index 0ad9c98..17c7723 100644 --- a/src/main/kotlin/moe/nikky/relayError.kt +++ b/src/main/kotlin/moe/nikky/relayError.kt @@ -1,7 +1,14 @@ package moe.nikky import dev.kordex.core.DiscordRelayedException +import dev.kordex.core.i18n.toKey +import dev.kordex.core.i18n.types.Key +fun relayError(messageKey: Key): Nothing { + throw DiscordRelayedException(messageKey) +} + +@Deprecated("replace with key") fun relayError(message: String): Nothing { - throw DiscordRelayedException("A **error** occurred: $message") + throw DiscordRelayedException(message.toKey()) } diff --git a/src/main/kotlin/moe/nikky/twitch/TwitchExtension.kt b/src/main/kotlin/moe/nikky/twitch/TwitchExtension.kt index e3edb0f..2f79087 100644 --- a/src/main/kotlin/moe/nikky/twitch/TwitchExtension.kt +++ b/src/main/kotlin/moe/nikky/twitch/TwitchExtension.kt @@ -43,6 +43,7 @@ import dev.kordex.core.commands.converters.impl.string import dev.kordex.core.commands.converters.impl.role import dev.kordex.core.extensions.Extension import dev.kordex.core.extensions.ephemeralSlashCommand +import dev.kordex.core.i18n.toKey import dev.kordex.core.storage.StorageType import dev.kordex.core.storage.StorageUnit import dev.kordex.core.time.TimestampType @@ -206,43 +207,43 @@ class TwitchExtension() : Extension(), Klogging { inner class TwitchAddArgs : Arguments() { val role by role { - name = "role" - description = "notification ping" + name = "role".toKey() + description = "notification ping".toKey() } val twitchUserName by string { - name = "twitch" - description = "Twitch username" + name = "twitch".toKey() + description = "Twitch username".toKey() } val channel by optionalChannel { - name = "channel" - description = "notification channel, defaults to current channel" + name = "channel".toKey() + description = "notification channel, defaults to current channel".toKey() requireChannelType(ChannelType.GuildText) } } inner class TwitchRemoveArgs : Arguments() { val twitchUserName by string { - name = "twitch" - description = "Twitch username" + name = "twitch".toKey() + description = "Twitch username".toKey() } val channel by optionalChannel { - name = "channel" - description = "notification channel, defaults to current channel" + name = "channel".toKey() + description = "notification channel, defaults to current channel".toKey() requireChannelType(ChannelType.GuildText) } } inner class TwitchScheduleSyncArgs : Arguments() { val twitchUserName by string { - name = "twitch" - description = "Twitch username" + name = "twitch".toKey() + description = "Twitch username".toKey() } val amount by defaultingInt { val validRange = 1..100 - name = "max" + name = "max".toKey() defaultValue = 30 description = - "amount of schedule entries to list, value between ${validRange.first} and ${validRange.last}, default: $defaultValue" + "amount of schedule entries to list, value between ${validRange.first} and ${validRange.last}, default: $defaultValue".toKey() validate { failIfNot("$value is not in range $validRange") { value in validRange } } @@ -251,42 +252,42 @@ class TwitchExtension() : Extension(), Klogging { inner class TwitchScheduleDeleteArgs : Arguments() { val twitchUserName by string { - name = "twitch" - description = "Twitch username" + name = "twitch".toKey() + description = "Twitch username".toKey() } } inner class TwitchScheduleListArgs : Arguments() { val twitchUserName by string { - name = "twitch" - description = "Twitch username" + name = "twitch".toKey() + description = "Twitch username".toKey() } val amount by defaultingInt { val validRange = 1..100 - name = "max" + name = "max".toKey() defaultValue = 30 description = - "amount of schedule entries to list, value between ${validRange.first} and ${validRange.last}, default: $defaultValue" + "amount of schedule entries to list, value between ${validRange.first} and ${validRange.last}, default: $defaultValue".toKey() validate { failIfNot("$value is not in range $validRange") { value in validRange } } } val includeCancelled by defaultingBoolean { - name = "include_cancelled" - description = "also list cancelled events" + name = "include_cancelled".toKey() + description = "also list cancelled events".toKey() defaultValue = false } } override suspend fun setup() { ephemeralSlashCommand { - name = "twitch" - description = "twitch notifications" + name = "twitch".toKey() + description = "twitch notifications".toKey() allowInDms = false ephemeralSubCommand(::TwitchAddArgs) { - name = "add" - description = "be notified about more streamers" + name = "add".toKey() + description = "be notified about more streamers".toKey() locking = true check { @@ -313,8 +314,8 @@ class TwitchExtension() : Extension(), Klogging { } ephemeralSubCommand(::TwitchRemoveArgs) { - name = "remove" - description = "removes a streamer from notifications" + name = "remove".toKey() + description = "removes a streamer from notifications".toKey() check { with(configurationExtension) { requiresBotControl() } @@ -340,8 +341,8 @@ class TwitchExtension() : Extension(), Klogging { } ephemeralSubCommand { - name = "list" - description = "lists all streamers in config" + name = "list".toKey() + description = "lists all streamers in config".toKey() check { with(configurationExtension) { requiresBotControl() } @@ -397,8 +398,8 @@ class TwitchExtension() : Extension(), Klogging { } ephemeralSubCommand { - name = "check" - description = "check permissions in channel" + name = "check".toKey() + description = "check permissions in channel".toKey() requireBotPermissions( *requiredPermissions @@ -415,8 +416,8 @@ class TwitchExtension() : Extension(), Klogging { } ephemeralSubCommand { - name = "status" - description = "check status of twitch background loop" + name = "status".toKey() + description = "check status of twitch background loop".toKey() check { with(configurationExtension) { requiresBotControl() } @@ -430,8 +431,8 @@ class TwitchExtension() : Extension(), Klogging { } ephemeralSubCommand() { - name = "cleanup" - description = "deletes old messages sent by the bot" + name = "cleanup".toKey() + description = "deletes old messages sent by the bot".toKey() // requireBotPermissions( // Permission.ManageMessages, // ) @@ -444,13 +445,13 @@ class TwitchExtension() : Extension(), Klogging { val before = Clock.System.now() - 7.days val webhooks = findWebhooks(channel = channel) - ?: relayError("could not find assosciated webhook") + ?: relayError("could not find assosciated webhook".toKey()) val messagesToDelete = webhooks.flatMap { webhook -> val token = webhook.token ?: return@flatMap emptyList() val messagesToDelete = channel.getMessagesBefore( - messageId = channel.lastMessageId ?: relayError("empty channel"), + messageId = channel.lastMessageId ?: relayError("empty channel".toKey()), limit = 1000, ) .filter { @@ -494,11 +495,11 @@ class TwitchExtension() : Extension(), Klogging { } } } - group("schedule") { - description = "twitch schedule sync" + group("schedule".toKey()) { + description = "twitch schedule sync".toKey() ephemeralSubCommand(::TwitchScheduleSyncArgs) { - name = "sync" - description = "synchronize schedule" + name = "sync".toKey() + description = "synchronize schedule".toKey() requireBotPermissions( Permission.ManageEvents, ) @@ -512,7 +513,7 @@ class TwitchExtension() : Extension(), Klogging { logins = listOf(arguments.twitchUserName), token = token, )[arguments.twitchUserName] - ?: relayError("cannot get user data for ${arguments.twitchUserName}") + ?: relayError("cannot get user data for ${arguments.twitchUserName}".toKey()) val segments = httpClient.getSchedule( token = token, broadcasterId = userData.id, @@ -619,8 +620,8 @@ class TwitchExtension() : Extension(), Klogging { } } ephemeralSubCommand(::TwitchScheduleDeleteArgs) { - name = "delete" - description = "delete all events for a twitch user" + name = "delete".toKey() + description = "delete all events for a twitch user".toKey() requireBotPermissions( Permission.ManageEvents, ) @@ -634,7 +635,7 @@ class TwitchExtension() : Extension(), Klogging { logins = listOf(arguments.twitchUserName), token = token, )[arguments.twitchUserName] - ?: relayError("cannot get user data for ${arguments.twitchUserName}") + ?: relayError("cannot get user data for ${arguments.twitchUserName}".toKey()) val existingEvents = guild.scheduledEvents .filter { event -> event.entityType == ScheduledEntityType.External } .filter { event -> @@ -656,8 +657,8 @@ class TwitchExtension() : Extension(), Klogging { } } ephemeralSubCommand(::TwitchScheduleListArgs) { - name = "list" - description = "list streamer schedule" + name = "list".toKey() + description = "list streamer schedule".toKey() requireBotPermissions( Permission.ManageEvents, ) @@ -668,7 +669,7 @@ class TwitchExtension() : Extension(), Klogging { logins = listOf(arguments.twitchUserName), token = token, )[arguments.twitchUserName] - ?: relayError("cannot get user data for ${arguments.twitchUserName}") + ?: relayError("cannot get user data for ${arguments.twitchUserName}".toKey()) val segments = httpClient.getSchedule( token = token, broadcasterId = userData.id, @@ -714,7 +715,7 @@ class TwitchExtension() : Extension(), Klogging { val channelInput = arguments.channel ?: currentChannel.asChannel() val channel = guild.getChannelOfOrNull(channelInput.id) ?: guild.getChannelOfOrNull(channelInput.id) - ?: relayError("must be a TextChannel or NewsChannel, was: ${channelInput.type}") + ?: relayError("must be a TextChannel or NewsChannel, was: ${channelInput.type}".toKey()) val user = try { val token = httpClient.getToken() @@ -723,11 +724,11 @@ class TwitchExtension() : Extension(), Klogging { logins = listOf(arguments.twitchUserName) ) userData[arguments.twitchUserName.lowercase()] - ?: relayError("cannot fetch user data: $userData for ") + ?: relayError("cannot fetch user data: $userData for ".toKey()) } catch (e: IllegalStateException) { relayError( - e.message - ?: "unknown error fetching user data for " + e.message?.toKey() + ?: "unknown error fetching user data for ".toKey() ) } @@ -755,14 +756,14 @@ class TwitchExtension() : Extension(), Klogging { val channelInput = arguments.channel ?: currentChannel.asChannel() val channel = guild.getChannelOfOrNull(channelInput.id) ?: guild.getChannelOfOrNull(channelInput.id) - ?: relayError("must be a TextChannel or NewsChannel, was: ${channelInput.type}") + ?: relayError("must be a TextChannel or NewsChannel, was: ${channelInput.type}".toKey()) val configUnit = guild.config() val twitchGuildConfig = configUnit.get() ?: TwitchGuildConfig() val (key, toRemove) = twitchGuildConfig.find( channelId = channel.id, twitchUserName = arguments.twitchUserName - ) ?: relayError("twitch config entry not found") + ) ?: relayError("twitch config entry not found".toKey()) try { toRemove.messageId?.let { @@ -773,7 +774,7 @@ class TwitchExtension() : Extension(), Klogging { } configUnit.save( - configUnit.get()?.remove(key) ?: relayError("failed to save config") + configUnit.get()?.remove(key) ?: relayError("failed to save config".toKey()) ) return "removed ${arguments.twitchUserName} from ${channel.mention}" @@ -864,7 +865,7 @@ class TwitchExtension() : Extension(), Klogging { twitchConfig.copy( messageId = message.id ) - ) ?: relayError("failed to save config") + ) ?: relayError("failed to save config".toKey()) ) } diff --git a/test_DockerFile b/test_DockerFile new file mode 100644 index 0000000..2bb277d --- /dev/null +++ b/test_DockerFile @@ -0,0 +1,3 @@ +# escape=\ +# syntax=docker/dockerfile:1 +