test / bot /cogs /language.py
mtaaz's picture
Upload 94 files
91c7f83 verified
from bot.i18n import get_cmd_desc
"""
Language cog: Multi-language support for the bot.
Provides a beautiful panel for changing server language.
"""
import discord
from discord.ext import commands
from bot.i18n import SUPPORTED_LANGUAGES, translate
from bot.theme import NEON_CYAN, NEON_LIME, panel_divider, success_embed, shimmer
LANGUAGE_META: dict[str, tuple[str, str]] = {
"ar": ("العربية", "🇸🇦"),
"en": ("English", "🇬🇧"),
"es": ("Español", "🇪🇸"),
"fr": ("Français", "🇫🇷"),
"de": ("Deutsch", "🇩🇪"),
"tr": ("Türkçe", "🇹🇷"),
"it": ("Italiano", "🇮🇹"),
"pt": ("Português", "🇵🇹"),
"ru": ("Русский", "🇷🇺"),
"hi": ("हिन्दी", "🇮🇳"),
"id": ("Indonesia", "🇮🇩"),
"ja": ("日本語", "🇯🇵"),
"zh": ("中文", "🇨🇳"),
"he": ("עברית", "🇮🇱"),
}
class LanguageSelect(discord.ui.Select):
def __init__(self, cog: "Language", guild_id: int, current_code: str) -> None:
self.cog = cog
self.guild_id = guild_id
options: list[discord.SelectOption] = []
dynamic_supported = sorted(
getattr(getattr(cog.bot, "translator", None), "supported_languages", set(SUPPORTED_LANGUAGES))
)
for code in dynamic_supported:
label, emoji = LANGUAGE_META.get(code, (code.upper(), "🌐"))
options.append(
discord.SelectOption(
label=label,
value=code,
emoji=emoji,
description=f"{code.upper()} language",
default=code == current_code,
)
)
super().__init__(
placeholder="Choose server language",
min_values=1,
max_values=1,
options=options[:25],
custom_id="lang:select",
)
async def callback(self, interaction: discord.Interaction) -> None:
if not interaction.guild:
await interaction.response.send_message(translate("en", "common.server_only"), ephemeral=True)
return
selected = self.values[0]
# Special rule requested by owner: Hebrew is visible but cannot be set.
if selected == "he":
current_code = await self.cog._current_code(interaction.guild.id)
for option in self.options:
option.default = option.value == current_code
embed = await self.cog._language_embed(interaction.guild.id, current_code)
await interaction.response.edit_message(embed=embed, view=self.view)
await interaction.followup.send("only you know this language", ephemeral=True)
return
await self.cog.bot.db.execute(
"INSERT INTO guild_config(guild_id, guild_language) VALUES (?, ?) "
"ON CONFLICT(guild_id) DO UPDATE SET guild_language = excluded.guild_language",
interaction.guild.id,
selected,
)
for option in self.options:
option.default = option.value == selected
embed = await self.cog._language_embed(interaction.guild.id, selected)
await interaction.response.edit_message(embed=embed, view=self.view)
# Send follow-up with hint to open /menu
lang_name = LANGUAGE_META.get(selected, (selected.upper(), "🌐"))[0]
hint_msg = translate(selected, "lang.updated")
followup_embed = discord.Embed(
title=f"✅ Language Changed!",
description=f"{panel_divider('lime')}\n{hint_msg}\n\n💡 Use `/menu` to see all commands in your selected language!\n{panel_divider('lime')}",
color=NEON_LIME,
)
await interaction.followup.send(embed=followup_embed, ephemeral=True)
class LanguagePanelView(discord.ui.View):
def __init__(self, cog: "Language", guild_id: int, current_code: str) -> None:
super().__init__(timeout=None)
self.add_item(LanguageSelect(cog, guild_id, current_code))
class Language(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
async def cog_load(self) -> None:
self.bot.add_view(LanguagePanelView(self, 0, "ar"))
async def _current_code(self, guild_id: int) -> str:
row = await self.bot.db.fetchone("SELECT guild_language FROM guild_config WHERE guild_id = ?", guild_id)
supported = set(getattr(getattr(self.bot, "translator", None), "supported_languages", set(SUPPORTED_LANGUAGES)))
return row[0] if row and row[0] in supported else "ar"
async def _language_embed(self, guild_id: int, current_code: str) -> discord.Embed:
current_name = LANGUAGE_META.get(current_code, (current_code.upper(), "🌐"))[0]
current_emoji = LANGUAGE_META.get(current_code, (current_code.upper(), "🌐"))[1]
lines = []
supported = sorted(
getattr(getattr(self.bot, "translator", None), "supported_languages", set(SUPPORTED_LANGUAGES))
)
for code in supported:
name, emoji = LANGUAGE_META.get(code, (code.upper(), "🌐"))
marker = "✅" if code == current_code else "▫️"
lines.append(f"{marker} {emoji} **{name}** `({code})`")
# Get translated content
title = translate(current_code, "lang.current").replace("{globe}", "🌍")
embed = discord.Embed(
title="🌍 Language Control Panel",
description=(
f"{shimmer('Current Language')}: **{current_emoji} {current_name}** (`{current_code}`)\n"
f"{panel_divider('cyan')}\n"
f"Pick your server language from the dropdown below.\n"
f"All bot messages and panels will use the selected language!"
),
color=NEON_CYAN,
)
embed.add_field(name="🌐 Supported Languages", value="\n".join(lines[:20]), inline=False)
embed.add_field(
name="💡 Tips",
value=(
"• Language changes apply instantly\n"
"• Use `/menu` to see commands in your language\n"
"• Available full locales: Arabic, English, Spanish, French, German"
),
inline=False
)
embed.set_footer(text="Changes apply instantly across bot messages and panels")
return embed
@commands.hybrid_command(name="language", description=get_cmd_desc("commands.tools.language_desc"))
@commands.has_permissions(manage_guild=True)
async def language(self, ctx: commands.Context) -> None:
if not ctx.guild:
await ctx.reply(translate("en", "common.server_only"))
return
current_code = await self._current_code(ctx.guild.id)
embed = await self._language_embed(ctx.guild.id, current_code)
view = LanguagePanelView(self, ctx.guild.id, current_code)
await ctx.reply(embed=embed, view=view)
@commands.hybrid_command(name="languages", description=get_cmd_desc("commands.tools.languages_desc"), hidden=True, with_app_command=False)
async def languages(self, ctx: commands.Context) -> None:
guild_id = ctx.guild.id if ctx.guild else None
lang = await self.bot.get_guild_language(guild_id)
pretty = [f"{LANGUAGE_META.get(code, (code.upper(), '🌐'))[1]} **{LANGUAGE_META.get(code, (code.upper(), '🌐'))[0]}** (`{code}`)" for code in LANGUAGE_META]
embed = discord.Embed(
title="🌍 Supported Languages",
description=f"{panel_divider('cyan')}\n" + "\n".join(pretty) + f"\n{panel_divider('cyan')}",
color=NEON_CYAN,
)
embed.set_footer(text=f"Current: {LANGUAGE_META.get(lang, (lang.upper(), '🌐'))[0]}")
await ctx.reply(embed=embed)
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(Language(bot))