discorddiscord.pycommand

Translating bot.tree.commands


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?


Solution

  • 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:

    translation working

    I switched my language to spanish and it translated the command name.

    References: