galacticwarrior9 / IslamBot

A Discord bot that supports Qur'an, hadith, prayer times, tafsir and more.
GNU General Public License v3.0
87 stars 36 forks source link

Localization #43

Open galacticwarrior9 opened 2 years ago

galacticwarrior9 commented 2 years ago

The bot is used on several servers where the primary language is neither English or Arabic.

The usage of user-contributed translations will increase the accessibility of the bot to more communities.

itzmk21 commented 2 years ago

Add a command to set language of a server? And, how exactly will this be coded? Is there any other way than repeating the same string for multiple languages, then doing a check for the language of the server?

MuhammadSaadSiddique commented 1 year ago

look to help need some knowledge about this issue

msabur commented 1 year ago

Discord.py supports localizing slash commands based on a user's selected language. It works for command names, command descriptions, parameter names, parameter descriptions, and choice names.

Documentation: https://discordpy.readthedocs.io/en/latest/interactions/api.html?highlight=translation#discord.app_commands.Translator

Small example that prepends “gb” to all texts for en-GB users:

# translation.py
from typing import Optional
import discord

class MyCustomTranslator(discord.app_commands.Translator):
    async def translate(self, string: discord.app_commands.locale_str, locale: discord.Locale, context: discord.app_commands.TranslationContext) -> Optional[str]:
        message_str = string.message
        locale_str = str(locale)

        if locale_str == 'en-GB':
            return 'gb' + message_str
        else:
            return None

and then in the setup_hook there would be an extra line await bot.tree.set_translator(MyCustomTranslator()).

itzmk21 commented 1 year ago

So, there's this:

class MyCustomTranslator(app_commands.Translator):
  async def load(self):
    # this gets called when the translator first gets loaded!
  async def unload(self):
    # in case you need to switch translators, this gets called when being removed
  async def translate(self, string: app_commands.locale_str, locale: discord.Locale, context: app_commands.TranslationContext) -> Optional[str]:
    """
    `locale_str` is the string that is requesting to be translated
    `locale` is the target language to translate to
    `context` is the origin of this string, eg TranslationContext.command_name, etc
    This function must return a string (that's been translated), or `None` to signal no available translation available, and will default to the original.
    """
    message_str = string.message
    return your_translate(message_str)
# IMPORTANT! put this in your `setup_hook` function
await bot.tree.set_translator(MyCustomTranslator())
# Optional, but helps save a lot of typing
from discord.app_commands import locale_str as _T
@app_commands.command(name=_T("bonk"))
@app_commands.describe(user=_T("The user to bonk."))
async def bonk(interaction: discord.Interaction, user: discord.User):
  await interaction.response.send_message(f":hammer: {user.mention}")

The digging around I've done suggest we need a format of how translations will be stored, right? One possible solution is using the gettext module in Python, then storing translations in different files, or maybe simply a JSON file, I really don't know lol.

msabur commented 11 months ago

I think using gettext would be better. Using JSON would give the greatest flexibility. However, with gettext there are CLI tools to help with management tasks like updating translations when the strings change. There are also GUI/CLI tools for working with translation files, which could help contributors. Downsides of gettext are that there’s an extra step of compiling the translation files, and that the CLI tools can have a slight learning curve.