mirror of
https://github.com/brandons209/Red-bot-Cogs.git
synced 2024-04-26 16:42:11 +12:00
small fixes to some cogs. added translation cog from Trusty with changes for a friend
This commit is contained in:
parent
9540c3c652
commit
ef3868d231
|
@ -100,7 +100,7 @@ class EveryoneEmoji(commands.Cog):
|
|||
name = name[1]
|
||||
img = await resp_2.read()
|
||||
else:
|
||||
async with self.session.get(url) as resp:
|
||||
async with self.session.get(str(url)) as resp:
|
||||
if resp.status != 200:
|
||||
await ctx.send("Emoji not found.")
|
||||
return
|
||||
|
|
|
@ -29,13 +29,25 @@ class ImageMagic(commands.Cog):
|
|||
|
||||
# original by Flame442, edited for Wand by ScriptPony
|
||||
if not ctx.message.attachments and not link:
|
||||
async for msg in ctx.channel.history(limit=10):
|
||||
for a in msg.attachments:
|
||||
path = urllib.parse.urlparse(a.url).path
|
||||
link = a.url
|
||||
break
|
||||
if link:
|
||||
break
|
||||
# first check for reply message
|
||||
if ctx.message.reference:
|
||||
msg = ctx.message.reference.resolved
|
||||
if msg is None:
|
||||
msg = await ctx.channel.fetch_message(ctx.message.reference.message_id)
|
||||
if msg and msg.attachments:
|
||||
for a in msg.attachments:
|
||||
path = urllib.parse.urlparse(a.url).path
|
||||
link = a.url
|
||||
break
|
||||
|
||||
if not link:
|
||||
async for msg in ctx.channel.history(limit=10):
|
||||
for a in msg.attachments:
|
||||
path = urllib.parse.urlparse(a.url).path
|
||||
link = a.url
|
||||
break
|
||||
if link:
|
||||
break
|
||||
if not link:
|
||||
raise ImageFindError("Please provide an attachment.")
|
||||
if link: # linked image
|
||||
|
@ -94,13 +106,13 @@ class ImageMagic(commands.Cog):
|
|||
try:
|
||||
img, name = await asyncio.wait_for(task, timeout=60)
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send("The image took too long to process.")
|
||||
await ctx.reply("The image took too long to process.", mention_author=False)
|
||||
return
|
||||
|
||||
try:
|
||||
await ctx.send(file=discord.File(BytesIO(img.make_blob()), name))
|
||||
await ctx.reply(file=discord.File(BytesIO(img.make_blob()), name), mention_author=False)
|
||||
except discord.errors.HTTPException:
|
||||
await ctx.send("That image is too large.")
|
||||
await ctx.reply("That image is too large.", mention_author=False)
|
||||
return
|
||||
|
||||
@commands.group()
|
||||
|
@ -125,7 +137,7 @@ class ImageMagic(commands.Cog):
|
|||
try:
|
||||
img = await self._get_image(ctx, link)
|
||||
except ImageFindError as e:
|
||||
return await ctx.send(e)
|
||||
return await ctx.reply(e, mention_author=False)
|
||||
|
||||
await self._command_body(
|
||||
ctx,
|
||||
|
@ -148,7 +160,7 @@ class ImageMagic(commands.Cog):
|
|||
try:
|
||||
img = await self._get_image(ctx, link)
|
||||
except ImageFindError as e:
|
||||
return await ctx.send(e)
|
||||
return await ctx.reply(e, mention_author=False)
|
||||
|
||||
await self._command_body(ctx, args=(self._distortion, img, "implode", (amount * intensity,)))
|
||||
|
||||
|
@ -165,7 +177,7 @@ class ImageMagic(commands.Cog):
|
|||
try:
|
||||
img = await self._get_image(ctx, link)
|
||||
except ImageFindError as e:
|
||||
return await ctx.send(e)
|
||||
return await ctx.reply(e, mention_author=False)
|
||||
|
||||
await self._command_body(ctx, args=(self._distortion, img, "swirl", (intensity,)))
|
||||
|
||||
|
@ -179,7 +191,7 @@ class ImageMagic(commands.Cog):
|
|||
try:
|
||||
img = await self._get_image(ctx, link)
|
||||
except ImageFindError as e:
|
||||
return await ctx.send(e)
|
||||
return await ctx.reply(e, mention_author=False)
|
||||
|
||||
await self._command_body(ctx, args=(self._distortion, img, "charcoal", (1.5, 0.5)))
|
||||
|
||||
|
@ -193,7 +205,7 @@ class ImageMagic(commands.Cog):
|
|||
try:
|
||||
img = await self._get_image(ctx, link)
|
||||
except ImageFindError as e:
|
||||
return await ctx.send(e)
|
||||
return await ctx.reply(e, mention_author=False)
|
||||
|
||||
await self._command_body(ctx, args=(self._distortion, img, "sketch", (0.5, 0.0, 98.0)))
|
||||
|
||||
|
@ -207,7 +219,7 @@ class ImageMagic(commands.Cog):
|
|||
try:
|
||||
img = await self._get_image(ctx, link)
|
||||
except ImageFindError as e:
|
||||
return await ctx.send(e)
|
||||
return await ctx.reply(e, mention_author=False)
|
||||
|
||||
h = img.height
|
||||
w = img.width
|
||||
|
|
|
@ -25,9 +25,14 @@ class ReactPoll(commands.Cog):
|
|||
self.config = Config.get_conf(self, identifier=9675846083, force_registration=True)
|
||||
self.config.register_global(poll_sessions={})
|
||||
|
||||
self.loop = bot.loop
|
||||
self.loop.create_task(self.load_polls())
|
||||
self.poll_task = self.loop.create_task(self.poll_closer())
|
||||
self.load_task = asyncio.create_task(self.load_polls())
|
||||
self.poll_task = asyncio.create_task(self.poll_closer())
|
||||
|
||||
def cog_unload(self):
|
||||
if self.load_task:
|
||||
self.load_task.cancel()
|
||||
if self.poll_task:
|
||||
self.poll_task.cancel()
|
||||
|
||||
async def poll_closer(self):
|
||||
await self.bot.wait_until_ready()
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from redbot.core import bank, commands, checks, Config
|
||||
from redbot.core.utils.chat_formatting import *
|
||||
from redbot.core.utils.predicates import MessagePredicate
|
||||
from redbot.core.data_manager import cog_data_path
|
||||
|
||||
from aitextgen import aitextgen
|
||||
|
|
13
translate/__init__.py
Normal file
13
translate/__init__.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from .translate import Translate
|
||||
|
||||
with open(Path(__file__).parent / "info.json") as fp:
|
||||
__red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"]
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
cog = Translate(bot)
|
||||
await cog.init()
|
||||
bot.add_cog(cog)
|
578
translate/api.py
Normal file
578
translate/api.py
Normal file
|
@ -0,0 +1,578 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
from copy import deepcopy
|
||||
from typing import Dict, List, Mapping, Optional, Tuple, Union, cast
|
||||
|
||||
import aiohttp
|
||||
import discord
|
||||
from discord.ext.commands.converter import Converter
|
||||
from discord.ext.commands.errors import BadArgument
|
||||
|
||||
from redbot.core import Config, VersionInfo, commands, version_info
|
||||
from redbot.core.bot import Red
|
||||
from redbot.core.i18n import Translator
|
||||
|
||||
from .errors import GoogleTranslateAPIError
|
||||
from .flags import FLAGS
|
||||
|
||||
BASE_URL = "https://translation.googleapis.com"
|
||||
_ = Translator("Translate", __file__)
|
||||
log = logging.getLogger("red.trusty-cogs.Translate")
|
||||
|
||||
FLAG_REGEX = re.compile(r"|".join(rf"{re.escape(f)}" for f in FLAGS.keys()))
|
||||
|
||||
|
||||
class FlagTranslation(Converter):
|
||||
"""
|
||||
This will convert flags and languages to the correct code to be used by the API
|
||||
|
||||
Guidance code on how to do this from:
|
||||
https://github.com/Rapptz/discord.py/blob/rewrite/discord/ext/commands/converter.py#L85
|
||||
https://github.com/Cog-Creators/Red-DiscordBot/blob/V3/develop/redbot/cogs/mod/mod.py#L24
|
||||
|
||||
"""
|
||||
|
||||
async def convert(self, ctx: commands.Context, argument: str) -> List[str]:
|
||||
result = []
|
||||
if argument in FLAGS:
|
||||
result = FLAGS[argument]["code"].upper()
|
||||
else:
|
||||
for lang in FLAGS:
|
||||
if FLAGS[lang]["name"].lower() in argument.lower():
|
||||
result = FLAGS[lang]["code"]
|
||||
break
|
||||
if FLAGS[lang]["country"].lower() in argument.lower():
|
||||
result = FLAGS[lang]["code"]
|
||||
break
|
||||
if not FLAGS[lang]["code"]:
|
||||
continue
|
||||
if FLAGS[lang]["code"] in argument.lower() and len(argument) == 2:
|
||||
result = FLAGS[lang]["code"]
|
||||
break
|
||||
if not result:
|
||||
raise BadArgument('Language "{}" not found'.format(argument))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class GoogleTranslateAPI:
|
||||
config: Config
|
||||
bot: Red
|
||||
cache: dict
|
||||
_key: Optional[str]
|
||||
_guild_counter: Dict[int, Dict[str, int]]
|
||||
_global_counter: Dict[str, int]
|
||||
|
||||
def __init__(self, *_args):
|
||||
self.config: Config
|
||||
self.bot: Red
|
||||
self.cache: dict
|
||||
self._key: Optional[str]
|
||||
self._guild_counter: Dict[int, Dict[str, int]]
|
||||
self._global_counter: Dict[str, int]
|
||||
|
||||
async def cleanup_cache(self) -> None:
|
||||
if version_info >= VersionInfo.from_str("3.2.0"):
|
||||
await self.bot.wait_until_red_ready()
|
||||
else:
|
||||
await self.bot.wait_until_ready()
|
||||
while self is self.bot.get_cog("Translate"):
|
||||
# cleanup the cache every 10 minutes
|
||||
self.cache["translations"] = []
|
||||
await asyncio.sleep(600)
|
||||
|
||||
async def save_usage(self) -> None:
|
||||
if version_info >= VersionInfo.from_str("3.2.0"):
|
||||
await self.bot.wait_until_red_ready()
|
||||
else:
|
||||
await self.bot.wait_until_ready()
|
||||
while self is self.bot.get_cog("Translate"):
|
||||
# Save usage stats every couple minutes
|
||||
await self._save_usage_stats()
|
||||
await asyncio.sleep(120)
|
||||
|
||||
async def _save_usage_stats(self):
|
||||
async with self.config.count() as count:
|
||||
for key, value in self._global_counter.items():
|
||||
count[key] = value
|
||||
for guild_id, data in self._guild_counter.items():
|
||||
async with self.config.guild_from_id(guild_id).count() as count:
|
||||
for key, value in data.items():
|
||||
count[key] = value
|
||||
|
||||
async def add_detect(self, guild: Optional[discord.Guild]):
|
||||
if guild:
|
||||
log.debug(f"adding detect to {guild.name}")
|
||||
if guild.id not in self._guild_counter:
|
||||
self._guild_counter[guild.id] = await self.config.guild(guild).count()
|
||||
self._guild_counter[guild.id]["detect"] += 1
|
||||
if not self._global_counter:
|
||||
self._global_counter = await self.config.count()
|
||||
self._global_counter["detect"] += 1
|
||||
|
||||
async def add_requests(self, guild: Optional[discord.Guild], message: str):
|
||||
if guild:
|
||||
log.debug(f"Adding requests to {guild.name}")
|
||||
if guild.id not in self._guild_counter:
|
||||
self._guild_counter[guild.id] = await self.config.guild(guild).count()
|
||||
self._guild_counter[guild.id]["requests"] += 1
|
||||
self._guild_counter[guild.id]["characters"] += len(message)
|
||||
if not self._global_counter:
|
||||
self._global_counter = await self.config.count()
|
||||
self._global_counter["requests"] += 1
|
||||
self._global_counter["characters"] += len(message)
|
||||
|
||||
async def _get_google_api_key(self) -> Optional[str]:
|
||||
key = {}
|
||||
if not self._key:
|
||||
try:
|
||||
key = await self.bot.get_shared_api_tokens("google_translate")
|
||||
except AttributeError:
|
||||
# Red 3.1 support
|
||||
key = await self.bot.db.api_tokens.get_raw("google_translate", default={})
|
||||
self._key = key.get("api_key")
|
||||
return self._key
|
||||
|
||||
async def _bw_list_cache_update(self, guild: discord.Guild) -> None:
|
||||
self.cache["guild_blacklist"][guild.id] = await self.config.guild(guild).blacklist()
|
||||
self.cache["guild_whitelist"][guild.id] = await self.config.guild(guild).whitelist()
|
||||
|
||||
async def check_bw_list(
|
||||
self,
|
||||
guild: discord.Guild,
|
||||
channel: discord.TextChannel,
|
||||
member: Union[discord.Member, discord.User],
|
||||
) -> bool:
|
||||
can_run = True
|
||||
if guild.id not in self.cache["guild_blacklist"]:
|
||||
self.cache["guild_blacklist"][guild.id] = await self.config.guild(guild).blacklist()
|
||||
if guild.id not in self.cache["guild_whitelist"]:
|
||||
self.cache["guild_whitelist"][guild.id] = await self.config.guild(guild).whitelist()
|
||||
whitelist = self.cache["guild_whitelist"][guild.id]
|
||||
blacklist = self.cache["guild_blacklist"][guild.id]
|
||||
if whitelist:
|
||||
can_run = False
|
||||
if channel.id in whitelist:
|
||||
can_run = True
|
||||
if channel.category_id and channel.category_id in whitelist:
|
||||
can_run = True
|
||||
if member.id in whitelist:
|
||||
can_run = True
|
||||
for role in getattr(member, "roles", []):
|
||||
if role.is_default():
|
||||
continue
|
||||
if role.id in whitelist:
|
||||
can_run = True
|
||||
return can_run
|
||||
else:
|
||||
if channel.id in blacklist:
|
||||
can_run = False
|
||||
if channel.category_id and channel.category_id in blacklist:
|
||||
can_run = False
|
||||
if member.id in blacklist:
|
||||
can_run = False
|
||||
for role in getattr(member, "roles", []):
|
||||
if role.is_default():
|
||||
continue
|
||||
if role.id in blacklist:
|
||||
can_run = False
|
||||
return can_run
|
||||
|
||||
async def detect_language(self, text: str) -> List[List[Dict[str, str]]]:
|
||||
"""
|
||||
Detect the language from given text
|
||||
"""
|
||||
params = {"q": text, "key": self._key}
|
||||
url = BASE_URL + "/language/translate/v2/detect"
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, params=params) as resp:
|
||||
data = await resp.json()
|
||||
if "error" in data:
|
||||
log.error(data["error"]["message"])
|
||||
raise GoogleTranslateAPIError(data["error"]["message"])
|
||||
return data["data"]["detections"]
|
||||
|
||||
async def translation_embed(
|
||||
self,
|
||||
author: Union[discord.Member, discord.User],
|
||||
translation: Tuple[str, str, str],
|
||||
requestor: Optional[Union[discord.Member, discord.User]] = None,
|
||||
) -> discord.Embed:
|
||||
em = discord.Embed(colour=author.colour, description=translation[0])
|
||||
em.set_author(name=author.display_name + _(" said:"), icon_url=str(author.avatar_url))
|
||||
detail_string = _("{_from} to {_to} | Requested by ").format(
|
||||
_from=translation[1].upper(), _to=translation[2].upper()
|
||||
)
|
||||
if requestor:
|
||||
detail_string += str(requestor)
|
||||
else:
|
||||
detail_string += str(author)
|
||||
em.set_footer(text=detail_string)
|
||||
return em
|
||||
|
||||
async def translate_text(self, from_lang: str, target: str, text: str) -> Optional[str]:
|
||||
"""
|
||||
request to translate the text
|
||||
"""
|
||||
formatting = "text"
|
||||
params = {
|
||||
"q": text,
|
||||
"target": target,
|
||||
"key": self._key,
|
||||
"format": formatting,
|
||||
"source": from_lang,
|
||||
}
|
||||
url = BASE_URL + "/language/translate/v2"
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, params=params) as resp:
|
||||
data = await resp.json()
|
||||
except Exception:
|
||||
return None
|
||||
if "error" in data:
|
||||
log.error(data["error"]["message"])
|
||||
raise GoogleTranslateAPIError(data["error"]["message"])
|
||||
if "data" in data:
|
||||
translated_text: str = data["data"]["translations"][0]["translatedText"]
|
||||
return translated_text
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message: discord.Message) -> None:
|
||||
"""
|
||||
Translates the message based off reactions
|
||||
with country flags
|
||||
"""
|
||||
if version_info >= VersionInfo.from_str("3.2.0"):
|
||||
await self.bot.wait_until_red_ready()
|
||||
else:
|
||||
await self.bot.wait_until_ready()
|
||||
if not message.guild:
|
||||
return
|
||||
if message.author.bot:
|
||||
return
|
||||
if not await self._get_google_api_key():
|
||||
return
|
||||
author = cast(discord.Member, message.author)
|
||||
channel = cast(discord.TextChannel, message.channel)
|
||||
links = await self.config.guild(channel.guild).autosend()
|
||||
link_channels = [int(r) for r in links.keys()]
|
||||
guild = message.guild
|
||||
if version_info >= VersionInfo.from_str("3.4.0"):
|
||||
if await self.bot.cog_disabled_in_guild(self, guild):
|
||||
return
|
||||
if not await self.check_bw_list(guild, channel, author):
|
||||
return
|
||||
if not await self.config.guild(guild).text() and not channel.id in link_channels:
|
||||
return
|
||||
if guild.id not in self.cache["guild_messages"]:
|
||||
if not await self.config.guild(guild).text() and not channel.id in link_channels:
|
||||
return
|
||||
else:
|
||||
self.cache["guild_messages"].append(guild.id)
|
||||
if not await self.local_perms(guild, author):
|
||||
return
|
||||
if not await self.global_perms(author):
|
||||
return
|
||||
if not await self.check_ignored_channel(message):
|
||||
return
|
||||
flag = FLAG_REGEX.search(message.clean_content)
|
||||
if flag:
|
||||
await self.translate_message(message, flag.group())
|
||||
elif channel.id in link_channels:
|
||||
await self.translate_automessage(message, links)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) -> None:
|
||||
"""
|
||||
Translates the message based off reactions
|
||||
with country flags
|
||||
"""
|
||||
if version_info >= VersionInfo.from_str("3.2.0"):
|
||||
await self.bot.wait_until_red_ready()
|
||||
else:
|
||||
await self.bot.wait_until_ready()
|
||||
if payload.message_id in self.cache["translations"]:
|
||||
return
|
||||
if str(payload.emoji) not in FLAGS:
|
||||
return
|
||||
if not await self._get_google_api_key():
|
||||
return
|
||||
channel = self.bot.get_channel(id=payload.channel_id)
|
||||
if not channel:
|
||||
return
|
||||
try:
|
||||
guild = channel.guild
|
||||
except AttributeError:
|
||||
return
|
||||
if guild is None:
|
||||
return
|
||||
if version_info >= VersionInfo.from_str("3.4.0"):
|
||||
if await self.bot.cog_disabled_in_guild(self, guild):
|
||||
return
|
||||
reacted_user = guild.get_member(payload.user_id)
|
||||
if reacted_user.bot:
|
||||
return
|
||||
if not await self.check_bw_list(guild, channel, reacted_user):
|
||||
return
|
||||
|
||||
if guild.id not in self.cache["guild_reactions"]:
|
||||
if not await self.config.guild(guild).reaction():
|
||||
return
|
||||
else:
|
||||
self.cache["guild_reactions"].append(guild.id)
|
||||
|
||||
if not await self.local_perms(guild, reacted_user):
|
||||
return
|
||||
if not await self.global_perms(reacted_user):
|
||||
return
|
||||
try:
|
||||
message = await channel.fetch_message(id=payload.message_id)
|
||||
except (discord.errors.NotFound, discord.Forbidden):
|
||||
return
|
||||
|
||||
if not await self.check_ignored_channel(message, reacted_user):
|
||||
return
|
||||
await self.translate_message(message, str(payload.emoji), reacted_user)
|
||||
|
||||
async def translate_automessage(self, message: discord.Message, links: dict) -> None:
|
||||
guild = cast(discord.Guild, message.guild)
|
||||
channel = cast(discord.TextChannel, message.channel)
|
||||
# remove sent channel from Links
|
||||
try:
|
||||
del links[str(channel.id)]
|
||||
except:
|
||||
pass
|
||||
|
||||
if message.embeds != []:
|
||||
if message.embeds[0].description:
|
||||
to_translate = cast(str, message.embeds[0].description)
|
||||
else:
|
||||
to_translate = None
|
||||
else:
|
||||
to_translate = message.clean_content
|
||||
|
||||
if not to_translate:
|
||||
for l_id, l_lang in links.items():
|
||||
ch = guild.get_channel(int(l_id))
|
||||
if not ch:
|
||||
continue
|
||||
|
||||
if message.attachments:
|
||||
files = [await a.to_file() for a in message.attachments]
|
||||
else:
|
||||
files = None
|
||||
|
||||
if message.embeds:
|
||||
links = "\n".join([e.url for e in message.embeds])
|
||||
else:
|
||||
links = ""
|
||||
|
||||
await ch.send(f"**{message.author.display_name} sent:**\n{links}", files=files)
|
||||
return
|
||||
try:
|
||||
detected_lang = await self.detect_language(to_translate)
|
||||
await self.add_detect(guild)
|
||||
except GoogleTranslateAPIError:
|
||||
return
|
||||
except Exception:
|
||||
log.exception("Error detecting language")
|
||||
return
|
||||
|
||||
original_lang = detected_lang[0][0]["language"]
|
||||
for l_id, target in links.items():
|
||||
ch = guild.get_channel(int(l_id))
|
||||
if not ch:
|
||||
continue
|
||||
try:
|
||||
if target == original_lang:
|
||||
translated_text = to_translate
|
||||
else:
|
||||
translated_text = await self.translate_text(original_lang, target, to_translate)
|
||||
await self.add_requests(guild, to_translate)
|
||||
except Exception:
|
||||
log.exception(f"Error translating message {guild=} {channel=}")
|
||||
return
|
||||
if not translated_text:
|
||||
log.exception(f"Message not translated to {l_lang} {guild=} {channel=}")
|
||||
return
|
||||
author = message.author
|
||||
from_lang = original_lang.upper()
|
||||
to_lang = target.upper()
|
||||
|
||||
translation = (translated_text, from_lang, to_lang)
|
||||
|
||||
if message.attachments:
|
||||
files = [await a.to_file() for a in message.attachments]
|
||||
else:
|
||||
files = None
|
||||
|
||||
if ch.permissions_for(guild.me).embed_links:
|
||||
em = await self.translation_embed(author, translation)
|
||||
translated_msg = await ch.send(embed=em, files=files)
|
||||
else:
|
||||
msg = _("{author} said:\n{translated_text}").format(author=author, translated_text=translated_text)
|
||||
translated_msg = await ch.send(msg, files=files)
|
||||
|
||||
async def translate_message(
|
||||
self,
|
||||
message: discord.Message,
|
||||
flag: str,
|
||||
reacted_user: Optional[discord.Member] = None,
|
||||
) -> None:
|
||||
guild = cast(discord.Guild, message.guild)
|
||||
channel = cast(discord.TextChannel, message.channel)
|
||||
if message.id in self.cache["cooldown_translations"]:
|
||||
if str(flag) in self.cache["cooldown_translations"][message.id]["past_flags"]:
|
||||
return
|
||||
if not self.cache["cooldown_translations"][message.id]["multiple"]:
|
||||
return
|
||||
if time.time() < self.cache["cooldown_translations"][message.id]["wait"]:
|
||||
delete_after = self.cache["cooldown_translations"][message.id]["wait"] - time.time()
|
||||
await channel.send(_("You're translating too many messages!"), delete_after=delete_after)
|
||||
return
|
||||
to_translate = None
|
||||
if message.embeds != []:
|
||||
if message.embeds[0].description:
|
||||
to_translate = cast(str, message.embeds[0].description)
|
||||
else:
|
||||
to_translate = message.clean_content
|
||||
|
||||
if not to_translate:
|
||||
return
|
||||
num_emojis = 0
|
||||
for reaction in message.reactions:
|
||||
if reaction.emoji == str(flag):
|
||||
num_emojis = reaction.count
|
||||
if num_emojis > 1:
|
||||
return
|
||||
target = FLAGS[str(flag)]["code"]
|
||||
try:
|
||||
detected_lang = await self.detect_language(to_translate)
|
||||
await self.add_detect(guild)
|
||||
except GoogleTranslateAPIError:
|
||||
return
|
||||
except Exception:
|
||||
log.exception("Error detecting language")
|
||||
return
|
||||
original_lang = detected_lang[0][0]["language"]
|
||||
if target == original_lang:
|
||||
return
|
||||
try:
|
||||
translated_text = await self.translate_text(original_lang, target, to_translate)
|
||||
await self.add_requests(guild, to_translate)
|
||||
except Exception:
|
||||
log.exception(f"Error translating message {guild=} {channel=}")
|
||||
return
|
||||
if not translated_text:
|
||||
return
|
||||
author = message.author
|
||||
from_lang = detected_lang[0][0]["language"].upper()
|
||||
to_lang = target.upper()
|
||||
if from_lang == to_lang:
|
||||
# don't post anything if the detected language is the same
|
||||
return
|
||||
translation = (translated_text, from_lang, to_lang)
|
||||
|
||||
if message.id not in self.cache["cooldown_translations"]:
|
||||
if not self.cache["cooldown"]:
|
||||
self.cache["cooldown"] = await self.config.cooldown()
|
||||
cooldown = deepcopy(self.cache["cooldown"])
|
||||
else:
|
||||
cooldown = self.cache["cooldown_translations"][message.id]
|
||||
cooldown["wait"] = time.time() + cooldown["timeout"]
|
||||
cooldown["past_flags"].append(str(flag))
|
||||
self.cache["cooldown_translations"][message.id] = cooldown
|
||||
|
||||
if channel.permissions_for(guild.me).embed_links:
|
||||
em = await self.translation_embed(author, translation, reacted_user)
|
||||
if version_info >= VersionInfo.from_str("3.4.6"):
|
||||
translated_msg = await channel.send(embed=em, reference=message, mention_author=False)
|
||||
else:
|
||||
translated_msg = await channel.send(embed=em)
|
||||
else:
|
||||
msg = _("{author} said:\n{translated_text}").format(author=author, translate_text=translated_text)
|
||||
translated_msg = await channel.send(msg)
|
||||
if not cooldown["multiple"]:
|
||||
self.cache["translations"].append(translated_msg.id)
|
||||
|
||||
async def local_perms(self, guild: discord.Guild, author: discord.Member) -> bool:
|
||||
"""Check the user is/isn't locally whitelisted/blacklisted.
|
||||
https://github.com/Cog-Creators/Red-DiscordBot/blob/V3/release/3.0.0/redbot/core/global_checks.py
|
||||
"""
|
||||
try:
|
||||
return await self.bot.allowed_by_whitelist_blacklist(
|
||||
author, who_id=author.id, guild_id=guild.id, role_ids=[r.id for r in author.roles]
|
||||
)
|
||||
except AttributeError:
|
||||
if await self.bot.is_owner(author):
|
||||
return True
|
||||
elif guild is None:
|
||||
return True
|
||||
guild_settings = self.bot.db.guild(guild)
|
||||
local_blacklist = await guild_settings.blacklist()
|
||||
local_whitelist = await guild_settings.whitelist()
|
||||
|
||||
_ids = [r.id for r in author.roles if not r.is_default()]
|
||||
_ids.append(author.id)
|
||||
if local_whitelist:
|
||||
return any(i in local_whitelist for i in _ids)
|
||||
|
||||
return not any(i in local_blacklist for i in _ids)
|
||||
|
||||
async def global_perms(self, author: discord.Member) -> bool:
|
||||
"""Check the user is/isn't globally whitelisted/blacklisted.
|
||||
https://github.com/Cog-Creators/Red-DiscordBot/blob/V3/release/3.0.0/redbot/core/global_checks.py
|
||||
"""
|
||||
try:
|
||||
return await self.bot.allowed_by_whitelist_blacklist(author)
|
||||
except AttributeError:
|
||||
if await self.bot.is_owner(author):
|
||||
return True
|
||||
whitelist = await self.bot.db.whitelist()
|
||||
if whitelist:
|
||||
return author.id in whitelist
|
||||
|
||||
return author.id not in await self.bot.db.blacklist()
|
||||
|
||||
async def check_ignored_channel(
|
||||
self, message: discord.Message, reacting_user: Optional[discord.Member] = None
|
||||
) -> bool:
|
||||
"""
|
||||
https://github.com/Cog-Creators/Red-DiscordBot/blob/V3/release/3.0.0/redbot/cogs/mod/mod.py#L1273
|
||||
"""
|
||||
if version_info >= VersionInfo.from_str("3.3.6"):
|
||||
ctx = await self.bot.get_context(message)
|
||||
if reacting_user:
|
||||
ctx.author = reacting_user
|
||||
return await self.bot.ignored_channel_or_guild(ctx)
|
||||
# everything below this can be removed at a later date when support
|
||||
# for previous versions are no longer required.
|
||||
channel = cast(discord.TextChannel, message.channel)
|
||||
guild = channel.guild
|
||||
author = cast(discord.Member, message.author)
|
||||
if reacting_user:
|
||||
author = reacting_user
|
||||
mod = self.bot.get_cog("Mod")
|
||||
if mod is None:
|
||||
return True
|
||||
perms = channel.permissions_for(author)
|
||||
surpass_ignore = (
|
||||
isinstance(channel, discord.abc.PrivateChannel)
|
||||
or perms.manage_guild
|
||||
or await self.bot.is_owner(author)
|
||||
or await self.bot.is_admin(author)
|
||||
)
|
||||
if surpass_ignore:
|
||||
return True
|
||||
guild_ignored = await mod.settings.guild(guild).ignored()
|
||||
chann_ignored = await mod.settings.channel(channel).ignored()
|
||||
return not (guild_ignored or chann_ignored and not perms.manage_channels)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_red_api_tokens_update(self, service_name: str, api_tokens: Mapping[str, str]) -> None:
|
||||
if service_name != "google_translate":
|
||||
return
|
||||
|
||||
self._key = None
|
58
translate/converters.py
Normal file
58
translate/converters.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
import re
|
||||
from typing import Union
|
||||
|
||||
import discord
|
||||
from discord.ext.commands.converter import IDConverter
|
||||
from discord.ext.commands.errors import BadArgument
|
||||
from redbot.core import commands
|
||||
from redbot.core.i18n import Translator
|
||||
|
||||
_ = Translator("Translate", __file__)
|
||||
|
||||
|
||||
class ChannelUserRole(IDConverter):
|
||||
"""
|
||||
This will check to see if the provided argument is a channel, user, or role
|
||||
|
||||
Guidance code on how to do this from:
|
||||
https://github.com/Rapptz/discord.py/blob/rewrite/discord/ext/commands/converter.py#L85
|
||||
https://github.com/Cog-Creators/Red-DiscordBot/blob/V3/develop/redbot/cogs/mod/mod.py#L24
|
||||
"""
|
||||
|
||||
async def convert(
|
||||
self, ctx: commands.Context, argument: str
|
||||
) -> Union[discord.TextChannel, discord.Role, discord.Member]:
|
||||
guild = ctx.guild
|
||||
result = None
|
||||
id_match = self._get_id_match(argument)
|
||||
channel_match = re.match(r"<#([0-9]+)>$", argument)
|
||||
member_match = re.match(r"<@!?([0-9]+)>$", argument)
|
||||
role_match = re.match(r"<@&([0-9]+)>$", argument)
|
||||
for converter in ["channel", "role", "member"]:
|
||||
if converter == "channel":
|
||||
match = id_match or channel_match
|
||||
if match:
|
||||
channel_id = match.group(1)
|
||||
result = guild.get_channel(int(channel_id))
|
||||
else:
|
||||
result = discord.utils.get(guild.text_channels, name=argument)
|
||||
if converter == "member":
|
||||
match = id_match or member_match
|
||||
if match:
|
||||
member_id = match.group(1)
|
||||
result = guild.get_member(int(member_id))
|
||||
else:
|
||||
result = guild.get_member_named(argument)
|
||||
if converter == "role":
|
||||
match = id_match or role_match
|
||||
if match:
|
||||
role_id = match.group(1)
|
||||
result = guild.get_role(int(role_id))
|
||||
else:
|
||||
result = discord.utils.get(guild._roles.values(), name=argument)
|
||||
if result:
|
||||
break
|
||||
if not result:
|
||||
msg = _("{arg} is not a valid channel, user or role.").format(arg=argument)
|
||||
raise BadArgument(msg)
|
||||
return result
|
4
translate/errors.py
Normal file
4
translate/errors.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
class GoogleTranslateAPIError(Exception):
|
||||
"""Raised when google translate has an oopsie"""
|
||||
|
||||
pass
|
277
translate/flags.py
Normal file
277
translate/flags.py
Normal file
|
@ -0,0 +1,277 @@
|
|||
FLAGS = {
|
||||
"🇦🇩": {"code": "ca", "country": "Andorra", "name": "Catalan"},
|
||||
"🇦🇪": {"code": "ar", "country": "United Arab Emirates", "name": "Arabic"},
|
||||
"🇦🇫": {"code": "ps", "country": "Afghanistan", "name": "Pashto"},
|
||||
"🇦🇬": {"code": "en", "country": "Antigua and Barbuda", "name": "English"},
|
||||
"🇦🇮": {"code": "en", "country": "Anguilla", "name": "English"},
|
||||
"🇦🇱": {"code": "sq", "country": "Albania", "name": "Albanian"},
|
||||
"🇦🇲": {"code": "hy", "country": "Armenia", "name": "Armenian"},
|
||||
"🇦🇴": {"code": "pt", "country": "Angola", "name": "Portuguese"},
|
||||
"🇦🇶": {"code": "en", "country": "Antarctica", "name": "English"},
|
||||
"🇦🇷": {"code": "es", "country": "Argentina", "name": "Spanish"},
|
||||
"🇦🇸": {"code": "en", "country": "American Samoa", "name": "English"},
|
||||
"🇦🇹": {"code": "de", "country": "Austria", "name": "German"},
|
||||
"🇦🇺": {"code": "en", "country": "Australia", "name": "English"},
|
||||
"🇦🇼": {"code": "nl", "country": "Aruba", "name": "Dutch"},
|
||||
"🇦🇽": {"code": "sv", "country": "Åland Islands", "name": "Swedish"},
|
||||
"🇦🇿": {"code": "az", "country": "Azerbaijan", "name": "Azerbaijani"},
|
||||
"🇧🇦": {"code": "bs", "country": "Bosnia and Herzegovina", "name": "Bosnian"},
|
||||
"🇧🇧": {"code": "en", "country": "Barbados", "name": "English"},
|
||||
"🇧🇩": {"code": "bn", "country": "Bangladesh", "name": "Bengali"},
|
||||
"🇧🇪": {"code": "nl", "country": "Belgium", "name": "Dutch"},
|
||||
"🇧🇫": {"code": "fr", "country": "Burkina Faso", "name": "French"},
|
||||
"🇧🇬": {"code": "bg", "country": "Bulgaria", "name": "Bulgarian"},
|
||||
"🇧🇭": {"code": "ar", "country": "Bahrain", "name": "Arabic"},
|
||||
"🇧🇮": {"code": "fr", "country": "Burundi", "name": "French"},
|
||||
"🇧🇯": {"code": "fr", "country": "Benin", "name": "French"},
|
||||
"🇧🇱": {"code": "fr", "country": "Saint Barthélemy", "name": "French"},
|
||||
"🇧🇲": {"code": "en", "country": "Bermuda", "name": "English"},
|
||||
"🇧🇳": {"code": "ms", "country": "Brunei Darussalam", "name": "Malay"},
|
||||
"🇧🇴": {"code": "es", "country": "Bolivia (Plurinational State of)", "name": "Spanish"},
|
||||
"🇧🇶": {"code": "nl", "country": "Bonaire, Sint Eustatius and Saba", "name": "Dutch"},
|
||||
"🇧🇷": {"code": "pt", "country": "Brazil", "name": "Portuguese"},
|
||||
"🇧🇸": {"code": "en", "country": "Bahamas", "name": "English"},
|
||||
"🇧🇹": {"code": "dz", "country": "Bhutan", "name": "Dzongkha"},
|
||||
"🇧🇻": {"code": "no", "country": "Bouvet Island", "name": "Norwegian"},
|
||||
"🇧🇼": {"code": "en", "country": "Botswana", "name": "English"},
|
||||
"🇧🇾": {"code": "be", "country": "Belarus", "name": "Belarusian"},
|
||||
"🇧🇿": {"code": "en", "country": "Belize", "name": "English"},
|
||||
"🇨🇦": {"code": "en", "country": "Canada", "name": "English"},
|
||||
"🇨🇨": {"code": "en", "country": "Cocos (Keeling) Islands", "name": "English"},
|
||||
"🇨🇩": {"code": "fr", "country": "Congo (Democratic Republic of the)", "name": "French"},
|
||||
"🇨🇫": {"code": "fr", "country": "Central African Republic", "name": "French"},
|
||||
"🇨🇬": {"code": "fr", "country": "Congo", "name": "French"},
|
||||
"🇨🇭": {"code": "de", "country": "Switzerland", "name": "German"},
|
||||
"🇨🇮": {"code": "fr", "country": "Côte d'Ivoire", "name": "French"},
|
||||
"🇨🇰": {"code": "en", "country": "Cook Islands", "name": "English"},
|
||||
"🇨🇱": {"code": "es", "country": "Chile", "name": "Spanish"},
|
||||
"🇨🇲": {"code": "en", "country": "Cameroon", "name": "English"},
|
||||
"🇨🇳": {"code": "zh", "country": "China", "name": "Chinese"},
|
||||
"🇨🇴": {"code": "es", "country": "Colombia", "name": "Spanish"},
|
||||
"🇨🇷": {"code": "es", "country": "Costa Rica", "name": "Spanish"},
|
||||
"🇨🇺": {"code": "es", "country": "Cuba", "name": "Spanish"},
|
||||
"🇨🇻": {"code": "pt", "country": "Cabo Verde", "name": "Portuguese"},
|
||||
"🇨🇼": {"code": "nl", "country": "Curaçao", "name": "Dutch"},
|
||||
"🇨🇽": {"code": "en", "country": "Christmas Island", "name": "English"},
|
||||
"🇨🇾": {"code": "el", "country": "Cyprus", "name": "Greek (modern)"},
|
||||
"🇨🇿": {"code": "cs", "country": "Czech Republic", "name": "Czech"},
|
||||
"🇩🇪": {"code": "de", "country": "Germany", "name": "German"},
|
||||
"🇩🇯": {"code": "fr", "country": "Djibouti", "name": "French"},
|
||||
"🇩🇰": {"code": "da", "country": "Denmark", "name": "Danish"},
|
||||
"🇩🇲": {"code": "en", "country": "Dominica", "name": "English"},
|
||||
"🇩🇴": {"code": "es", "country": "Dominican Republic", "name": "Spanish"},
|
||||
"🇩🇿": {"code": "ar", "country": "Algeria", "name": "Arabic"},
|
||||
"🇪🇨": {"code": "es", "country": "Ecuador", "name": "Spanish"},
|
||||
"🇪🇪": {"code": "et", "country": "Estonia", "name": "Estonian"},
|
||||
"🇪🇬": {"code": "ar", "country": "Egypt", "name": "Arabic"},
|
||||
"🇪🇭": {"code": "es", "country": "Western Sahara", "name": "Spanish"},
|
||||
"🇪🇷": {"code": "ti", "country": "Eritrea", "name": "Tigrinya"},
|
||||
"🇪🇸": {"code": "es", "country": "Spain", "name": "Spanish"},
|
||||
"🇪🇹": {"code": "am", "country": "Ethiopia", "name": "Amharic"},
|
||||
"🇪🇺": {
|
||||
"code": "EU",
|
||||
"emoji": "🇪🇺",
|
||||
"message": "Not Found",
|
||||
"name": "European Union",
|
||||
"status": 404,
|
||||
"title": "flag for European Union",
|
||||
"unicode": "U+1F1EA U+1F1FA",
|
||||
"country": "N/A",
|
||||
},
|
||||
"🇫🇮": {"code": "fi", "country": "Finland", "name": "Finnish"},
|
||||
"🇫🇯": {"code": "en", "country": "Fiji", "name": "English"},
|
||||
"🇫🇰": {"code": "en", "country": "Falkland Islands (Malvinas)", "name": "English"},
|
||||
"🇫🇲": {"code": "en", "country": "Micronesia (Federated States of)", "name": "English"},
|
||||
"🇫🇴": {"code": "fo", "country": "Faroe Islands", "name": "Faroese"},
|
||||
"🇫🇷": {"code": "fr", "country": "France", "name": "French"},
|
||||
"🇬🇦": {"code": "fr", "country": "Gabon", "name": "French"},
|
||||
"🇬🇧": {
|
||||
"code": "en",
|
||||
"country": "United Kingdom of Great Britain and Northern Ireland",
|
||||
"name": "English",
|
||||
},
|
||||
"🇬🇩": {"code": "en", "country": "Grenada", "name": "English"},
|
||||
"🇬🇪": {"code": "ka", "country": "Georgia", "name": "Georgian"},
|
||||
"🇬🇫": {"code": "fr", "country": "French Guiana", "name": "French"},
|
||||
"🇬🇬": {"code": "en", "country": "Guernsey", "name": "English"},
|
||||
"🇬🇭": {"code": "en", "country": "Ghana", "name": "English"},
|
||||
"🇬🇮": {"code": "en", "country": "Gibraltar", "name": "English"},
|
||||
"🇬🇱": {"code": "kl", "country": "Greenland", "name": "Kalaallisut"},
|
||||
"🇬🇲": {"code": "en", "country": "Gambia", "name": "English"},
|
||||
"🇬🇳": {"code": "fr", "country": "Guinea", "name": "French"},
|
||||
"🇬🇵": {"code": "fr", "country": "Guadeloupe", "name": "French"},
|
||||
"🇬🇶": {"code": "es", "country": "Equatorial Guinea", "name": "Spanish"},
|
||||
"🇬🇷": {"code": "el", "country": "Greece", "name": "Greek (modern)"},
|
||||
"🇬🇸": {
|
||||
"code": "en",
|
||||
"country": "South Georgia and the South Sandwich Islands",
|
||||
"name": "English",
|
||||
},
|
||||
"🇬🇹": {"code": "es", "country": "Guatemala", "name": "Spanish"},
|
||||
"🇬🇺": {"code": "en", "country": "Guam", "name": "English"},
|
||||
"🇬🇼": {"code": "pt", "country": "Guinea-Bissau", "name": "Portuguese"},
|
||||
"🇬🇾": {"code": "en", "country": "Guyana", "name": "English"},
|
||||
"🇭🇰": {"code": "en", "country": "Hong Kong", "name": "English"},
|
||||
"🇭🇲": {"code": "en", "country": "Heard Island and McDonald Islands", "name": "English"},
|
||||
"🇭🇳": {"code": "es", "country": "Honduras", "name": "Spanish"},
|
||||
"🇭🇷": {"code": "hr", "country": "Croatia", "name": "Croatian"},
|
||||
"🇭🇹": {"code": "fr", "country": "Haiti", "name": "French"},
|
||||
"🇭🇺": {"code": "hu", "country": "Hungary", "name": "Hungarian"},
|
||||
"🇮🇩": {"code": "id", "country": "Indonesia", "name": "Indonesian"},
|
||||
"🇮🇪": {"code": "ga", "country": "Ireland", "name": "Irish"},
|
||||
"🇮🇱": {"code": "he", "country": "Israel", "name": "Hebrew (modern)"},
|
||||
"🇮🇲": {"code": "en", "country": "Isle of Man", "name": "English"},
|
||||
"🇮🇳": {"code": "hi", "country": "India", "name": "Hindi"},
|
||||
"🇮🇴": {"code": "en", "country": "British Indian Ocean Territory", "name": "English"},
|
||||
"🇮🇶": {"code": "ar", "country": "Iraq", "name": "Arabic"},
|
||||
"🇮🇷": {"code": "fa", "country": "Iran (Islamic Republic of)", "name": "Persian (Farsi)"},
|
||||
"🇮🇸": {"code": "is", "country": "Iceland", "name": "Icelandic"},
|
||||
"🇮🇹": {"code": "it", "country": "Italy", "name": "Italian"},
|
||||
"🇯🇪": {"code": "en", "country": "Jersey", "name": "English"},
|
||||
"🇯🇲": {"code": "en", "country": "Jamaica", "name": "English"},
|
||||
"🇯🇴": {"code": "ar", "country": "Jordan", "name": "Arabic"},
|
||||
"🇯🇵": {"code": "ja", "country": "Japan", "name": "Japanese"},
|
||||
"🇰🇪": {"code": "en", "country": "Kenya", "name": "English"},
|
||||
"🇰🇬": {"code": "ky", "country": "Kyrgyzstan", "name": "Kyrgyz"},
|
||||
"🇰🇭": {"code": "km", "country": "Cambodia", "name": "Khmer"},
|
||||
"🇰🇮": {"code": "en", "country": "Kiribati", "name": "English"},
|
||||
"🇰🇲": {"code": "ar", "country": "Comoros", "name": "Arabic"},
|
||||
"🇰🇳": {"code": "en", "country": "Saint Kitts and Nevis", "name": "English"},
|
||||
"🇰🇵": {"code": "ko", "country": "Korea (Democratic People's Republic of)", "name": "Korean"},
|
||||
"🇰🇷": {"code": "ko", "country": "Korea (Republic of)", "name": "Korean"},
|
||||
"🇰🇼": {"code": "ar", "country": "Kuwait", "name": "Arabic"},
|
||||
"🇰🇾": {"code": "en", "country": "Cayman Islands", "name": "English"},
|
||||
"🇰🇿": {"code": "kk", "country": "Kazakhstan", "name": "Kazakh"},
|
||||
"🇱🇦": {"code": "lo", "country": "Lao People's Democratic Republic", "name": "Lao"},
|
||||
"🇱🇧": {"code": "ar", "country": "Lebanon", "name": "Arabic"},
|
||||
"🇱🇨": {"code": "en", "country": "Saint Lucia", "name": "English"},
|
||||
"🇱🇮": {"code": "de", "country": "Liechtenstein", "name": "German"},
|
||||
"🇱🇰": {"code": "si", "country": "Sri Lanka", "name": "Sinhalese"},
|
||||
"🇱🇷": {"code": "en", "country": "Liberia", "name": "English"},
|
||||
"🇱🇸": {"code": "en", "country": "Lesotho", "name": "English"},
|
||||
"🇱🇹": {"code": "lt", "country": "Lithuania", "name": "Lithuanian"},
|
||||
"🇱🇺": {"code": "fr", "country": "Luxembourg", "name": "French"},
|
||||
"🇱🇻": {"code": "lv", "country": "Latvia", "name": "Latvian"},
|
||||
"🇱🇾": {"code": "ar", "country": "Libya", "name": "Arabic"},
|
||||
"🇲🇦": {"code": "ar", "country": "Morocco", "name": "Arabic"},
|
||||
"🇲🇨": {"code": "fr", "country": "Monaco", "name": "French"},
|
||||
"🇲🇩": {"code": "ro", "country": "Moldova (Republic of)", "name": "Romanian"},
|
||||
"🇲🇪": {"code": "sr", "country": "Montenegro", "name": "Serbian"},
|
||||
"🇲🇫": {"code": "en", "country": "Saint Martin (French part)", "name": "English"},
|
||||
"🇲🇬": {"code": "fr", "country": "Madagascar", "name": "French"},
|
||||
"🇲🇭": {"code": "en", "country": "Marshall Islands", "name": "English"},
|
||||
"🇲🇰": {
|
||||
"code": "mk",
|
||||
"country": "Macedonia (the former Yugoslav Republic of)",
|
||||
"name": "Macedonian",
|
||||
},
|
||||
"🇲🇱": {"code": "fr", "country": "Mali", "name": "French"},
|
||||
"🇲🇲": {"code": "my", "country": "Myanmar", "name": "Burmese"},
|
||||
"🇲🇳": {"code": "mn", "country": "Mongolia", "name": "Mongolian"},
|
||||
"🇲🇴": {"code": "zh", "country": "Macao", "name": "Chinese"},
|
||||
"🇲🇵": {"code": "en", "country": "Northern Mariana Islands", "name": "English"},
|
||||
"🇲🇶": {"code": "fr", "country": "Martinique", "name": "French"},
|
||||
"🇲🇷": {"code": "ar", "country": "Mauritania", "name": "Arabic"},
|
||||
"🇲🇸": {"code": "en", "country": "Montserrat", "name": "English"},
|
||||
"🇲🇹": {"code": "mt", "country": "Malta", "name": "Maltese"},
|
||||
"🇲🇺": {"code": "en", "country": "Mauritius", "name": "English"},
|
||||
"🇲🇻": {"code": "dv", "country": "Maldives", "name": "Divehi"},
|
||||
"🇲🇼": {"code": "en", "country": "Malawi", "name": "English"},
|
||||
"🇲🇽": {"code": "es", "country": "Mexico", "name": "Spanish"},
|
||||
"🇲🇾": {"code": None, "country": "Malaysia", "name": "Malaysian"},
|
||||
"🇲🇿": {"code": "pt", "country": "Mozambique", "name": "Portuguese"},
|
||||
"🇳🇦": {"code": "en", "country": "Namibia", "name": "English"},
|
||||
"🇳🇨": {"code": "fr", "country": "New Caledonia", "name": "French"},
|
||||
"🇳🇪": {"code": "fr", "country": "Niger", "name": "French"},
|
||||
"🇳🇫": {"code": "en", "country": "Norfolk Island", "name": "English"},
|
||||
"🇳🇬": {"code": "en", "country": "Nigeria", "name": "English"},
|
||||
"🇳🇮": {"code": "es", "country": "Nicaragua", "name": "Spanish"},
|
||||
"🇳🇱": {"code": "nl", "country": "Netherlands", "name": "Dutch"},
|
||||
"🇳🇴": {"code": "no", "country": "Norway", "name": "Norwegian"},
|
||||
"🇳🇵": {"code": "ne", "country": "Nepal", "name": "Nepali"},
|
||||
"🇳🇷": {"code": "en", "country": "Nauru", "name": "English"},
|
||||
"🇳🇺": {"code": "en", "country": "Niue", "name": "English"},
|
||||
"🇳🇿": {"code": "en", "country": "New Zealand", "name": "English"},
|
||||
"🇴🇲": {"code": "ar", "country": "Oman", "name": "Arabic"},
|
||||
"🇵🇦": {"code": "es", "country": "Panama", "name": "Spanish"},
|
||||
"🇵🇪": {"code": "es", "country": "Peru", "name": "Spanish"},
|
||||
"🇵🇫": {"code": "fr", "country": "French Polynesia", "name": "French"},
|
||||
"🇵🇬": {"code": "en", "country": "Papua New Guinea", "name": "English"},
|
||||
"🇵🇭": {"code": "tl", "country": "Philippines", "name": "Tagalog (Filipino)"},
|
||||
"🇵🇰": {"code": "en", "country": "Pakistan", "name": "English"},
|
||||
"🇵🇱": {"code": "pl", "country": "Poland", "name": "Polish"},
|
||||
"🇵🇲": {"code": "fr", "country": "Saint Pierre and Miquelon", "name": "French"},
|
||||
"🇵🇳": {"code": "en", "country": "Pitcairn", "name": "English"},
|
||||
"🇵🇷": {"code": "es", "country": "Puerto Rico", "name": "Spanish"},
|
||||
"🇵🇸": {"code": "ar", "country": "Palestine, State of", "name": "Arabic"},
|
||||
"🇵🇹": {"code": "pt", "country": "Portugal", "name": "Portuguese"},
|
||||
"🇵🇼": {"code": "en", "country": "Palau", "name": "English"},
|
||||
"🇵🇾": {"code": "es", "country": "Paraguay", "name": "Spanish"},
|
||||
"🇶🇦": {"code": "ar", "country": "Qatar", "name": "Arabic"},
|
||||
"🇷🇪": {"code": "fr", "country": "Réunion", "name": "French"},
|
||||
"🇷🇴": {"code": "ro", "country": "Romania", "name": "Romanian"},
|
||||
"🇷🇸": {"code": "sr", "country": "Serbia", "name": "Serbian"},
|
||||
"🇷🇺": {"code": "ru", "country": "Russian Federation", "name": "Russian"},
|
||||
"🇷🇼": {"code": "rw", "country": "Rwanda", "name": "Kinyarwanda"},
|
||||
"🇸🇦": {"code": "ar", "country": "Saudi Arabia", "name": "Arabic"},
|
||||
"🇸🇧": {"code": "en", "country": "Solomon Islands", "name": "English"},
|
||||
"🇸🇨": {"code": "fr", "country": "Seychelles", "name": "French"},
|
||||
"🇸🇩": {"code": "ar", "country": "Sudan", "name": "Arabic"},
|
||||
"🇸🇪": {"code": "sv", "country": "Sweden", "name": "Swedish"},
|
||||
"🇸🇬": {"code": "en", "country": "Singapore", "name": "English"},
|
||||
"🇸🇭": {
|
||||
"code": "en",
|
||||
"country": "Saint Helena, Ascension and Tristan da Cunha",
|
||||
"name": "English",
|
||||
},
|
||||
"🇸🇮": {"code": "sl", "country": "Slovenia", "name": "Slovene"},
|
||||
"🇸🇯": {"code": "no", "country": "Svalbard and Jan Mayen", "name": "Norwegian"},
|
||||
"🇸🇰": {"code": "sk", "country": "Slovakia", "name": "Slovak"},
|
||||
"🇸🇱": {"code": "en", "country": "Sierra Leone", "name": "English"},
|
||||
"🇸🇲": {"code": "it", "country": "San Marino", "name": "Italian"},
|
||||
"🇸🇳": {"code": "fr", "country": "Senegal", "name": "French"},
|
||||
"🇸🇴": {"code": "so", "country": "Somalia", "name": "Somali"},
|
||||
"🇸🇷": {"code": "nl", "country": "Suriname", "name": "Dutch"},
|
||||
"🇸🇸": {"code": "en", "country": "South Sudan", "name": "English"},
|
||||
"🇸🇹": {"code": "pt", "country": "Sao Tome and Principe", "name": "Portuguese"},
|
||||
"🇸🇻": {"code": "es", "country": "El Salvador", "name": "Spanish"},
|
||||
"🇸🇽": {"code": "nl", "country": "Sint Maarten (Dutch part)", "name": "Dutch"},
|
||||
"🇸🇾": {"code": "ar", "country": "Syrian Arab Republic", "name": "Arabic"},
|
||||
"🇸🇿": {"code": "en", "country": "Swaziland", "name": "English"},
|
||||
"🇹🇨": {"code": "en", "country": "Turks and Caicos Islands", "name": "English"},
|
||||
"🇹🇩": {"code": "fr", "country": "Chad", "name": "French"},
|
||||
"🇹🇫": {"code": "fr", "country": "French Southern Territories", "name": "French"},
|
||||
"🇹🇬": {"code": "fr", "country": "Togo", "name": "French"},
|
||||
"🇹🇭": {"code": "th", "country": "Thailand", "name": "Thai"},
|
||||
"🇹🇯": {"code": "tg", "country": "Tajikistan", "name": "Tajik"},
|
||||
"🇹🇰": {"code": "en", "country": "Tokelau", "name": "English"},
|
||||
"🇹🇱": {"code": "pt", "country": "Timor-Leste", "name": "Portuguese"},
|
||||
"🇹🇲": {"code": "tk", "country": "Turkmenistan", "name": "Turkmen"},
|
||||
"🇹🇳": {"code": "ar", "country": "Tunisia", "name": "Arabic"},
|
||||
"🇹🇴": {"code": "en", "country": "Tonga", "name": "English"},
|
||||
"🇹🇷": {"code": "tr", "country": "Turkey", "name": "Turkish"},
|
||||
"🇹🇹": {"code": "en", "country": "Trinidad and Tobago", "name": "English"},
|
||||
"🇹🇻": {"code": "en", "country": "Tuvalu", "name": "English"},
|
||||
"🇹🇼": {"code": "zh", "country": "Taiwan", "name": "Chinese"},
|
||||
"🇹🇿": {"code": "sw", "country": "Tanzania, United Republic of", "name": "Swahili"},
|
||||
"🇺🇦": {"code": "uk", "country": "Ukraine", "name": "Ukrainian"},
|
||||
"🇺🇬": {"code": "en", "country": "Uganda", "name": "English"},
|
||||
"🇺🇲": {"code": "en", "country": "United States Minor Outlying Islands", "name": "English"},
|
||||
"🇺🇸": {"code": "en", "country": "United States of America", "name": "English"},
|
||||
"🇺🇾": {"code": "es", "country": "Uruguay", "name": "Spanish"},
|
||||
"🇺🇿": {"code": "uz", "country": "Uzbekistan", "name": "Uzbek"},
|
||||
"🇻🇦": {"code": "la", "country": "Holy See", "name": "Latin"},
|
||||
"🇻🇨": {"code": "en", "country": "Saint Vincent and the Grenadines", "name": "English"},
|
||||
"🇻🇪": {"code": "es", "country": "Venezuela (Bolivarian Republic of)", "name": "Spanish"},
|
||||
"🇻🇬": {"code": "en", "country": "Virgin Islands (British)", "name": "English"},
|
||||
"🇻🇮": {"code": "en", "country": "Virgin Islands (U.S.)", "name": "English"},
|
||||
"🇻🇳": {"code": "vi", "country": "Viet Nam", "name": "Vietnamese"},
|
||||
"🇻🇺": {"code": "bi", "country": "Vanuatu", "name": "Bislama"},
|
||||
"🇼🇫": {"code": "fr", "country": "Wallis and Futuna", "name": "French"},
|
||||
"🇼🇸": {"code": "sm", "country": "Samoa", "name": "Samoan"},
|
||||
"🇾🇪": {"code": "ar", "country": "Yemen", "name": "Arabic"},
|
||||
"🇾🇹": {"code": "fr", "country": "Mayotte", "name": "French"},
|
||||
"🇿🇦": {"code": "af", "country": "South Africa", "name": "Afrikaans"},
|
||||
"🇿🇲": {"code": "en", "country": "Zambia", "name": "English"},
|
||||
"🇿🇼": {"code": "en", "country": "Zimbabwe", "name": "English"},
|
||||
}
|
29
translate/info.json
Normal file
29
translate/info.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"author" : [
|
||||
"Aziz",
|
||||
"TrustyJAID",
|
||||
"brandons209"
|
||||
],
|
||||
"description" : "Add flag emojis to messages to translate to that language or translate messages by command.",
|
||||
"disabled" : false,
|
||||
"end_user_data_statement" : "This cog does not persistently store data or metadata about users. However, this cog does pass user data to an external API for the purposes of analyzing and translating languages.",
|
||||
"hidden" : true,
|
||||
"install_msg" : "1. Go to Google Developers Console and log in with your Google account. (https://console.developers.google.com/)\n2. You should be prompted to create a new project (name does not matter).\n3. Click on Enable APIs and Services at the top.\n4. In the list of APIs choose or search for Cloud Translate API and click on it. Choose Enable.\n5. Click on Credentials on the left navigation bar.\n6. Click on Create Credential at the top.\n7. At the top click the link for \"API key\".\n8. No application restrictions are needed. Click Create at the bottom.\n9. You now have a key to add to `[p]translateset` Note: This cog may end up costing lots of money to use up to $20 per 1 million characters.",
|
||||
"max_bot_version" : "0.0.0",
|
||||
"min_bot_version" : "3.1.8",
|
||||
"min_python_version" : [
|
||||
3,
|
||||
7,
|
||||
2
|
||||
],
|
||||
"name" : "Translate",
|
||||
"permissions" : [],
|
||||
"required_cogs" : {},
|
||||
"requirements" : [],
|
||||
"short" : "Translate messages using google translate!",
|
||||
"tags" : [
|
||||
"utility",
|
||||
"translation"
|
||||
],
|
||||
"type" : "COG"
|
||||
}
|
157
translate/locales/fr-FR.po
Normal file
157
translate/locales/fr-FR.po
Normal file
|
@ -0,0 +1,157 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-02-09 00:37+0100\n"
|
||||
"PO-Revision-Date: 2019-02-09 01::03+0100\n"
|
||||
"Last-Translator: Predä <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: FRENCH <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: redgettext 2.2\n"
|
||||
|
||||
|
||||
#: translate.py:62
|
||||
#, docstring
|
||||
msgid ""
|
||||
"\n"
|
||||
" Translate messages using google translate\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Traduire des messages en utilisant Google Traduction\n\n"
|
||||
" "
|
||||
|
||||
#: translate.py:90
|
||||
msgid " said:"
|
||||
msgstr " a dit :"
|
||||
|
||||
#: translate.py:91
|
||||
msgid " to "
|
||||
msgstr " vers "
|
||||
|
||||
#: translate.py:91
|
||||
msgid "Requested by "
|
||||
msgstr "Demandé par "
|
||||
|
||||
#: translate.py:185
|
||||
msgid "said:"
|
||||
msgstr "a dit :"
|
||||
|
||||
#: translate.py:305
|
||||
#, docstring
|
||||
msgid ""
|
||||
"\n"
|
||||
" Translate messages with google translate\n"
|
||||
"\n"
|
||||
" `to_language` is the language you would like to translate\n"
|
||||
" `message` is the message to translate\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Traduire des messages avec Google Traduction\n"
|
||||
"\n"
|
||||
" `to_language` est la langue que vous souhaitez traduire\n\n"
|
||||
" `message` est le message que vous voulez traduire\n\n"
|
||||
" "
|
||||
|
||||
#: translate.py:313
|
||||
msgid "The bot owner needs to set an api key first!"
|
||||
msgstr "Le propriétaire du bot doit d'abord définir la clé API !"
|
||||
|
||||
#: translate.py:340
|
||||
#, docstring
|
||||
msgid ""
|
||||
"\n"
|
||||
" Toggle the bot auto translating\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Activer la traduction automatique du bot\n\n"
|
||||
" "
|
||||
|
||||
#: translate.py:349
|
||||
#, docstring
|
||||
msgid ""
|
||||
"\n"
|
||||
" Toggle translations to flag emoji reactions\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Activer la traduction en utilisant des drapeaux dans les réactions\n\n"
|
||||
" "
|
||||
|
||||
#: translate.py:355 translate.py:372
|
||||
msgid "on"
|
||||
msgstr "activée"
|
||||
|
||||
#: translate.py:357 translate.py:374
|
||||
msgid "off"
|
||||
msgstr "désactivée"
|
||||
|
||||
#: translate.py:359
|
||||
msgid "Reaction translations have been turned "
|
||||
msgstr "La traduction en se servant des réactions a été "
|
||||
|
||||
#: translate.py:366
|
||||
#, docstring
|
||||
msgid ""
|
||||
"\n"
|
||||
" Toggle translations with flag emojis in text\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Activer la traduction en utilisant des émojis de drapeaux dans le texte\n"
|
||||
" "
|
||||
|
||||
#: translate.py:376
|
||||
msgid "Flag emoji translations have been turned "
|
||||
msgstr "La traduction en utilisant des émojis de drapeaux a été "
|
||||
|
||||
#: translate.py:382
|
||||
#, docstring
|
||||
msgid ""
|
||||
"\n"
|
||||
" You must get an API key from google to set this up\n"
|
||||
"\n"
|
||||
" Note: Using this cog costs money, current rates are $20 per 1 million characters.\n"
|
||||
"\n"
|
||||
" 1. Go to Google Developers Console and log in with your Google account. \n"
|
||||
" (https://console.developers.google.com/)\n"
|
||||
" 2. You should be prompted to create a new project (name does not matter).\n"
|
||||
" 3. Click on Enable APIs and Services at the top.\n"
|
||||
" 4. In the list of APIs choose or search for Cloud Translate API and click on it. \n"
|
||||
" Choose Enable.\n"
|
||||
" 5. Click on Credentials on the left navigation bar.\n"
|
||||
" 6. Click on Create Credential at the top.\n"
|
||||
" 7. At the top click the link for \"API key\".\n"
|
||||
" 8. No application restrictions are needed. Click Create at the bottom.\n"
|
||||
" 9. You now have a key to add to `[p]translateset`\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Vous devez obtenir une clé d'API de Google pour configurer ceci\n"
|
||||
"\n"
|
||||
" Remarque : L'utilisation de ce cog coûte de l'argent, les taux actuels sont d'environ 17€ pour 1 million de caractères.\n"
|
||||
"\n"
|
||||
" 1. Allez sur la console développeurs Google, et connectez-vous avec votre compte Google. \n\n"
|
||||
" (https://console.developers.google.com/)\n\n"
|
||||
" 2. Vous devriez être invité à créer un nouveau projet (le nom n'a pas d'importance).\n\n"
|
||||
" 3. Cliquez sur \"Activer des API et des services\" en haut de la page.\n\n"
|
||||
" 4. Dans la liste des APIs, choisissez ou recherchez Cloud Translate API, cliquez dessus. \n\n"
|
||||
" Choisissez \"Activer\".\n\n"
|
||||
" 5. Cliquez sur \"Identifiants\" dans la barre de navigation en bas à gauche.\n\n"
|
||||
" 6. Cliquez sur \"Créer des identifiants\" en haut de la page.\n\n"
|
||||
" 7. En haut cliquez sur le lien pour \"Clé API\".\n\n"
|
||||
" 8. Aucunes restrictions d'applications sont nécessaires. Cliquez sur \"Créer\" en bas de la page.\n\n"
|
||||
" 9. Vous avez maintenant une clé à ajouter sur `[p]translateset`\n\n"
|
||||
" "
|
||||
|
||||
#: translate.py:400
|
||||
msgid "API key set."
|
||||
msgstr "Clé API définie."
|
||||
|
456
translate/translate.py
Normal file
456
translate/translate.py
Normal file
|
@ -0,0 +1,456 @@
|
|||
import discord
|
||||
import logging
|
||||
from typing import Optional, Union
|
||||
|
||||
from discord.ext.commands.errors import BadArgument
|
||||
from redbot.core import Config, checks, commands, version_info, VersionInfo
|
||||
from redbot.core.i18n import Translator, cog_i18n
|
||||
from redbot.core.utils.chat_formatting import humanize_list, error
|
||||
|
||||
from .api import FlagTranslation, GoogleTranslateAPI
|
||||
from .converters import ChannelUserRole
|
||||
from .errors import GoogleTranslateAPIError
|
||||
|
||||
"""
|
||||
Translator cog
|
||||
|
||||
Cog credit to aziz#5919 for the idea and
|
||||
|
||||
Links
|
||||
|
||||
Wiki https://goo.gl/3fxjSA
|
||||
GitHub https://goo.gl/oQAQde
|
||||
Support the developer https://goo.gl/Brchj4
|
||||
Invite the bot to your guild https://goo.gl/aQm2G7
|
||||
Join the official development guild https://discord.gg/uekTNPj
|
||||
"""
|
||||
|
||||
BASE_URL = "https://translation.googleapis.com"
|
||||
_ = Translator("Translate", __file__)
|
||||
log = logging.getLogger("red.trusty-cogs.Translate")
|
||||
|
||||
|
||||
@cog_i18n(_)
|
||||
class Translate(GoogleTranslateAPI, commands.Cog):
|
||||
"""
|
||||
Translate messages using Google Translate
|
||||
"""
|
||||
|
||||
__author__ = ["Aziz", "TrustyJAID"]
|
||||
__version__ = "2.3.7"
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.config = Config.get_conf(self, 156434873547585, force_registration=True)
|
||||
default_guild = {
|
||||
"reaction": False,
|
||||
"text": False,
|
||||
"whitelist": [],
|
||||
"blacklist": [],
|
||||
"count": {"characters": 0, "requests": 0, "detect": 0},
|
||||
"autosend": {},
|
||||
}
|
||||
default = {
|
||||
"cooldown": {"past_flags": [], "timeout": 0, "multiple": False},
|
||||
"count": {"characters": 0, "requests": 0, "detect": 0},
|
||||
}
|
||||
self.config.register_guild(**default_guild)
|
||||
self.config.register_global(**default)
|
||||
self.cache = {
|
||||
"translations": [],
|
||||
"cooldown_translations": {},
|
||||
"guild_messages": [],
|
||||
"guild_reactions": [],
|
||||
"cooldown": {},
|
||||
"guild_blacklist": {},
|
||||
"guild_whitelist": {},
|
||||
"autolangs": {},
|
||||
}
|
||||
self._key: Optional[str] = None
|
||||
self._clear_cache = self.bot.loop.create_task(self.cleanup_cache())
|
||||
self._save_loop = self.bot.loop.create_task(self.save_usage())
|
||||
self._guild_counter = {}
|
||||
self._global_counter = {}
|
||||
|
||||
def format_help_for_context(self, ctx: commands.Context) -> str:
|
||||
"""
|
||||
Thanks Sinbad!
|
||||
"""
|
||||
pre_processed = super().format_help_for_context(ctx)
|
||||
return f"{pre_processed}\n\nCog Version: {self.__version__}"
|
||||
|
||||
async def red_delete_data_for_user(self, **kwargs):
|
||||
"""
|
||||
Nothing to delete
|
||||
"""
|
||||
return
|
||||
|
||||
async def init(self) -> None:
|
||||
try:
|
||||
key = await self.config.api_key()
|
||||
except AttributeError:
|
||||
return
|
||||
try:
|
||||
central_key = await self.bot.get_shared_api_tokens("google_translate")
|
||||
except AttributeError:
|
||||
# Red 3.1 support
|
||||
central_key = await self.bot.db.api_tokens.get_raw("google_translate", default={})
|
||||
if not central_key:
|
||||
try:
|
||||
await self.bot.set_shared_api_tokens("google_translate", api_key=key)
|
||||
except AttributeError:
|
||||
await self.bot.db.api_tokens.set_raw("google_translate", value={"api_key": key})
|
||||
await self.config.api_key.clear()
|
||||
self._global_counter = await self.config.count()
|
||||
all_guilds = await self.config.all_guilds()
|
||||
for g_id, data in all_guilds.items():
|
||||
self._guild_counter[g_id] = data["count"]
|
||||
|
||||
@commands.command()
|
||||
async def translate(
|
||||
self,
|
||||
ctx: commands.Context,
|
||||
to_language: FlagTranslation,
|
||||
*,
|
||||
message: Union[discord.Message, str],
|
||||
) -> None:
|
||||
"""
|
||||
Translate messages with Google Translate
|
||||
|
||||
`<to_language>` is the language you would like to translate
|
||||
`<message>` is the message to translate, this can be words you want
|
||||
to translate, a channelID-messageID from SHIFT + clicking a message and copying ID,
|
||||
a message ID from the current channel, or message link
|
||||
"""
|
||||
if not await self._get_google_api_key():
|
||||
msg = _("The bot owner needs to set an api key first!")
|
||||
await ctx.send(msg)
|
||||
return
|
||||
author = ctx.message.author
|
||||
requestor = ctx.message.author
|
||||
msg = ctx.message
|
||||
if isinstance(message, discord.Message):
|
||||
msg = message
|
||||
author = message.author
|
||||
message = message.clean_content
|
||||
try:
|
||||
detected_lang = await self.detect_language(message)
|
||||
await self.add_detect(ctx.guild)
|
||||
except GoogleTranslateAPIError as e:
|
||||
await ctx.send(str(e))
|
||||
return
|
||||
from_lang = detected_lang[0][0]["language"]
|
||||
original_lang = detected_lang[0][0]["language"]
|
||||
if to_language == original_lang:
|
||||
return await ctx.send(
|
||||
_("I cannot translate `{from_lang}` to `{to}`").format(from_lang=from_lang, to=to_language)
|
||||
)
|
||||
try:
|
||||
translated_text = await self.translate_text(original_lang, to_language, message)
|
||||
await self.add_requests(ctx.guild, message)
|
||||
except GoogleTranslateAPIError as e:
|
||||
await ctx.send(str(e))
|
||||
return
|
||||
|
||||
if ctx.channel.permissions_for(ctx.me).embed_links:
|
||||
translation = (translated_text, from_lang, to_language)
|
||||
em = await self.translation_embed(author, translation, requestor)
|
||||
if version_info >= VersionInfo.from_str("3.4.6") and msg.channel.id == ctx.channel.id:
|
||||
await ctx.send(embed=em, reference=msg, mention_author=False)
|
||||
else:
|
||||
await ctx.send(embed=em)
|
||||
else:
|
||||
if version_info >= VersionInfo.from_str("3.4.6") and msg.channel.id == ctx.channel.id:
|
||||
await ctx.send(translated_text, reference=msg, mention_author=False)
|
||||
else:
|
||||
await ctx.send(translated_text)
|
||||
|
||||
@commands.group()
|
||||
async def translateset(self, ctx: commands.Context) -> None:
|
||||
"""
|
||||
Toggle the bot auto translating
|
||||
"""
|
||||
pass
|
||||
|
||||
@translateset.command(name="auto")
|
||||
async def translate_auto(self, ctx: commands.Context, languages: str, *links: discord.TextChannel) -> None:
|
||||
"""
|
||||
Set channels to auto translate messages from and to
|
||||
|
||||
All channels will be linked together, that is every channel's messages will be translated to every other channel.
|
||||
|
||||
Languages should be the **receive language** that every message sent to it should be translated to.
|
||||
|
||||
**languages** should be a comma seperated list of languages with no spaces matching the links!
|
||||
"""
|
||||
langs = [l.strip() for l in languages.strip().split(",")]
|
||||
if len(langs) != len(links):
|
||||
return await ctx.send(error("The number of lanuages and link channels don't match!"), delete_after=30)
|
||||
|
||||
await self.config.guild(ctx.guild).autosend.set({l.id: lang for l, lang in zip(links, langs)})
|
||||
await ctx.tick()
|
||||
|
||||
@translateset.command(name="stats")
|
||||
async def translate_stats(self, ctx: commands.Context, guild_id: Optional[int]):
|
||||
"""
|
||||
Shows translation usage
|
||||
"""
|
||||
if guild_id and not await self.bot.is_owner(ctx.author):
|
||||
return await ctx.send(_("That is only available for the bot owner."))
|
||||
elif guild_id and await self.bot.is_owner(ctx.author):
|
||||
if not (guild := self.bot.get_guild(guild_id)):
|
||||
return await ctx.send(_("Guild `{guild_id}` not found.").format(guild_id=guild_id))
|
||||
else:
|
||||
guild = ctx.guild
|
||||
tr_keys = {
|
||||
"requests": _("API Requests:"),
|
||||
"detect": _("API Detect Language:"),
|
||||
"characters": _("Characters requested:"),
|
||||
}
|
||||
count = (
|
||||
self._guild_counter[guild.id] if guild.id in self._guild_counter else await self.config.guild(guild).count()
|
||||
)
|
||||
gl_count = self._global_counter if self._global_counter else await self.config.count()
|
||||
msg = _("__Global Usage__:\n")
|
||||
for key, value in gl_count.items():
|
||||
msg += tr_keys[key] + f" **{value}**\n"
|
||||
msg += _("__{guild} Usage__:\n").format(guild=guild.name)
|
||||
for key, value in count.items():
|
||||
msg += tr_keys[key] + f" **{value}**\n"
|
||||
await ctx.maybe_send_embed(msg)
|
||||
|
||||
@translateset.group(aliases=["blocklist"])
|
||||
@checks.mod_or_permissions(manage_messages=True)
|
||||
@commands.guild_only()
|
||||
async def blacklist(self, ctx: commands.Context) -> None:
|
||||
"""
|
||||
Set blacklist options for translations
|
||||
|
||||
blacklisting supports channels, users, or roles
|
||||
"""
|
||||
pass
|
||||
|
||||
@translateset.group(aliases=["allowlist"])
|
||||
@checks.mod_or_permissions(manage_messages=True)
|
||||
@commands.guild_only()
|
||||
async def whitelist(self, ctx: commands.Context) -> None:
|
||||
"""
|
||||
Set whitelist options for translations
|
||||
|
||||
whitelisting supports channels, users, or roles
|
||||
"""
|
||||
pass
|
||||
|
||||
@whitelist.command(name="add")
|
||||
@checks.mod_or_permissions(manage_messages=True)
|
||||
@commands.guild_only()
|
||||
async def whitelist_add(self, ctx: commands.Context, *channel_user_role: ChannelUserRole) -> None:
|
||||
"""
|
||||
Add a channel, user, or role to translation whitelist
|
||||
"""
|
||||
if len(channel_user_role) < 1:
|
||||
return await ctx.send(_("You must supply 1 or more channels users or roles to be whitelisted."))
|
||||
for obj in channel_user_role:
|
||||
if obj.id not in await self.config.guild(ctx.guild).whitelist():
|
||||
async with self.config.guild(ctx.guild).whitelist() as whitelist:
|
||||
whitelist.append(obj.id)
|
||||
await self._bw_list_cache_update(ctx.guild)
|
||||
msg = _("`{list_type}` added to translation whitelist.")
|
||||
list_type = humanize_list([c.name for c in channel_user_role])
|
||||
await ctx.send(msg.format(list_type=list_type))
|
||||
|
||||
@whitelist.command(name="remove", aliases=["rem", "del"])
|
||||
@checks.mod_or_permissions(manage_messages=True)
|
||||
@commands.guild_only()
|
||||
async def whitelist_remove(self, ctx: commands.Context, *channel_user_role: ChannelUserRole) -> None:
|
||||
"""
|
||||
Remove a channel, user, or role from translation whitelist
|
||||
"""
|
||||
if len(channel_user_role) < 1:
|
||||
return await ctx.send(
|
||||
_("You must supply 1 or more channels, users, " "or roles to be removed from the whitelist")
|
||||
)
|
||||
for obj in channel_user_role:
|
||||
if obj.id in await self.config.guild(ctx.guild).whitelist():
|
||||
async with self.config.guild(ctx.guild).whitelist() as whitelist:
|
||||
whitelist.remove(obj.id)
|
||||
await self._bw_list_cache_update(ctx.guild)
|
||||
msg = _("`{list_type}` removed from translation whitelist.")
|
||||
list_type = humanize_list([c.name for c in channel_user_role])
|
||||
await ctx.send(msg.format(list_type=list_type))
|
||||
|
||||
@whitelist.command(name="list")
|
||||
@checks.mod_or_permissions(manage_messages=True)
|
||||
@commands.guild_only()
|
||||
async def whitelist_list(self, ctx: commands.Context) -> None:
|
||||
"""
|
||||
List Channels, Users, and Roles in the servers translation whitelist.
|
||||
"""
|
||||
whitelist = []
|
||||
for _id in await self.config.guild(ctx.guild).whitelist():
|
||||
try:
|
||||
whitelist.append(await ChannelUserRole().convert(ctx, str(_id)))
|
||||
except BadArgument:
|
||||
continue
|
||||
whitelist_s = ", ".join(x.name for x in whitelist)
|
||||
await ctx.send(_("`{whitelisted}` are currently whitelisted.").format(whitelisted=whitelist_s))
|
||||
|
||||
@blacklist.command(name="add")
|
||||
@checks.mod_or_permissions(manage_messages=True)
|
||||
@commands.guild_only()
|
||||
async def blacklist_add(self, ctx: commands.Context, *channel_user_role: ChannelUserRole) -> None:
|
||||
"""
|
||||
Add a channel, user, or role to translation blacklist
|
||||
"""
|
||||
if len(channel_user_role) < 1:
|
||||
return await ctx.send(_("You must supply 1 or more channels users or roles to be blacklisted."))
|
||||
for obj in channel_user_role:
|
||||
if obj.id not in await self.config.guild(ctx.guild).blacklist():
|
||||
async with self.config.guild(ctx.guild).blacklist() as blacklist:
|
||||
blacklist.append(obj.id)
|
||||
await self._bw_list_cache_update(ctx.guild)
|
||||
msg = _("`{list_type}` added to translation blacklist.")
|
||||
list_type = humanize_list([c.name for c in channel_user_role])
|
||||
await ctx.send(msg.format(list_type=list_type))
|
||||
|
||||
@blacklist.command(name="remove", aliases=["rem", "del"])
|
||||
@checks.mod_or_permissions(manage_messages=True)
|
||||
@commands.guild_only()
|
||||
async def blacklist_remove(self, ctx: commands.Context, *channel_user_role: ChannelUserRole) -> None:
|
||||
"""
|
||||
Remove a channel, user, or role from translation blacklist
|
||||
"""
|
||||
if len(channel_user_role) < 1:
|
||||
return await ctx.send(
|
||||
_("You must supply 1 or more channels, users, " "or roles to be removed from the blacklist")
|
||||
)
|
||||
for obj in channel_user_role:
|
||||
if obj.id in await self.config.guild(ctx.guild).blacklist():
|
||||
async with self.config.guild(ctx.guild).blacklist() as blacklist:
|
||||
blacklist.remove(obj.id)
|
||||
await self._bw_list_cache_update(ctx.guild)
|
||||
msg = _("`{list_type}` removed from translation blacklist.")
|
||||
list_type = humanize_list([c.name for c in channel_user_role])
|
||||
await ctx.send(msg.format(list_type=list_type))
|
||||
|
||||
@blacklist.command(name="list")
|
||||
@checks.mod_or_permissions(manage_messages=True)
|
||||
@commands.guild_only()
|
||||
async def blacklist_list(self, ctx: commands.Context) -> None:
|
||||
"""
|
||||
List Channels, Users, and Roles in the servers translation blacklist.
|
||||
"""
|
||||
blacklist = []
|
||||
for _id in await self.config.guild(ctx.guild).blacklist():
|
||||
try:
|
||||
blacklist.append(await ChannelUserRole().convert(ctx, str(_id)))
|
||||
except BadArgument:
|
||||
continue
|
||||
blacklist_s = ", ".join(x.name for x in blacklist)
|
||||
await ctx.send(_("`{blacklisted}` are currently blacklisted.").format(blacklisted=blacklist_s))
|
||||
|
||||
@translateset.command(aliases=["reaction", "reactions"])
|
||||
@checks.mod_or_permissions(manage_channels=True)
|
||||
@commands.guild_only()
|
||||
async def react(self, ctx: commands.Context) -> None:
|
||||
"""
|
||||
Toggle translations to flag emoji reactions
|
||||
"""
|
||||
guild = ctx.message.guild
|
||||
toggle = not await self.config.guild(guild).reaction()
|
||||
if toggle:
|
||||
verb = _("on")
|
||||
else:
|
||||
verb = _("off")
|
||||
if guild.id in self.cache["guild_reactions"]:
|
||||
self.cache["guild_reactions"].remove(guild.id)
|
||||
await self.config.guild(guild).reaction.set(toggle)
|
||||
msg = _("Reaction translations have been turned ")
|
||||
await ctx.send(msg + verb)
|
||||
|
||||
@translateset.command(aliases=["multi"])
|
||||
@checks.is_owner()
|
||||
@commands.guild_only()
|
||||
async def multiple(self, ctx: commands.Context) -> None:
|
||||
"""
|
||||
Toggle multiple translations for the same message
|
||||
|
||||
This will also ignore the translated message from
|
||||
being translated into another language
|
||||
"""
|
||||
toggle = not await self.config.cooldown.multiple()
|
||||
if toggle:
|
||||
verb = _("on")
|
||||
else:
|
||||
verb = _("off")
|
||||
await self.config.cooldown.multiple.set(toggle)
|
||||
self.cache["cooldown"] = await self.config.cooldown()
|
||||
msg = _("Multiple translations have been turned ")
|
||||
await ctx.send(msg + verb)
|
||||
|
||||
@translateset.command(aliases=["cooldown"])
|
||||
@checks.is_owner()
|
||||
@commands.guild_only()
|
||||
async def timeout(self, ctx: commands.Context, time: int) -> None:
|
||||
"""
|
||||
Set the cooldown before a message can be reacted to again
|
||||
for translation
|
||||
|
||||
`<time>` Number of seconds until that message can be reacted to again
|
||||
Note: If multiple reactions are not allowed the timeout setting
|
||||
is ignored until the cache cleanup ~10 minutes.
|
||||
"""
|
||||
await self.config.cooldown.timeout.set(time)
|
||||
self.cache["cooldown"] = await self.config.cooldown()
|
||||
msg = _("Translation timeout set to {time}s.").format(time=time)
|
||||
await ctx.send(msg)
|
||||
|
||||
@translateset.command(aliases=["flags"])
|
||||
@checks.mod_or_permissions(manage_channels=True)
|
||||
@commands.guild_only()
|
||||
async def flag(self, ctx: commands.Context) -> None:
|
||||
"""
|
||||
Toggle translations with flag emojis in text
|
||||
"""
|
||||
guild = ctx.message.guild
|
||||
toggle = not await self.config.guild(guild).text()
|
||||
if toggle:
|
||||
verb = _("on")
|
||||
else:
|
||||
verb = _("off")
|
||||
if guild.id in self.cache["guild_messages"]:
|
||||
self.cache["guild_messages"].remove(guild.id)
|
||||
await self.config.guild(guild).text.set(toggle)
|
||||
msg = _("Flag emoji translations have been turned ")
|
||||
await ctx.send(msg + verb)
|
||||
|
||||
@translateset.command()
|
||||
@checks.is_owner()
|
||||
async def creds(self, ctx: commands.Context) -> None:
|
||||
"""
|
||||
You must get an API key from Google to set this up
|
||||
|
||||
Note: Using this cog costs money, current rates are $20 per 1 million characters.
|
||||
"""
|
||||
msg = _(
|
||||
"1. Go to Google Developers Console and log in with your Google account."
|
||||
"(https://console.developers.google.com/)\n"
|
||||
"2. You should be prompted to create a new project (name does not matter).\n"
|
||||
"3. Click on Enable APIs and Services at the top.\n"
|
||||
"4. In the list of APIs choose or search for Cloud Translate API and click on it."
|
||||
"Choose Enable.\n"
|
||||
"5. Click on Credentials on the left navigation bar.\n"
|
||||
"6. Click on Create Credential at the top.\n"
|
||||
'7. At the top click the link for "API key".\n'
|
||||
"8. No application restrictions are needed. Click Create at the bottom.\n"
|
||||
"9. You now have a key to add to \n"
|
||||
"`{prefix}set api google_translate api_key,YOUR_KEY_HERE`\n"
|
||||
).format(prefix=ctx.prefix)
|
||||
await ctx.maybe_send_embed(msg)
|
||||
|
||||
def cog_unload(self):
|
||||
self._clear_cache.cancel()
|
||||
self._save_loop.cancel()
|
||||
self.bot.loop.create_task(self._save_usage_stats())
|
||||
|
||||
__unload = cog_unload
|
Loading…
Reference in a new issue