Repository: Cog-Creators/Red-DiscordBot

Issue:
Help isn't translatable - pot files for strings aren't created
Only thing from `help.py` that gets added to `.po` files is help docstring for `[p]help`.


Discussion:
Reason for this is us using `T_` instead of `_` which prevent `gettext` from picking those strings.

There's also another problem with using Translator inside f-string, e.g. `f"{_('Syntax')}"` won't get picked after changing from `T_`, this is a bigger issue that we would need to fix in redgettext (and probably avoid such usage until then) if we want to have it supported.
Can't we just switch ``T_`` for ``_`` and change the f-strings to use ``.format()`` ?
We can, the f-string issue will probably not be fixed any time soon (even though I do have code for `pygettext` that could probably just be applied to `redgettext`, but I am not so sure about its quality) and the `T_` could just be added to keywords supported by `redgettext`, although I am not sure why `T_` was used over `_` here.

Resolving patch:
diff --git a/redbot/core/commands/help.py b/redbot/core/commands/help.py
--- a/redbot/core/commands/help.py
+++ b/redbot/core/commands/help.py
@@ -50,7 +50,7 @@
 
 __all__ = ["red_help", "RedHelpFormatter", "HelpSettings"]
 
-T_ = Translator("Help", __file__)
+_ = Translator("Help", __file__)
 
 HelpTarget = Union[commands.Command, commands.Group, commands.Cog, dpy_commands.bot.BotBase, str]
 
@@ -179,7 +179,7 @@ async def get_bot_help_mapping(self, ctx, help_settings: HelpSettings):
 
     @staticmethod
     def get_default_tagline(ctx: Context):
-        return T_(
+        return _(
             "Type {ctx.clean_prefix}help <command> for more info on a command. "
             "You can also type {ctx.clean_prefix}help <category> for more info on a category."
         ).format(ctx=ctx)
@@ -190,7 +190,7 @@ async def format_command_help(
 
         send = help_settings.verify_exists
         if not send:
-            async for _ in self.help_filter_func(
+            async for __ in self.help_filter_func(
                 ctx, (obj,), bypass_hidden=True, help_settings=help_settings
             ):
                 # This is a really lazy option for not
@@ -209,9 +209,9 @@ async def format_command_help(
         description = command.description or ""
 
         tagline = (help_settings.tagline) or self.get_default_tagline(ctx)
-        signature = (
-            f"`{T_('Syntax')}: {ctx.clean_prefix}{command.qualified_name} {command.signature}`"
-        )
+        signature = _(
+            "`Syntax: {ctx.clean_prefix}{command.qualified_name} {command.signature}`"
+        ).format(ctx=ctx, command=command)
         subcommands = None
 
         if hasattr(command, "all_commands"):
@@ -250,9 +250,9 @@ def shorten_line(a_line: str) -> str:
                 )
                 for i, page in enumerate(pagify(subtext, page_length=500, shorten_by=0)):
                     if i == 0:
-                        title = T_("**__Subcommands:__**")
+                        title = _("**__Subcommands:__**")
                     else:
-                        title = T_("**__Subcommands:__** (continued)")
+                        title = _("**__Subcommands:__** (continued)")
                     field = EmbedField(title, page, False)
                     emb["fields"].append(field)
 
@@ -263,7 +263,7 @@ def shorten_line(a_line: str) -> str:
             subtext = None
             subtext_header = None
             if subcommands:
-                subtext_header = T_("Subcommands:")
+                subtext_header = _("Subcommands:")
                 max_width = max(discord.utils._string_width(name) for name in subcommands.keys())
 
                 def width_maker(cmds):
@@ -327,7 +327,7 @@ async def make_and_send_embeds(self, ctx, embed_dict: dict, help_settings: HelpS
         page_char_limit = min(page_char_limit, 5500)  # Just in case someone was manually...
 
         author_info = {
-            "name": f"{ctx.me.display_name} {T_('Help Menu')}",
+            "name": _("{ctx.me.display_name} Help Menu").format(ctx=ctx),
             "icon_url": ctx.me.avatar_url,
         }
 
@@ -374,9 +374,9 @@ async def make_and_send_embeds(self, ctx, embed_dict: dict, help_settings: HelpS
             embed = discord.Embed(color=color, **embed_dict["embed"])
 
             if page_count > 1:
-                description = T_(
-                    "*Page {page_num} of {page_count}*\n{content_description}"
-                ).format(content_description=embed.description, page_num=i, page_count=page_count)
+                description = _("*Page {page_num} of {page_count}*\n{content_description}").format(
+                    content_description=embed.description, page_num=i, page_count=page_count
+                )
                 embed.description = description
 
             embed.set_author(**author_info)
@@ -425,9 +425,9 @@ def shorten_line(a_line: str) -> str:
                 )
                 for i, page in enumerate(pagify(command_text, page_length=500, shorten_by=0)):
                     if i == 0:
-                        title = T_("**__Commands:__**")
+                        title = _("**__Commands:__**")
                     else:
-                        title = T_("**__Commands:__** (continued)")
+                        title = _("**__Commands:__** (continued)")
                     field = EmbedField(title, page, False)
                     emb["fields"].append(field)
 
@@ -437,7 +437,7 @@ def shorten_line(a_line: str) -> str:
             subtext = None
             subtext_header = None
             if coms:
-                subtext_header = T_("Commands:")
+                subtext_header = _("Commands:")
                 max_width = max(discord.utils._string_width(name) for name in coms.keys())
 
                 def width_maker(cmds):
@@ -479,7 +479,7 @@ async def format_bot_help(self, ctx: Context, help_settings: HelpSettings):
                 if cog_name:
                     title = f"**__{cog_name}:__**"
                 else:
-                    title = f"**__{T_('No Category')}:__**"
+                    title = _("**__No Category:__**")
 
                 def shorten_line(a_line: str) -> str:
                     if len(a_line) < 70:  # embed max width needs to be lower
@@ -492,7 +492,7 @@ def shorten_line(a_line: str) -> str:
                 )
 
                 for i, page in enumerate(pagify(cog_text, page_length=1000, shorten_by=0)):
-                    title = title if i < 1 else f"{title} {T_('(continued)')}"
+                    title = title if i < 1 else _("{title} (continued)").format(title=title)
                     field = EmbedField(title, page, False)
                     emb["fields"].append(field)
 
@@ -508,7 +508,7 @@ def shorten_line(a_line: str) -> str:
                 names.extend(list(v.name for v in v.values()))
 
             max_width = max(
-                discord.utils._string_width((name or T_("No Category:"))) for name in names
+                discord.utils._string_width((name or _("No Category:"))) for name in names
             )
 
             def width_maker(cmds):
@@ -522,7 +522,7 @@ def width_maker(cmds):
 
             for cog_name, data in coms:
 
-                title = f"{cog_name}:" if cog_name else T_("No Category:")
+                title = f"{cog_name}:" if cog_name else _("No Category:")
                 to_join.append(title)
 
                 for name, doc, width in width_maker(sorted(data.items())):
@@ -579,7 +579,8 @@ async def command_not_found(self, ctx, help_for, help_settings: HelpSettings):
             ret = await format_fuzzy_results(ctx, fuzzy_commands, embed=use_embeds)
             if use_embeds:
                 ret.set_author(
-                    name=f"{ctx.me.display_name} {T_('Help Menu')}", icon_url=ctx.me.avatar_url
+                    name=_("{ctx.me.display_name} Help Menu").format(ctx=ctx),
+                    icon_url=ctx.me.avatar_url,
                 )
                 tagline = help_settings.tagline or self.get_default_tagline(ctx)
                 ret.set_footer(text=tagline)
@@ -587,11 +588,12 @@ async def command_not_found(self, ctx, help_for, help_settings: HelpSettings):
             else:
                 await ctx.send(ret)
         elif help_settings.verify_exists:
-            ret = T_("Help topic for *{command_name}* not found.").format(command_name=help_for)
+            ret = _("Help topic for *{command_name}* not found.").format(command_name=help_for)
             if use_embeds:
                 ret = discord.Embed(color=(await ctx.embed_color()), description=ret)
                 ret.set_author(
-                    name=f"{ctx.me.display_name} {T_('Help Menu')}", icon_url=ctx.me.avatar_url
+                    name=_("{ctx.me.display_name} Help Menu").format(ctx=ctx),
+                    icon_url=ctx.me.avatar_url,
                 )
                 tagline = help_settings.tagline or self.get_default_tagline(ctx)
                 ret.set_footer(text=tagline)
@@ -603,13 +605,14 @@ async def subcommand_not_found(self, ctx, command, not_found, help_settings: Hel
         """
         Sends an error
         """
-        ret = T_("Command *{command_name}* has no subcommand named *{not_found}*.").format(
+        ret = _("Command *{command_name}* has no subcommand named *{not_found}*.").format(
             command_name=command.qualified_name, not_found=not_found[0]
         )
         if await ctx.embed_requested():
             ret = discord.Embed(color=(await ctx.embed_color()), description=ret)
             ret.set_author(
-                name=f"{ctx.me.display_name} {T_('Help Menu')}", icon_url=ctx.me.avatar_url
+                name=_("{ctx.me.display_name} Help Menu").format(ctx=ctx),
+                icon_url=ctx.me.avatar_url,
             )
             tagline = help_settings.tagline or self.get_default_tagline(ctx)
             ret.set_footer(text=tagline)
@@ -677,7 +680,7 @@ async def send_pages(
                         msg = await destination.send(page)
                 except discord.Forbidden:
                     return await ctx.send(
-                        T_(
+                        _(
                             "I couldn't send the help message to you in DM. "
                             "Either you blocked me or you disabled DMs in this server."
                         )
@@ -713,7 +716,7 @@ async def _delete_delay_help(
             menus.start_adding_reactions(m, c.keys())
 
 
-@commands.command(name="help", hidden=True, i18n=T_)
+@commands.command(name="help", hidden=True, i18n=_)
 async def red_help(ctx: Context, *, thing_to_get_help_for: str = None):
     """
     I need somebody


Test patch: