From 75e31faa802f07d6d9713f35468483bf0ae3ec40 Mon Sep 17 00:00:00 2001 From: expeehaa Date: Sun, 26 Nov 2023 18:41:55 +0100 Subject: [PATCH 1/6] Add parameters for name and description localization to the application command create and edit methods. --- lib/discordrb/api/application.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/discordrb/api/application.rb b/lib/discordrb/api/application.rb index dc5f7d50e..a3ccc7170 100644 --- a/lib/discordrb/api/application.rb +++ b/lib/discordrb/api/application.rb @@ -30,13 +30,13 @@ def get_global_command(token, application_id, command_id) # Create a global application command. # https://discord.com/developers/docs/interactions/slash-commands#create-global-application-command - def create_global_command(token, application_id, name, description, options = [], default_permission = nil, type = 1, default_member_permissions = nil, contexts = nil) + def create_global_command(token, application_id, name, description, options = [], default_permission = nil, type = 1, default_member_permissions = nil, contexts = nil, name_localizations = {}, description_localizations = {}) Discordrb::API.request( :applications_aid_commands, nil, :post, "#{Discordrb::API.api_base}/applications/#{application_id}/commands", - { name: name, description: description, options: options, default_permission: default_permission, type: type, default_member_permissions: default_member_permissions, contexts: contexts }.to_json, + { name: name, description: description, options: options, default_permission: default_permission, type: type, default_member_permissions: default_member_permissions, contexts: contexts, name_localizations: name_localizations, description_localizations: description_localizations }.to_json, Authorization: token, content_type: :json ) @@ -44,13 +44,13 @@ def create_global_command(token, application_id, name, description, options = [] # Edit a global application command. # https://discord.com/developers/docs/interactions/slash-commands#edit-global-application-command - def edit_global_command(token, application_id, command_id, name = nil, description = nil, options = nil, default_permission = nil, type = 1, default_member_permissions = nil, contexts = nil) + def edit_global_command(token, application_id, command_id, name = nil, description = nil, options = nil, default_permission = nil, type = 1, default_member_permissions = nil, contexts = nil, name_localizations = {}, description_localizations = {}) Discordrb::API.request( :applications_aid_commands_cid, nil, :patch, "#{Discordrb::API.api_base}/applications/#{application_id}/commands/#{command_id}", - { name: name, description: description, options: options, default_permission: default_permission, type: type, default_member_permissions: default_member_permissions, contexts: contexts }.compact.to_json, + { name: name, description: description, options: options, default_permission: default_permission, type: type, default_member_permissions: default_member_permissions, contexts: contexts, name_localizations: name_localizations, description_localizations: description_localizations }.compact.to_json, Authorization: token, content_type: :json ) @@ -108,13 +108,13 @@ def get_guild_command(token, application_id, guild_id, command_id) # Create an application command for a guild. # https://discord.com/developers/docs/interactions/slash-commands#create-guild-application-command - def create_guild_command(token, application_id, guild_id, name, description, options = nil, default_permission = nil, type = 1, default_member_permissions = nil, contexts = nil) + def create_guild_command(token, application_id, guild_id, name, description, options = nil, default_permission = nil, type = 1, default_member_permissions = nil, contexts = nil, name_localizations = {}, description_localizations = {}) Discordrb::API.request( :applications_aid_guilds_gid_commands, guild_id, :post, "#{Discordrb::API.api_base}/applications/#{application_id}/guilds/#{guild_id}/commands", - { name: name, description: description, options: options, default_permission: default_permission, type: type, default_member_permissions: default_member_permissions, contexts: contexts }.to_json, + { name: name, description: description, options: options, default_permission: default_permission, type: type, default_member_permissions: default_member_permissions, contexts: contexts, name_localizations: name_localizations, description_localizations: description_localizations }.to_json, Authorization: token, content_type: :json ) @@ -122,13 +122,13 @@ def create_guild_command(token, application_id, guild_id, name, description, opt # Edit an application command for a guild. # https://discord.com/developers/docs/interactions/slash-commands#edit-guild-application-command - def edit_guild_command(token, application_id, guild_id, command_id, name = nil, description = nil, options = nil, default_permission = nil, type = 1, default_member_permissions = nil, contexts = nil) + def edit_guild_command(token, application_id, guild_id, command_id, name = nil, description = nil, options = nil, default_permission = nil, type = 1, default_member_permissions = nil, contexts = nil, name_localizations = {}, description_localizations = {}) Discordrb::API.request( :applications_aid_guilds_gid_commands_cid, guild_id, :patch, "#{Discordrb::API.api_base}/applications/#{application_id}/guilds/#{guild_id}/commands/#{command_id}", - { name: name, description: description, options: options, default_permission: default_permission, type: type, default_member_permissions: default_member_permissions, contexts: contexts }.compact.to_json, + { name: name, description: description, options: options, default_permission: default_permission, type: type, default_member_permissions: default_member_permissions, contexts: contexts, name_localizations: name_localizations, description_localizations: description_localizations }.compact.to_json, Authorization: token, content_type: :json ) From 0299228491037a0a83b96ea627ac7647f93bb5da Mon Sep 17 00:00:00 2001 From: expeehaa Date: Sun, 26 Nov 2023 19:06:09 +0100 Subject: [PATCH 2/6] Add fields for name and description localizations to the parsed application command object. --- lib/discordrb/data/interaction.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/discordrb/data/interaction.rb b/lib/discordrb/data/interaction.rb index 4f0bcebac..e9f3af761 100644 --- a/lib/discordrb/data/interaction.rb +++ b/lib/discordrb/data/interaction.rb @@ -327,9 +327,15 @@ class ApplicationCommand # @return [String] attr_reader :name + # @return [Hash, nil] + attr_reader :name_localizations + # @return [String] attr_reader :description + # @return [Hash, nil] + attr_reader :description_localizations + # @return [true, false] attr_reader :default_permission @@ -347,7 +353,9 @@ def initialize(data, bot, server_id = nil) @server_id = server_id&.to_i @name = data['name'] + @name_localizations = data['name_localizations'] @description = data['description'] + @description_localizations = data['description_localizations'] @default_permission = data['default_permission'] @options = data['options'] end From 4cce718afaccca793ff90b305e9e52ad1e12fbcd Mon Sep 17 00:00:00 2001 From: expeehaa Date: Sun, 26 Nov 2023 19:14:00 +0100 Subject: [PATCH 3/6] Add support for name and description localizations to higher-level methods for creating and editing of application commands. --- lib/discordrb/bot.rb | 12 ++++++------ lib/discordrb/data/interaction.rb | 6 ++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/discordrb/bot.rb b/lib/discordrb/bot.rb index 9fb43b91d..664aad982 100644 --- a/lib/discordrb/bot.rb +++ b/lib/discordrb/bot.rb @@ -831,7 +831,7 @@ def get_application_command(command_id, server_id: nil) # end # end # end - def register_application_command(name, description, server_id: nil, default_permission: nil, type: :chat_input, default_member_permissions: nil, contexts: nil) + def register_application_command(name, description, server_id: nil, default_permission: nil, type: :chat_input, default_member_permissions: nil, contexts: nil, name_localizations: nil, description_localizations: nil) type = ApplicationCommand::TYPES[type] || type builder = Interactions::OptionBuilder.new @@ -839,9 +839,9 @@ def register_application_command(name, description, server_id: nil, default_perm yield(builder, permission_builder) if block_given? resp = if server_id - API::Application.create_guild_command(@token, profile.id, server_id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts) + API::Application.create_guild_command(@token, profile.id, server_id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts, name_localizations, description_localizations) else - API::Application.create_global_command(@token, profile.id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts) + API::Application.create_global_command(@token, profile.id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts, name_localizations, description_localizations) end cmd = ApplicationCommand.new(JSON.parse(resp), self, server_id) @@ -856,7 +856,7 @@ def register_application_command(name, description, server_id: nil, default_perm # @yieldparam [OptionBuilder] # @yieldparam [PermissionBuilder] - def edit_application_command(command_id, server_id: nil, name: nil, description: nil, default_permission: nil, type: :chat_input, default_member_permissions: nil, contexts: nil) + def edit_application_command(command_id, server_id: nil, name: nil, description: nil, default_permission: nil, type: :chat_input, default_member_permissions: nil, contexts: nil, name_localizations: nil, description_localizations: nil) type = ApplicationCommand::TYPES[type] || type builder = Interactions::OptionBuilder.new @@ -865,9 +865,9 @@ def edit_application_command(command_id, server_id: nil, name: nil, description: yield(builder, permission_builder) if block_given? resp = if server_id - API::Application.edit_guild_command(@token, profile.id, server_id, command_id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts) + API::Application.edit_guild_command(@token, profile.id, server_id, command_id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts, name_localizations, description_localizations) else - API::Application.edit_global_command(@token, profile.id, command_id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts) + API::Application.edit_global_command(@token, profile.id, command_id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts, name_localizations, description_localizations) end cmd = ApplicationCommand.new(JSON.parse(resp), self, server_id) diff --git a/lib/discordrb/data/interaction.rb b/lib/discordrb/data/interaction.rb index e9f3af761..7b464cfbf 100644 --- a/lib/discordrb/data/interaction.rb +++ b/lib/discordrb/data/interaction.rb @@ -380,10 +380,12 @@ def mention(subcommand_group: nil, subcommand: nil) # @param name [String] The name to use for this command. # @param description [String] The description of this command. # @param default_permission [true, false] Whether this command is available with default permissions. + # @param name_localizations [Hash] The localized names of the command. + # @param description_localizations [Hash] The localized descriptions of the command. # @yieldparam (see Bot#edit_application_command) # @return (see Bot#edit_application_command) - def edit(name: nil, description: nil, default_permission: nil, &block) - @bot.edit_application_command(@id, server_id: @server_id, name: name, description: description, default_permission: default_permission, &block) + def edit(name: nil, description: nil, default_permission: nil, name_localizations: nil, description_localizations: nil, &block) + @bot.edit_application_command(@id, server_id: @server_id, name: name, description: description, default_permission: default_permission, name_localizations: name_localizations, description_localizations: description_localizations, &block) end # Delete this application command. From 7cb619cf5443f6a28e5ddd818e40aabe895b029d Mon Sep 17 00:00:00 2001 From: expeehaa Date: Sun, 26 Nov 2023 19:22:31 +0100 Subject: [PATCH 4/6] Add support for name and description localizations to the Discord::Interactions::OptionBuilder methods. --- lib/discordrb/data/interaction.rb | 70 ++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/lib/discordrb/data/interaction.rb b/lib/discordrb/data/interaction.rb index 7b464cfbf..5ee7bfedd 100644 --- a/lib/discordrb/data/interaction.rb +++ b/lib/discordrb/data/interaction.rb @@ -439,6 +439,8 @@ def initialize # @param name [String, Symbol] The name of the subcommand. # @param description [String] A description of the subcommand. + # @param name_localizations [Hash, nil] The localized names of the subcommand. + # @param description_localizations [Hash, nil] The localized descriptions of the subcommand. # @yieldparam [OptionBuilder] # @return (see #option) # @example @@ -447,15 +449,17 @@ def initialize # sub.string('message', 'What to echo back', required: true) # end # end - def subcommand(name, description) + def subcommand(name, description, name_localizations: nil, description_localizations: nil) builder = OptionBuilder.new yield builder if block_given? - option(TYPES[:subcommand], name, description, options: builder.to_a) + option(TYPES[:subcommand], name, description, options: builder.to_a, name_localizations: name_localizations, description_localizations: description_localizations) end # @param name [String, Symbol] The name of the subcommand group. # @param description [String] A description of the subcommand group. + # @param name_localizations [Hash, nil] The localized names of the subcommand group. + # @param description_localizations [Hash, nil] The localized descriptions of the subcommand group. # @yieldparam [OptionBuilder] # @return (see #option) # @example @@ -466,11 +470,11 @@ def subcommand(name, description) # end # end # end - def subcommand_group(name, description) + def subcommand_group(name, description, name_localizations: nil, description_localizations: nil) builder = OptionBuilder.new yield builder - option(TYPES[:subcommand_group], name, description, options: builder.to_a) + option(TYPES[:subcommand_group], name, description, options: builder.to_a, name_localizations: name_localizations, description_localizations: description_localizations) end # @param name [String, Symbol] The name of the argument. @@ -479,10 +483,12 @@ def subcommand_group(name, description) # @param min_length [Integer] A minimum length for option value. # @param max_length [Integer] A maximum length for option value. # @param choices [Hash, nil] Available choices, mapped as `Name => Value`. + # @param name_localizations [Hash, nil] The localized names of the argument. + # @param description_localizations [Hash, nil] The localized descriptions of the argument. # @return (see #option) - def string(name, description, required: nil, min_length: nil, max_length: nil, choices: nil) + def string(name, description, required: nil, min_length: nil, max_length: nil, choices: nil, name_localizations: nil, description_localizations: nil) option(TYPES[:string], name, description, - required: required, min_length: min_length, max_length: max_length, choices: choices) + required: required, min_length: min_length, max_length: max_length, choices: choices, name_localizations: name_localizations, description_localizations: description_localizations) end # @param name [String, Symbol] The name of the argument. @@ -491,52 +497,64 @@ def string(name, description, required: nil, min_length: nil, max_length: nil, c # @param min_value [Integer] A minimum value for option. # @param max_value [Integer] A maximum value for option. # @param choices [Hash, nil] Available choices, mapped as `Name => Value`. + # @param name_localizations [Hash, nil] The localized names of the argument. + # @param description_localizations [Hash, nil] The localized descriptions of the argument. # @return (see #option) - def integer(name, description, required: nil, min_value: nil, max_value: nil, choices: nil) + def integer(name, description, required: nil, min_value: nil, max_value: nil, choices: nil, name_localizations: nil, description_localizations: nil) option(TYPES[:integer], name, description, - required: required, min_value: min_value, max_value: max_value, choices: choices) + required: required, min_value: min_value, max_value: max_value, choices: choices, name_localizations: name_localizations, description_localizations: description_localizations) end # @param name [String, Symbol] The name of the argument. # @param description [String] A description of the argument. # @param required [true, false] Whether this option must be provided. + # @param name_localizations [Hash, nil] The localized names of the argument. + # @param description_localizations [Hash, nil] The localized descriptions of the argument. # @return (see #option) - def boolean(name, description, required: nil) - option(TYPES[:boolean], name, description, required: required) + def boolean(name, description, required: nil, name_localizations: nil, description_localizations: nil) + option(TYPES[:boolean], name, description, required: required, name_localizations: name_localizations, description_localizations: description_localizations) end # @param name [String, Symbol] The name of the argument. # @param description [String] A description of the argument. # @param required [true, false] Whether this option must be provided. + # @param name_localizations [Hash, nil] The localized names of the argument. + # @param description_localizations [Hash, nil] The localized descriptions of the argument. # @return (see #option) - def user(name, description, required: nil) - option(TYPES[:user], name, description, required: required) + def user(name, description, required: nil, name_localizations: nil, description_localizations: nil) + option(TYPES[:user], name, description, required: required, name_localizations: name_localizations, description_localizations: description_localizations) end # @param name [String, Symbol] The name of the argument. # @param description [String] A description of the argument. # @param required [true, false] Whether this option must be provided. # @param types [Array] See {CHANNEL_TYPES} + # @param name_localizations [Hash, nil] The localized names of the argument. + # @param description_localizations [Hash, nil] The localized descriptions of the argument. # @return (see #option) - def channel(name, description, required: nil, types: nil) + def channel(name, description, required: nil, types: nil, name_localizations: nil, description_localizations: nil) types = types&.collect { |type| type.is_a?(Numeric) ? type : CHANNEL_TYPES[type] } - option(TYPES[:channel], name, description, required: required, channel_types: types) + option(TYPES[:channel], name, description, required: required, channel_types: types, name_localizations: name_localizations, description_localizations: description_localizations) end # @param name [String, Symbol] The name of the argument. # @param description [String] A description of the argument. # @param required [true, false] Whether this option must be provided. + # @param name_localizations [Hash, nil] The localized names of the argument. + # @param description_localizations [Hash, nil] The localized descriptions of the argument. # @return (see #option) - def role(name, description, required: nil) - option(TYPES[:role], name, description, required: required) + def role(name, description, required: nil, name_localizations: nil, description_localizations: nil) + option(TYPES[:role], name, description, required: required, name_localizations: name_localizations, description_localizations: description_localizations) end # @param name [String, Symbol] The name of the argument. # @param description [String] A description of the argument. # @param required [true, false] Whether this option must be provided. + # @param name_localizations [Hash, nil] The localized names of the argument. + # @param description_localizations [Hash, nil] The localized descriptions of the argument. # @return (see #option) - def mentionable(name, description, required: nil) - option(TYPES[:mentionable], name, description, required: required) + def mentionable(name, description, required: nil, name_localizations: nil, description_localizations: nil) + option(TYPES[:mentionable], name, description, required: required, name_localizations: name_localizations, description_localizations: description_localizations) end # @param name [String, Symbol] The name of the argument. @@ -545,17 +563,19 @@ def mentionable(name, description, required: nil) # @param min_value [Float] A minimum value for option. # @param max_value [Float] A maximum value for option. # @return (see #option) - def number(name, description, required: nil, min_value: nil, max_value: nil, choices: nil) + def number(name, description, required: nil, min_value: nil, max_value: nil, choices: nil, name_localizations: nil, description_localizations: nil) option(TYPES[:number], name, description, - required: required, min_value: min_value, max_value: max_value, choices: choices) + required: required, min_value: min_value, max_value: max_value, choices: choices, name_localizations: name_localizations, description_localizations: description_localizations) end # @param name [String, Symbol] The name of the argument. # @param description [String] A description of the argument. # @param required [true, false] Whether this option must be provided. + # @param name_localizations [Hash, nil] The localized names of the argument. + # @param description_localizations [Hash, nil] The localized descriptions of the argument. # @return (see #option) - def attachment(name, description, required: nil) - option(TYPES[:attachment], name, description, required: required) + def attachment(name, description, required: nil, name_localizations: nil, description_localizations: nil) + option(TYPES[:attachment], name, description, required: required, name_localizations: name_localizations, description_localizations: description_localizations) end # @!visibility private @@ -568,10 +588,12 @@ def attachment(name, description, required: nil) # @param min_length [Integer] A minimum length for string option value. # @param max_length [Integer] A maximum length for string option value. # @param channel_types [Array] Channel types that can be provides for channel options. + # @param name_localizations [Hash, nil] The localized names of the argument. + # @param description_localizations [Hash, nil] The localized descriptions of the argument. # @return Hash def option(type, name, description, required: nil, choices: nil, options: nil, min_value: nil, max_value: nil, - min_length: nil, max_length: nil, channel_types: nil) - opt = { type: type, name: name, description: description } + min_length: nil, max_length: nil, channel_types: nil, name_localizations: nil, description_localizations: nil) + opt = { type: type, name: name, description: description, name_localizations: name_localizations, description_localizations: description_localizations }.compact choices = choices.map { |option_name, value| { name: option_name, value: value } } if choices opt.merge!({ required: required, choices: choices, options: options, min_value: min_value, From 62469deb66e6f7a781af8e1d6e48b1a813d3f580 Mon Sep 17 00:00:00 2001 From: expeehaa Date: Sun, 26 Nov 2023 19:49:06 +0100 Subject: [PATCH 5/6] Update slash commands example to include name and description localizations. --- examples/slash_commands.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/slash_commands.rb b/examples/slash_commands.rb index fae4802f9..001176484 100644 --- a/examples/slash_commands.rb +++ b/examples/slash_commands.rb @@ -11,10 +11,10 @@ # # You may want to have a separate script for registering your commands so you don't need to do this every # time you start your bot. -bot.register_application_command(:example, 'Example commands', server_id: ENV.fetch('SLASH_COMMAND_BOT_SERVER_ID', nil)) do |cmd| +bot.register_application_command(:example, 'Example commands', server_id: ENV.fetch('SLASH_COMMAND_BOT_SERVER_ID', nil), name_localizations: { 'de' => 'beispiel' }, description_localizations: { 'de' => 'Beispielbefehle' }) do |cmd| cmd.subcommand_group(:fun, 'Fun things!') do |group| group.subcommand('8ball', 'Shake the magic 8 ball') do |sub| - sub.string('question', 'Ask a question to receive wisdom', required: true) + sub.string('question', 'Ask a question to receive wisdom', required: true, name_localizations: { 'de' => 'frage' }, description_localizations: { 'de' => 'Stell eine Frage um Weisheit zu erlangen' }) end group.subcommand('java', 'What if it was java?') From 2c990aafafb58f7471707b517eb5ece63a17be0a Mon Sep 17 00:00:00 2001 From: expeehaa Date: Tue, 15 Oct 2024 20:00:14 +0200 Subject: [PATCH 6/6] Support requesting global and guild commands with or without localizations. --- lib/discordrb/api/application.rb | 8 ++++---- lib/discordrb/bot.rb | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/discordrb/api/application.rb b/lib/discordrb/api/application.rb index a3ccc7170..4dfbe968f 100644 --- a/lib/discordrb/api/application.rb +++ b/lib/discordrb/api/application.rb @@ -6,12 +6,12 @@ module Discordrb::API::Application # Get a list of global application commands. # https://discord.com/developers/docs/interactions/slash-commands#get-global-application-commands - def get_global_commands(token, application_id) + def get_global_commands(token, application_id, with_localizations: nil) Discordrb::API.request( :applications_aid_commands, nil, :get, - "#{Discordrb::API.api_base}/applications/#{application_id}/commands", + "#{Discordrb::API.api_base}/applications/#{application_id}/commands#{"?with_localizations=#{!!with_localizations}" unless with_localizations.nil?}", Authorization: token ) end @@ -84,12 +84,12 @@ def bulk_overwrite_global_commands(token, application_id, commands) # Get a guild's commands for an application. # https://discord.com/developers/docs/interactions/slash-commands#get-guild-application-commands - def get_guild_commands(token, application_id, guild_id) + def get_guild_commands(token, application_id, guild_id, with_localizations: nil) Discordrb::API.request( :applications_aid_guilds_gid_commands, guild_id, :get, - "#{Discordrb::API.api_base}/applications/#{application_id}/guilds/#{guild_id}/commands", + "#{Discordrb::API.api_base}/applications/#{application_id}/guilds/#{guild_id}/commands#{"?with_localizations=#{!!with_localizations}" unless with_localizations.nil?}", Authorization: token ) end diff --git a/lib/discordrb/bot.rb b/lib/discordrb/bot.rb index 664aad982..eb1893fc8 100644 --- a/lib/discordrb/bot.rb +++ b/lib/discordrb/bot.rb @@ -792,12 +792,13 @@ def prune_empty_groups # Get all application commands. # @param server_id [String, Integer, nil] The ID of the server to get the commands from. Global if `nil`. + # @param with_localizations [true, false, nil] Whether the full localizations of commands should be included in the result. `nil` requests the Discord API default. # @return [Array] - def get_application_commands(server_id: nil) + def get_application_commands(server_id: nil, with_localizations: nil) resp = if server_id - API::Application.get_guild_commands(@token, profile.id, server_id) + API::Application.get_guild_commands(@token, profile.id, server_id, with_localizations: with_localizations) else - API::Application.get_global_commands(@token, profile.id) + API::Application.get_global_commands(@token, profile.id, with_localizations: with_localizations) end JSON.parse(resp).map do |command_data|