diff --git a/redbot/cogs/admin/admin.py b/redbot/cogs/admin/admin.py index 35eb7a964..a8bb090c9 100644 --- a/redbot/cogs/admin/admin.py +++ b/redbot/cogs/admin/admin.py @@ -1,11 +1,10 @@ +import logging from typing import Tuple import discord from redbot.core import Config, checks, commands - -import logging - +from redbot.core.i18n import Translator, cog_i18n from redbot.core.utils.chat_formatting import box from .announcer import Announcer from .converters import MemberDefaultAuthor, SelfRole diff --git a/redbot/cogs/bank/bank.py b/redbot/cogs/bank/bank.py index 6969fe30d..7fd79170c 100644 --- a/redbot/cogs/bank/bank.py +++ b/redbot/cogs/bank/bank.py @@ -67,7 +67,7 @@ class Bank(commands.Cog): @checks.guildowner_or_permissions(administrator=True) @commands.group(autohelp=True) async def bankset(self, ctx: commands.Context): - """Base command for bank settings""" + """Base command for bank settings.""" if ctx.invoked_subcommand is None: if await bank.is_global(): bank_name = await bank._conf.bank_name() @@ -91,9 +91,11 @@ class Bank(commands.Cog): @bankset.command(name="toggleglobal") @checks.is_owner() async def bankset_toggleglobal(self, ctx: commands.Context, confirm: bool = False): - """Toggles whether the bank is global or not - If the bank is global, it will become per-server - If the bank is per-server, it will become global""" + """Toggle whether the bank is global or not. + + If the bank is global, it will become per-server. + If the bank is per-server, it will become global. + """ cur_setting = await bank.is_global() word = _("per-server") if cur_setting else _("global") @@ -111,14 +113,14 @@ class Bank(commands.Cog): @bankset.command(name="bankname") @check_global_setting_guildowner() async def bankset_bankname(self, ctx: commands.Context, *, name: str): - """Set the bank's name""" + """Set the bank's name.""" await bank.set_bank_name(name, ctx.guild) await ctx.send(_("Bank name has been set to: {name}").format(name=name)) @bankset.command(name="creditsname") @check_global_setting_guildowner() async def bankset_creditsname(self, ctx: commands.Context, *, name: str): - """Set the name for the bank's currency""" + """Set the name for the bank's currency.""" await bank.set_currency_name(name, ctx.guild) await ctx.send(_("Currency name has been set to: {name}").format(name=name)) diff --git a/redbot/cogs/cleanup/cleanup.py b/redbot/cogs/cleanup/cleanup.py index 94eab2364..0ff24fdd5 100644 --- a/redbot/cogs/cleanup/cleanup.py +++ b/redbot/cogs/cleanup/cleanup.py @@ -16,7 +16,7 @@ _ = Translator("Cleanup", __file__) @cog_i18n(_) class Cleanup(commands.Cog): - """Commands for cleaning messages""" + """Commands for cleaning messages.""" def __init__(self, bot: Red): super().__init__() @@ -104,7 +104,7 @@ class Cleanup(commands.Cog): @commands.group() @checks.mod_or_permissions(manage_messages=True) async def cleanup(self, ctx: commands.Context): - """Deletes messages.""" + """Delete messages.""" pass @cleanup.command() @@ -112,16 +112,17 @@ class Cleanup(commands.Cog): async def text( self, ctx: commands.Context, text: str, number: int, delete_pinned: bool = False ): - """Deletes last X messages matching the specified text. + """Delete the last X messages matching the specified text. Example: - cleanup text \"test\" 5 + `[p]cleanup text "test" 5` - Remember to use double quotes.""" + Remember to use double quotes. + """ channel = ctx.channel if not channel.permissions_for(ctx.guild.me).manage_messages: - await ctx.send("I need the Manage Messages permission to do this.") + await ctx.send(_("I need the Manage Messages permission to do this.")) return author = ctx.author @@ -159,14 +160,15 @@ class Cleanup(commands.Cog): async def user( self, ctx: commands.Context, user: str, number: int, delete_pinned: bool = False ): - """Deletes last X messages from specified user. + """Delete the last X messages from a specified user. Examples: - cleanup user @\u200bTwentysix 2 - cleanup user Red 6""" + `[p]cleanup user @\u200bTwentysix 2` + `[p]cleanup user Red 6` + """ channel = ctx.channel if not channel.permissions_for(ctx.guild.me).manage_messages: - await ctx.send("I need the Manage Messages permission to do this.") + await ctx.send(_("I need the Manage Messages permission to do this.")) return member = None @@ -214,7 +216,7 @@ class Cleanup(commands.Cog): @cleanup.command() @commands.guild_only() async def after(self, ctx: commands.Context, message_id: int, delete_pinned: bool = False): - """Deletes all messages after specified message. + """Delete all messages after a specified message. To get a message id, enable developer mode in Discord's settings, 'appearance' tab. Then right click a message @@ -223,7 +225,7 @@ class Cleanup(commands.Cog): channel = ctx.channel if not channel.permissions_for(ctx.guild.me).manage_messages: - await ctx.send("I need the Manage Messages permission to do this.") + await ctx.send(_("I need the Manage Messages permission to do this.")) return author = ctx.author @@ -280,14 +282,15 @@ class Cleanup(commands.Cog): @cleanup.command() @commands.guild_only() async def messages(self, ctx: commands.Context, number: int, delete_pinned: bool = False): - """Deletes last X messages. + """Delete the last X messages. Example: - cleanup messages 26""" + `[p]cleanup messages 26` + """ channel = ctx.channel if not channel.permissions_for(ctx.guild.me).manage_messages: - await ctx.send("I need the Manage Messages permission to do this.") + await ctx.send(_("I need the Manage Messages permission to do this.")) return author = ctx.author @@ -311,11 +314,11 @@ class Cleanup(commands.Cog): @cleanup.command(name="bot") @commands.guild_only() async def cleanup_bot(self, ctx: commands.Context, number: int, delete_pinned: bool = False): - """Cleans up command messages and messages from the bot.""" + """Clean up command messages and messages from the bot.""" channel = ctx.channel if not channel.permissions_for(ctx.guild.me).manage_messages: - await ctx.send("I need the Manage Messages permission to do this.") + await ctx.send(_("I need the Manage Messages permission to do this.")) return author = ctx.message.author @@ -369,7 +372,7 @@ class Cleanup(commands.Cog): match_pattern: str = None, delete_pinned: bool = False, ): - """Cleans up messages owned by the bot. + """Clean up messages owned by the bot. By default, all messages are cleaned. If a third argument is specified, it is used for pattern matching: If it begins with r( and ends with ), diff --git a/redbot/cogs/customcom/customcom.py b/redbot/cogs/customcom/customcom.py index 870cf8923..f2d6165d2 100644 --- a/redbot/cogs/customcom/customcom.py +++ b/redbot/cogs/customcom/customcom.py @@ -54,7 +54,7 @@ class CommandObj: intro = _( "Welcome to the interactive random {cc} maker!\n" "Every message you send will be added as one of the random " - "responses to choose from once this {} is " + "responses to choose from once this {cc} is " "triggered. To exit this interactive menu, type `{quit}`" ).format(cc="customcommand", quit="exit()") await ctx.send(intro) @@ -196,30 +196,26 @@ class CustomCommands(commands.Cog): @commands.group(aliases=["cc"]) @commands.guild_only() async def customcom(self, ctx: commands.Context): - """Custom commands management""" + """Custom commands management.""" pass - @customcom.group(name="add") + @customcom.group(name="create", aliases=["add"]) @checks.mod_or_permissions(administrator=True) - async def cc_add(self, ctx: commands.Context): - """ - Adds a new custom command + async def cc_create(self, ctx: commands.Context): + """Create custom commands. - CCs can be enhanced with arguments: - https://red-discordbot.readthedocs.io/en/v3-develop/cog_customcom.html + CCs can be enhanced with arguments, see the guide + [here](https://red-discordbot.readthedocs.io/en/v3-develop/cog_customcom.html). """ pass - @cc_add.command(name="random") + @cc_create.command(name="random") @checks.mod_or_permissions(administrator=True) - async def cc_add_random(self, ctx: commands.Context, command: str.lower): - """ - Create a CC where it will randomly choose a response! + async def cc_create_random(self, ctx: commands.Context, command: str.lower): + """Create a CC where it will randomly choose a response! - Note: This is interactive + Note: This command is interactive. """ - responses = [] - responses = await self.commandobj.get_responses(ctx=ctx) try: await self.commandobj.create(ctx=ctx, command=command, response=responses) @@ -233,16 +229,16 @@ class CustomCommands(commands.Cog): # await ctx.send(str(responses)) - @cc_add.command(name="simple") + @cc_create.command(name="simple") @checks.mod_or_permissions(administrator=True) - async def cc_add_simple(self, ctx, command: str.lower, *, text: str): - """Adds a simple custom command + async def cc_create_simple(self, ctx, command: str.lower, *, text: str): + """Add a simple custom command. Example: - [p]customcom add simple yourcommand Text you want + - `[p]customcom create simple yourcommand Text you want` """ if command in self.bot.all_commands: - await ctx.send(_("That command is already a standard command.")) + await ctx.send(_("There already exists a bot command with the same name.")) return try: await self.commandobj.create(ctx=ctx, command=command, response=text) @@ -261,13 +257,14 @@ class CustomCommands(commands.Cog): async def cc_cooldown( self, ctx, command: str.lower, cooldown: int = None, *, per: str.lower = "member" ): - """ - Sets, edits, or views cooldowns for a custom command + """Set, edit, or view the cooldown for a custom command. + + You may set cooldowns per member, channel, or guild. Multiple + cooldowns may be set. All cooldowns must be cooled to call the + custom command. - You may set cooldowns per member, channel, or guild. - Multiple cooldowns may be set. All cooldowns must be cooled to call the custom command. Example: - [p]customcom cooldown yourcommand 30 + - `[p]customcom cooldown yourcommand 30` """ if cooldown is None: try: @@ -294,17 +291,18 @@ class CustomCommands(commands.Cog): except NotFound: await ctx.send( _("That command doesn't exist. Use `{command}` to add it.").format( - command="{}customcom add".format(ctx.prefix) + command="{}customcom create".format(ctx.prefix) ) ) @customcom.command(name="delete") @checks.mod_or_permissions(administrator=True) async def cc_delete(self, ctx, command: str.lower): - """Deletes a custom command - + """Delete a custom command +. Example: - [p]customcom delete yourcommand""" + - `[p]customcom delete yourcommand` + """ try: await self.commandobj.delete(ctx=ctx, command=command) await ctx.send(_("Custom command successfully deleted.")) @@ -314,18 +312,20 @@ class CustomCommands(commands.Cog): @customcom.command(name="edit") @checks.mod_or_permissions(administrator=True) async def cc_edit(self, ctx, command: str.lower, *, text: str = None): - """Edits a custom command's response + """Edit a custom command. Example: - [p]customcom edit yourcommand Text you want + - `[p]customcom edit yourcommand Text you want` """ + command = command.lower() + try: await self.commandobj.edit(ctx=ctx, command=command, response=text) await ctx.send(_("Custom command successfully edited.")) except NotFound: await ctx.send( - _("That command doesn't exist. Use `{}` to add it.").format( - "{}customcom add".format(ctx.prefix) + _("That command doesn't exist. Use `{command}` to add it.").format( + command="{}customcom create".format(ctx.prefix) ) ) except ArgParseError as e: @@ -333,7 +333,7 @@ class CustomCommands(commands.Cog): @customcom.command(name="list") async def cc_list(self, ctx): - """Shows custom commands list""" + """List all available custom commands.""" response = await CommandObj.get_commands(self.config.guild(ctx.guild)) @@ -342,7 +342,7 @@ class CustomCommands(commands.Cog): _( "There are no custom commands in this server." " Use `{command}` to start adding some." - ).format(command="{}customcom add".format(ctx.prefix)) + ).format(command="{}customcom create".format(ctx.prefix)) ) return diff --git a/redbot/cogs/dataconverter/dataconverter.py b/redbot/cogs/dataconverter/dataconverter.py index 93696800b..ee17f7a68 100644 --- a/redbot/cogs/dataconverter/dataconverter.py +++ b/redbot/cogs/dataconverter/dataconverter.py @@ -13,9 +13,7 @@ _ = Translator("DataConverter", __file__) @cog_i18n(_) class DataConverter(commands.Cog): - """ - Cog for importing Red v2 Data - """ + """Import Red V2 data to your V3 instance.""" def __init__(self, bot: Red): super().__init__() @@ -24,13 +22,10 @@ class DataConverter(commands.Cog): @checks.is_owner() @commands.command(name="convertdata") async def dataconversioncommand(self, ctx: commands.Context, v2path: str): - """ - Interactive prompt for importing data from Red v2 + """Interactive prompt for importing data from Red V2. - Takes the path where the v2 install is - - Overwrites values which have entries in both v2 and v3, - use with caution. + Takes the path where the V2 install is, and overwrites + values which have entries in both V2 and v3; use with caution. """ resolver = SpecResolver(Path(v2path.strip())) @@ -54,7 +49,7 @@ class DataConverter(commands.Cog): "message", check=MessagePredicate.same_context(ctx), timeout=60 ) except asyncio.TimeoutError: - return await ctx.send(_("Try this again when you are more ready")) + return await ctx.send(_("Try this again when you are ready.")) else: if message.content.strip().lower() in ["quit", "exit", "-1", "q", "cancel"]: return await ctx.tick() @@ -72,7 +67,7 @@ class DataConverter(commands.Cog): else: return await ctx.send( _( - "There isn't anything else I know how to convert here." - "\nThere might be more things I can convert in the future." + "There isn't anything else I know how to convert here.\n" + "There might be more things I can convert in the future." ) ) diff --git a/redbot/cogs/downloader/checks.py b/redbot/cogs/downloader/checks.py index 33bd192d7..cb86a8d4e 100644 --- a/redbot/cogs/downloader/checks.py +++ b/redbot/cogs/downloader/checks.py @@ -1,11 +1,15 @@ import asyncio from redbot.core import commands +from redbot.core.i18n import Translator from redbot.core.utils.predicates import MessagePredicate __all__ = ["do_install_agreement"] -REPO_INSTALL_MSG = ( +T_ = Translator("DownloaderChecks", __file__) + +_ = lambda s: s +REPO_INSTALL_MSG = _( "You're about to add a 3rd party repository. The creator of Red" " and its community have no responsibility for any potential " "damage that the content of 3rd party repositories might cause." @@ -14,6 +18,7 @@ REPO_INSTALL_MSG = ( "shown again until the next reboot.\n\nYou have **30** seconds" " to reply to this message." ) +_ = T_ async def do_install_agreement(ctx: commands.Context): @@ -21,14 +26,14 @@ async def do_install_agreement(ctx: commands.Context): if downloader is None or downloader.already_agreed: return True - await ctx.send(REPO_INSTALL_MSG) + await ctx.send(T_(REPO_INSTALL_MSG)) try: await ctx.bot.wait_for( "message", check=MessagePredicate.lower_equal_to("i agree", ctx), timeout=30 ) except asyncio.TimeoutError: - await ctx.send("Your response has timed out, please try again.") + await ctx.send(_("Your response has timed out, please try again.")) return False downloader.already_agreed = True diff --git a/redbot/cogs/downloader/converters.py b/redbot/cogs/downloader/converters.py index 0c4a1284c..f2a64ddc5 100644 --- a/redbot/cogs/downloader/converters.py +++ b/redbot/cogs/downloader/converters.py @@ -8,10 +8,10 @@ class InstalledCog(Installable): async def convert(cls, ctx: commands.Context, arg: str) -> Installable: downloader = ctx.bot.get_cog("Downloader") if downloader is None: - raise commands.CommandError("Downloader not loaded.") + raise commands.CommandError(_("No Downloader cog found.")) cog = discord.utils.get(await downloader.installed_cogs(), name=arg) if cog is None: - raise commands.BadArgument("That cog is not installed") + raise commands.BadArgument(_("That cog is not installed")) return cog diff --git a/redbot/cogs/downloader/downloader.py b/redbot/cogs/downloader/downloader.py index ec664a377..de4e75d5d 100644 --- a/redbot/cogs/downloader/downloader.py +++ b/redbot/cogs/downloader/downloader.py @@ -8,7 +8,7 @@ from sys import path as syspath from typing import Tuple, Union, Iterable import discord -from redbot.core import checks, commands, Config +from redbot.core import checks, commands, Config, checks, commands from redbot.core.bot import Red from redbot.core.data_manager import cog_data_path from redbot.core.i18n import Translator, cog_i18n @@ -193,9 +193,7 @@ class Downloader(commands.Cog): @commands.command() @checks.is_owner() async def pipinstall(self, ctx, *deps: str): - """ - Installs a group of dependencies using pip. - """ + """Install a group of dependencies using pip.""" repo = Repo("", "", "", Path.cwd(), loop=ctx.bot.loop) success = await repo.install_raw_requirements(deps, self.LIB_PATH) @@ -212,18 +210,15 @@ class Downloader(commands.Cog): @commands.group() @checks.is_owner() async def repo(self, ctx): - """ - Command group for managing Downloader repos. - """ + """Repo management commands.""" pass @repo.command(name="add") async def _repo_add(self, ctx, name: str, repo_url: str, branch: str = None): - """ - Add a new repo to Downloader. + """Add a new repo. - Name can only contain characters A-z, numbers and underscore - Branch will default to master if not specified + The name can only contain characters A-z, numbers and underscores. + The branch will default to master if not specified. """ agreed = await do_install_agreement(ctx) if not agreed: @@ -246,11 +241,9 @@ class Downloader(commands.Cog): if repo.install_msg is not None: await ctx.send(repo.install_msg.replace("[p]", ctx.prefix)) - @repo.command(name="delete") + @repo.command(name="delete", aliases=["remove"]) async def _repo_del(self, ctx, repo_name: Repo): - """ - Removes a repo from Downloader and its' files. - """ + """Remove a repo and its files.""" await self._repo_manager.delete_repo(repo_name.name) await ctx.send( @@ -259,9 +252,7 @@ class Downloader(commands.Cog): @repo.command(name="list") async def _repo_list(self, ctx): - """ - Lists all installed repos. - """ + """List all installed repos.""" repos = self._repo_manager.get_all_repo_names() repos = sorted(repos, key=str.lower) joined = _("Installed Repos:\n\n") @@ -274,11 +265,9 @@ class Downloader(commands.Cog): @repo.command(name="info") async def _repo_info(self, ctx, repo_name: Repo): - """ - Lists information about a single repo - """ + """Show information about a repo.""" if repo_name is None: - await ctx.send(_("There is no repo `{repo_name}`").format(repo_name=repo_name.name)) + await ctx.send(_("Repo `{repo_name}` not found.").format(repo_name=repo_name.name)) return msg = _("Information on {repo_name}:\n{description}").format( @@ -289,28 +278,24 @@ class Downloader(commands.Cog): @commands.group() @checks.is_owner() async def cog(self, ctx): - """ - Command group for managing installable Cogs. - """ + """Cog installation management commands.""" pass @cog.command(name="install") async def _cog_install(self, ctx, repo_name: Repo, cog_name: str): - """ - Installs a cog from the given repo. - """ - cog = discord.utils.get(repo_name.available_cogs, name=cog_name) # type: Installable + """Install a cog from the given repo.""" + cog: Installable = discord.utils.get(repo_name.available_cogs, name=cog_name) if cog is None: await ctx.send( _( - "Error, there is no cog by the name of `{cog_name}` in the `{repo_name}` repo." + "Error: there is no cog by the name of `{cog_name}` in the `{repo_name}` repo." ).format(cog_name=cog_name, repo_name=repo_name.name) ) return elif cog.min_python_version > sys.version_info: await ctx.send( - _("This cog requires at least python version {}, aborting install.").format( - ".".join([str(n) for n in cog.min_python_version]) + _("This cog requires at least python version {version}, aborting install.").format( + version=".".join([str(n) for n in cog.min_python_version]) ) ) return @@ -329,15 +314,16 @@ class Downloader(commands.Cog): await repo_name.install_libraries(self.SHAREDLIB_PATH) - await ctx.send(_("`{cog_name}` cog successfully installed.").format(cog_name=cog_name)) + await ctx.send(_("Cog `{cog_name}` successfully installed.").format(cog_name=cog_name)) if cog.install_msg is not None: await ctx.send(cog.install_msg.replace("[p]", ctx.prefix)) @cog.command(name="uninstall") async def _cog_uninstall(self, ctx, cog_name: InstalledCog): - """ - Allows you to uninstall cogs that were previously installed - through Downloader. + """Uninstall a cog. + + You may only uninstall cogs which were previously installed + by Downloader. """ # noinspection PyUnresolvedReferences,PyProtectedMember real_name = cog_name.name @@ -348,7 +334,7 @@ class Downloader(commands.Cog): # noinspection PyTypeChecker await self._remove_from_installed(cog_name) await ctx.send( - _("`{real_name}` was successfully removed.").format(real_name=real_name) + _("Cog `{cog_name}` was successfully uninstalled.").format(cog_name=real_name) ) else: await ctx.send( @@ -356,14 +342,14 @@ class Downloader(commands.Cog): "That cog was installed but can no longer" " be located. You may need to remove it's" " files manually if it is still usable." - ) + " Also make sure you've unloaded the cog" + " with `{prefix}unload {cog_name}`." + ).format(cog_name=real_name) ) @cog.command(name="update") async def _cog_update(self, ctx, cog_name: InstalledCog = None): - """ - Updates all cogs or one of your choosing. - """ + """Update all cogs, or one of your choosing.""" installed_cogs = set(await self.installed_cogs()) async with ctx.typing(): @@ -426,9 +412,7 @@ class Downloader(commands.Cog): @cog.command(name="list") async def _cog_list(self, ctx, repo_name: Repo): - """ - Lists all available cogs from a single repo. - """ + """List all available cogs from a single repo.""" installed = await self.installed_cogs() installed_str = "" if installed: @@ -453,9 +437,7 @@ class Downloader(commands.Cog): @cog.command(name="info") async def _cog_info(self, ctx, repo_name: Repo, cog_name: str): - """ - Lists information about a single cog. - """ + """List information about a single cog.""" cog = discord.utils.get(repo_name.available_cogs, name=cog_name) if cog is None: await ctx.send( @@ -549,9 +531,9 @@ class Downloader(commands.Cog): @commands.command() async def findcog(self, ctx: commands.Context, command_name: str): - """ - Figures out which cog a command comes from. Only works with loaded - cogs. + """Find which cog a command comes from. + + This will only work with loaded cogs. """ command = ctx.bot.all_commands.get(command_name) diff --git a/redbot/cogs/downloader/repo_manager.py b/redbot/cogs/downloader/repo_manager.py index fa03f641f..eb9ac8121 100644 --- a/redbot/cogs/downloader/repo_manager.py +++ b/redbot/cogs/downloader/repo_manager.py @@ -12,11 +12,15 @@ from typing import Tuple, MutableMapping, Union, Optional from redbot.core import data_manager, commands from redbot.core.utils import safe_delete +from redbot.core.i18n import Translator + from . import errors from .installable import Installable, InstallableType from .json_mixins import RepoJSONMixin from .log import log +_ = Translator("RepoManager", __file__) + class Repo(RepoJSONMixin): GIT_CLONE = "git clone --recurse-submodules -b {branch} {url} {folder}" @@ -64,13 +68,15 @@ class Repo(RepoJSONMixin): async def convert(cls, ctx: commands.Context, argument: str): downloader_cog = ctx.bot.get_cog("Downloader") if downloader_cog is None: - raise commands.CommandError("No Downloader cog found.") + raise commands.CommandError(_("No Downloader cog found.")) # noinspection PyProtectedMember repo_manager = downloader_cog._repo_manager poss_repo = repo_manager.get_repo(argument) if poss_repo is None: - raise commands.BadArgument("Repo by the name {} does not exist.".format(argument)) + raise commands.BadArgument( + _('Repo by the name "{repo_name}" does not exist.').format(repo_name=argument) + ) return poss_repo def _existing_git_repo(self) -> (bool, Path):