I saw this in several bots and I also wanted to test it on my own, that when bots had a simple bot.tree.command command such as /play, the further parameters of this command, i.e. description and its options were translated into my language set on Discord, and how can I also do this?
Looking at the documentation: https://discordpy.readthedocs.io/en/stable/interactions/api.html?highlight=translate#discord.app_commands.Translator
You can translate commands into your language set quite easily (either manually or through a translator).
This took me an hour to figure out but I found this post: https://github.com/Rapptz/discord.py/discussions/9160
In there, Rapptz makes a translator. The docs is a little confusing on how to do this but the post defintely helped. Here's my implementation:
from typing import Optional
import discord
import os
from discord import app_commands, Locale
from discord.app_commands import locale_str, TranslationContextTypes
from discord.ui import Select
intents = discord.Intents.default()
bot = discord.Client(intents=intents)
tree = app_commands.CommandTree(bot)
class epicTranslator(discord.app_commands.Translator): # https://github.com/Rapptz/discord.py/discussions/9160
async def translate(self, string: locale_str, locale: Locale, context: TranslationContextTypes) -> Optional[str]:
message = str(string)
if locale is discord.Locale.spain_spanish:
if message == 'testing_options':
return 'opciones_de_prueba'
@bot.event
async def on_ready():
await tree.set_translator(epicTranslator())
await tree.sync()
print('tree synced')
class View(discord.ui.View):
@discord.ui.select(cls=Select, options=[discord.SelectOption(label=x, value=x) for x in
['France', 'other_country', 'other_other_country']])
async def select_country(self, interaction: discord.Interaction, select):
return await interaction.response.send_message(f'You selected {select.values[0]}')
@tree.command(name=discord.app_commands.locale_str("testing_options"))
@app_commands.choices(food=[
app_commands.Choice(name="Choice_one", value="1"),
app_commands.Choice(name="Choice_two", value="2")
])
async def testing_options(ctx, food: app_commands.Choice[str]):
if food == "1":
await ctx.response.send_message('Hello', view=View())
else:
await ctx.response.send_message('Hello2', view=View())
# Translate
TOKEN = os.getenv('DISCORD_TOKEN_KEY')
bot.run(os.getenv('TOKEN'))
It might be a lot of code, so I'll go step by step:
class epicTranslator(discord.app_commands.Translator): # https://github.com/Rapptz/discord.py/discussions/9160
async def translate(self, string: locale_str, locale: Locale, context: TranslationContextTypes) -> Optional[str]:
message = str(string)
if locale is discord.Locale.spain_spanish:
if message == 'testing_options':
return 'opciones_de_prueba'
The above code uses a translator object which you'll use in on_ready
to set your translator to. In this object, you can set the translate
function to return whatever value you want to translate per string. Here's where you can implement a translator library.
@bot.event
async def on_ready():
await tree.set_translator(epicTranslator())
await tree.sync()
print('tree synced')
In on_ready
is where you'll want to set the translator and sync! Syncing is important.
@tree.command(name=discord.app_commands.locale_str("testing_options"))
This is the only time I actually use the translator. When you translate, use discord.app_commands.locale_str("command name or whatever"
. It's also important that if it's a command name that the name here be the same as the command name!. You can also use this for "commands, parameters, and choices."
As you can see below, this implementation works:
I switched my language to spanish and it translated the command name.
References: