[V3 i18n] Internationalise help for commands and cogs (#1143)

* Framework for internationalised command help

* Translator for class docstring of cog

* Remove references to old context module

* Use CogManagerUI as PoC

* Replace all references to RedContext

* Rename CogI18n object to avoid confusion

* Update docs

* Update i18n docs.

* Store translators in list instead of dict

* Change commands module to package, updated refs in cogs

* Updated docs and more references in cogs

* Resolve syntax error

* Update from merge
This commit is contained in:
Tobotimus
2018-05-12 09:47:49 +10:00
committed by Kowlin
parent 1e60d1c265
commit 15ea5440a3
35 changed files with 575 additions and 259 deletions

View File

@@ -3,21 +3,20 @@ from datetime import datetime, timedelta
from collections import deque, defaultdict, namedtuple
import discord
from discord.ext import commands
from redbot.core import checks, Config, modlog, RedContext
from redbot.core import checks, Config, modlog, commands
from redbot.core.bot import Red
from redbot.core.i18n import CogI18n
from redbot.core.i18n import Translator, cog_i18n
from redbot.core.utils.chat_formatting import box, escape
from .checks import mod_or_voice_permissions, admin_or_voice_permissions, bot_has_voice_permissions
from redbot.core.utils.mod import is_mod_or_superior, is_allowed_by_hierarchy, \
get_audit_reason
from .log import log
_ = CogI18n("Mod", __file__)
_ = Translator("Mod", __file__)
@cog_i18n(_)
class Mod:
"""Moderation tools."""
@@ -174,7 +173,7 @@ class Mod:
@commands.group()
@commands.guild_only()
@checks.guildowner_or_permissions(administrator=True)
async def modset(self, ctx: RedContext):
async def modset(self, ctx: commands.Context):
"""Manages server administration settings."""
if ctx.invoked_subcommand is None:
guild = ctx.guild
@@ -200,7 +199,7 @@ class Mod:
@modset.command()
@commands.guild_only()
async def hierarchy(self, ctx: RedContext):
async def hierarchy(self, ctx: commands.Context):
"""Toggles role hierarchy check for mods / admins"""
guild = ctx.guild
toggled = await self.settings.guild(guild).respect_hierarchy()
@@ -215,7 +214,7 @@ class Mod:
@modset.command()
@commands.guild_only()
async def banmentionspam(self, ctx: RedContext, max_mentions: int=False):
async def banmentionspam(self, ctx: commands.Context, max_mentions: int=False):
"""Enables auto ban for messages mentioning X different people
Accepted values: 5 or superior"""
@@ -240,7 +239,7 @@ class Mod:
@modset.command()
@commands.guild_only()
async def deleterepeats(self, ctx: RedContext):
async def deleterepeats(self, ctx: commands.Context):
"""Enables auto deletion of repeated messages"""
guild = ctx.guild
cur_setting = await self.settings.guild(guild).delete_repeats()
@@ -254,7 +253,7 @@ class Mod:
@modset.command()
@commands.guild_only()
async def deletedelay(self, ctx: RedContext, time: int=None):
async def deletedelay(self, ctx: commands.Context, time: int=None):
"""Sets the delay until the bot removes the command message.
Must be between -1 and 60.
@@ -281,7 +280,7 @@ class Mod:
@modset.command()
@commands.guild_only()
async def reinvite(self, ctx: RedContext):
async def reinvite(self, ctx: commands.Context):
"""Toggles whether an invite will be sent when a user is unbanned via [p]unban.
If this is True, the bot will attempt to create and send a single-use invite
@@ -298,7 +297,7 @@ class Mod:
@commands.command()
@commands.guild_only()
@checks.admin_or_permissions(kick_members=True)
async def kick(self, ctx: RedContext, user: discord.Member, *, reason: str = None):
async def kick(self, ctx: commands.Context, user: discord.Member, *, reason: str = None):
"""Kicks user.
If a reason is specified, it will be the reason that shows up
@@ -338,7 +337,7 @@ class Mod:
@commands.command()
@commands.guild_only()
@checks.admin_or_permissions(ban_members=True)
async def ban(self, ctx: RedContext, user: discord.Member, days: str = None, *, reason: str = None):
async def ban(self, ctx: commands.Context, user: discord.Member, days: str = None, *, reason: str = None):
"""Bans user and deletes last X days worth of messages.
If days is not a number, it's treated as the first word of the reason.
@@ -399,7 +398,7 @@ class Mod:
@commands.command()
@commands.guild_only()
@checks.admin_or_permissions(ban_members=True)
async def hackban(self, ctx: RedContext, user_id: int, *, reason: str = None):
async def hackban(self, ctx: commands.Context, user_id: int, *, reason: str = None):
"""Preemptively bans user from the server
A user ID needs to be provided in order to ban
@@ -452,7 +451,7 @@ class Mod:
@commands.command()
@commands.guild_only()
@checks.admin_or_permissions(ban_members=True)
async def tempban(self, ctx: RedContext, user: discord.Member, days: int=1, *, reason: str=None):
async def tempban(self, ctx: commands.Context, user: discord.Member, days: int=1, *, reason: str=None):
"""Tempbans the user for the specified number of days"""
guild = ctx.guild
author = ctx.author
@@ -500,7 +499,7 @@ class Mod:
@commands.command()
@commands.guild_only()
@checks.admin_or_permissions(ban_members=True)
async def softban(self, ctx: RedContext, user: discord.Member, *, reason: str = None):
async def softban(self, ctx: commands.Context, user: discord.Member, *, reason: str = None):
"""Kicks the user, deleting 1 day worth of messages."""
guild = ctx.guild
channel = ctx.channel
@@ -579,7 +578,7 @@ class Mod:
@commands.guild_only()
@checks.admin_or_permissions(ban_members=True)
@commands.bot_has_permissions(ban_members=True)
async def unban(self, ctx: RedContext, user_id: int, *, reason: str = None):
async def unban(self, ctx: commands.Context, user_id: int, *, reason: str = None):
"""Unbans the target user.
Requires specifying the target user's ID. To find this, you may either:
@@ -637,7 +636,7 @@ class Mod:
.format(invite.url))
@staticmethod
async def get_invite_for_reinvite(ctx: RedContext, max_age: int=86400):
async def get_invite_for_reinvite(ctx: commands.Context, max_age: int=86400):
"""Handles the reinvite logic for getting an invite
to send the newly unbanned user
:returns: :class:`Invite`"""
@@ -672,7 +671,7 @@ class Mod:
@commands.guild_only()
@admin_or_voice_permissions(mute_members=True, deafen_members=True)
@bot_has_voice_permissions(mute_members=True, deafen_members=True)
async def voiceban(self, ctx: RedContext, user: discord.Member, *, reason: str=None):
async def voiceban(self, ctx: commands.Context, user: discord.Member, *, reason: str=None):
"""Bans the target user from speaking and listening in voice channels in the server"""
user_voice_state = user.voice
if user_voice_state is None:
@@ -709,7 +708,7 @@ class Mod:
@commands.guild_only()
@admin_or_voice_permissions(mute_members=True, deafen_members=True)
@bot_has_voice_permissions(mute_members=True, deafen_members=True)
async def voiceunban(self, ctx: RedContext, user: discord.Member, *, reason: str=None):
async def voiceunban(self, ctx: commands.Context, user: discord.Member, *, reason: str=None):
"""Unbans the user from speaking/listening in the server's voice channels"""
user_voice_state = user.voice
if user_voice_state is None:
@@ -743,7 +742,7 @@ class Mod:
@commands.command()
@commands.guild_only()
@checks.admin_or_permissions(manage_nicknames=True)
async def rename(self, ctx: RedContext, user: discord.Member, *, nickname=""):
async def rename(self, ctx: commands.Context, user: discord.Member, *, nickname=""):
"""Changes user's nickname
Leaving the nickname empty will remove it."""
@@ -763,7 +762,7 @@ class Mod:
@commands.group()
@commands.guild_only()
@checks.mod_or_permissions(manage_channel=True)
async def mute(self, ctx: RedContext):
async def mute(self, ctx: commands.Context):
"""Mutes user in the channel/server"""
if ctx.invoked_subcommand is None:
await ctx.send_help()
@@ -772,7 +771,7 @@ class Mod:
@commands.guild_only()
@mod_or_voice_permissions(mute_members=True)
@bot_has_voice_permissions(mute_members=True)
async def voice_mute(self, ctx: RedContext, user: discord.Member,
async def voice_mute(self, ctx: commands.Context, user: discord.Member,
*, reason: str = None):
"""Mutes the user in a voice channel"""
user_voice_state = user.voice
@@ -811,7 +810,7 @@ class Mod:
@checks.mod_or_permissions(administrator=True)
@mute.command(name="channel")
@commands.guild_only()
async def channel_mute(self, ctx: RedContext, user: discord.Member, *, reason: str = None):
async def channel_mute(self, ctx: commands.Context, user: discord.Member, *, reason: str = None):
"""Mutes user in the current channel"""
author = ctx.message.author
channel = ctx.message.channel
@@ -839,7 +838,7 @@ class Mod:
@checks.mod_or_permissions(administrator=True)
@mute.command(name="server", aliases=["guild"])
@commands.guild_only()
async def guild_mute(self, ctx: RedContext, user: discord.Member, *, reason: str = None):
async def guild_mute(self, ctx: commands.Context, user: discord.Member, *, reason: str = None):
"""Mutes user in the server"""
author = ctx.message.author
guild = ctx.guild
@@ -902,7 +901,7 @@ class Mod:
@commands.group()
@commands.guild_only()
@checks.mod_or_permissions(manage_channel=True)
async def unmute(self, ctx: RedContext):
async def unmute(self, ctx: commands.Context):
"""Unmutes user in the channel/server
Defaults to channel"""
@@ -913,7 +912,7 @@ class Mod:
@commands.guild_only()
@mod_or_voice_permissions(mute_members=True)
@bot_has_voice_permissions(mute_members=True)
async def voice_unmute(self, ctx: RedContext, user: discord.Member, *, reason: str = None):
async def voice_unmute(self, ctx: commands.Context, user: discord.Member, *, reason: str = None):
"""Unmutes the user in a voice channel"""
user_voice_state = user.voice
if user_voice_state:
@@ -947,7 +946,7 @@ class Mod:
@checks.mod_or_permissions(administrator=True)
@unmute.command(name="channel")
@commands.guild_only()
async def channel_unmute(self, ctx: RedContext, user: discord.Member, *, reason: str=None):
async def channel_unmute(self, ctx: commands.Context, user: discord.Member, *, reason: str=None):
"""Unmutes user in the current channel"""
channel = ctx.channel
author = ctx.author
@@ -970,7 +969,7 @@ class Mod:
@checks.mod_or_permissions(administrator=True)
@unmute.command(name="server", aliases=["guild"])
@commands.guild_only()
async def guild_unmute(self, ctx: RedContext, user: discord.Member, *, reason: str=None):
async def guild_unmute(self, ctx: commands.Context, user: discord.Member, *, reason: str=None):
"""Unmutes user in the server"""
guild = ctx.guild
author = ctx.author
@@ -1038,14 +1037,14 @@ class Mod:
@commands.group()
@commands.guild_only()
@checks.admin_or_permissions(manage_channels=True)
async def ignore(self, ctx: RedContext):
async def ignore(self, ctx: commands.Context):
"""Adds servers/channels to ignorelist"""
if ctx.invoked_subcommand is None:
await ctx.send_help()
await ctx.send(await self.count_ignored())
@ignore.command(name="channel")
async def ignore_channel(self, ctx: RedContext, channel: discord.TextChannel=None):
async def ignore_channel(self, ctx: commands.Context, channel: discord.TextChannel=None):
"""Ignores channel
Defaults to current one"""
@@ -1058,7 +1057,8 @@ class Mod:
await ctx.send(_("Channel already in ignore list."))
@ignore.command(name="server", aliases=["guild"])
async def ignore_guild(self, ctx: RedContext):
@commands.has_permissions(manage_guild=True)
async def ignore_guild(self, ctx: commands.Context):
"""Ignores current server"""
guild = ctx.guild
if not await self.settings.guild(guild).ignored():
@@ -1070,14 +1070,14 @@ class Mod:
@commands.group()
@commands.guild_only()
@checks.admin_or_permissions(manage_channels=True)
async def unignore(self, ctx: RedContext):
async def unignore(self, ctx: commands.Context):
"""Removes servers/channels from ignorelist"""
if ctx.invoked_subcommand is None:
await ctx.send_help()
await ctx.send(await self.count_ignored())
@unignore.command(name="channel")
async def unignore_channel(self, ctx: RedContext, channel: discord.TextChannel=None):
async def unignore_channel(self, ctx: commands.Context, channel: discord.TextChannel=None):
"""Removes channel from ignore list
Defaults to current one"""
@@ -1091,7 +1091,8 @@ class Mod:
await ctx.send(_("That channel is not in the ignore list."))
@unignore.command(name="server", aliases=["guild"])
async def unignore_guild(self, ctx: RedContext):
@commands.has_permissions(manage_guild=True)
async def unignore_guild(self, ctx: commands.Context):
"""Removes current guild from ignore list"""
guild = ctx.message.guild
if await self.settings.guild(guild).ignored():
@@ -1131,11 +1132,8 @@ class Mod:
chann_ignored and not perms.manage_channels)
@commands.command()
async def names(self, ctx: RedContext, user: discord.Member):
async def names(self, ctx: commands.Context, user: discord.Member):
"""Show previous names/nicknames of a user"""
async with self.settings.user(user).past_names() as name_list:
while None in name_list: # clean out null entries from a bug
name_list.remove(None)
names = await self.settings.user(user).past_names()
nicks = await self.settings.member(user).past_nicks()
msg = ""
@@ -1225,7 +1223,7 @@ class Mod:
return True
return False
async def on_command(self, ctx: RedContext):
async def on_command(self, ctx: commands.Context):
"""Currently used for:
* delete delay"""
guild = ctx.guild
@@ -1359,15 +1357,13 @@ class Mod:
if entry.target == target:
return entry
async def on_member_update(self, before: discord.Member, after: discord.Member):
async def on_member_update(self, before, after):
if before.name != after.name:
async with self.settings.user(before).past_names() as name_list:
while None in name_list: # clean out null entries from a bug
name_list.remove(None)
if after.name in name_list:
if after.nick in name_list:
# Ensure order is maintained without duplicates occuring
name_list.remove(after.name)
name_list.append(after.name)
name_list.remove(after.nick)
name_list.append(after.nick)
while len(name_list) > 20:
name_list.pop(0)