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))