add(i18n): create a language switcher command for all guilds

This commit is contained in:
Romain J 2019-09-29 23:01:49 +02:00
commit d5f1f71a0a
8 changed files with 125 additions and 71 deletions

View file

@ -9,6 +9,7 @@ import humanize
from discord.ext import commands
from bot import TuxBot
from .utils.models.lang import Lang
from .utils.lang import Texts
from .utils.models.warn import Warn
@ -35,7 +36,7 @@ class Admin(commands.Cog):
member: discord.Member = kwargs.get('member')
reason = kwargs.get(
'reason',
Texts('admin').get("Please enter a reason")
Texts('admin', ctx).get("Please enter a reason")
)
if kwargs.get('type') == 'ban':
@ -86,7 +87,7 @@ class Admin(commands.Cog):
message_id)
await message.edit(content=content)
except (discord.errors.NotFound, discord.errors.Forbidden):
await ctx.send(Texts('utils').get("Unable to find the message"),
await ctx.send(Texts('utils', ctx).get("Unable to find the message"),
delete_after=5)
@_say.command(name='to')
@ -119,10 +120,10 @@ class Admin(commands.Cog):
await ctx.send(embed=e)
except discord.Forbidden:
await ctx.send(Texts('admin').get("Unable to ban this user"),
await ctx.send(Texts('admin', ctx).get("Unable to ban this user"),
delete_after=5)
except discord.errors.NotFound:
await ctx.send(Texts('utils').get("Unable to find the user..."),
await ctx.send(Texts('utils', ctx).get("Unable to find the user..."),
delete_after=5)
"""---------------------------------------------------------------------"""
@ -144,10 +145,10 @@ class Admin(commands.Cog):
await ctx.send(embed=e)
except discord.Forbidden:
await ctx.send(Texts('admin').get("Unable to kick this user"),
await ctx.send(Texts('admin', ctx).get("Unable to kick this user"),
delete_after=5)
except discord.errors.NotFound:
await ctx.send(Texts('utils').get("Unable to find the user..."),
await ctx.send(Texts('utils', ctx).get("Unable to find the user..."),
delete_after=5)
"""---------------------------------------------------------------------"""
@ -179,7 +180,7 @@ class Admin(commands.Cog):
for emoji in emojis:
await message.add_reaction(emoji)
except discord.errors.NotFound:
await ctx.send(Texts('utils').get("Unable to find the message"),
await ctx.send(Texts('utils', ctx).get("Unable to find the message"),
delete_after=5)
@_react.command(name='clear')
@ -189,7 +190,7 @@ class Admin(commands.Cog):
message_id)
await message.clear_reactions()
except discord.errors.NotFound:
await ctx.send(Texts('utils').get("Unable to find the message"),
await ctx.send(Texts('utils', ctx).get("Unable to find the message"),
delete_after=5)
"""---------------------------------------------------------------------"""
@ -206,7 +207,7 @@ class Admin(commands.Cog):
message_id)
await message.delete()
except (discord.errors.NotFound, discord.errors.Forbidden):
await ctx.send(Texts('utils').get("Unable to find the message"),
await ctx.send(Texts('utils', ctx).get("Unable to find the message"),
delete_after=5)
@_delete.command(name='from', aliases=['to', 'in'])
@ -222,7 +223,7 @@ class Admin(commands.Cog):
message_id)
await message.delete()
except (discord.errors.NotFound, discord.errors.Forbidden):
await ctx.send(Texts('utils').get("Unable to find the message"),
await ctx.send(Texts('utils', ctx).get("Unable to find the message"),
delete_after=5)
"""---------------------------------------------------------------------"""
@ -276,7 +277,7 @@ class Admin(commands.Cog):
if ctx.invoked_subcommand is None:
warns_list, warns = await self.get_warn(ctx)
e = discord.Embed(
title=f"{warns.count()} {Texts('admin').get('last warns')}: ",
title=f"{warns.count()} {Texts('admin', ctx).get('last warns')}: ",
description=warns_list
)
@ -288,7 +289,7 @@ class Admin(commands.Cog):
member = await ctx.guild.fetch_member(member.id)
if not member:
return await ctx.send(
Texts('utils').get("Unable to find the user...")
Texts('utils', ctx).get("Unable to find the user...")
)
def check(pld: discord.RawReactionActionEvent):
@ -301,15 +302,15 @@ class Admin(commands.Cog):
if warns.count() >= 3:
e = discord.Embed(
title=Texts('admin').get('More than 2 warns'),
title=Texts('admin', ctx).get('More than 2 warns'),
description=f"{member.mention} "
+ Texts('admin').get('has more than 2 warns')
+ Texts('admin', ctx).get('has more than 2 warns')
)
e.add_field(
name='__Actions__',
value=':one: kick\n'
':two: ban\n'
':three: ' + Texts('admin').get('ignore')
':three: ' + Texts('admin', ctx).get('ignore')
)
choice = await ctx.send(embed=e)
@ -325,7 +326,7 @@ class Admin(commands.Cog):
)
except asyncio.TimeoutError:
return await ctx.send(
Texts('admin').get('Took too long. Aborting.')
Texts('admin', ctx).get('Took too long. Aborting.')
)
finally:
await choice.delete()
@ -338,7 +339,7 @@ class Admin(commands.Cog):
content=f"{ctx.prefix}"
f"kick "
f"{member} "
f"{Texts('admin').get('More than 2 warns')}"
f"{Texts('admin', ctx).get('More than 2 warns')}"
)
return await alt_ctx.command.invoke(alt_ctx)
@ -350,15 +351,15 @@ class Admin(commands.Cog):
content=f"{ctx.prefix}"
f"ban "
f"{member} "
f"{Texts('admin').get('More than 2 warns')}"
f"{Texts('admin', ctx).get('More than 2 warns')}"
)
return await alt_ctx.command.invoke(alt_ctx)
await self.add_warn(ctx, member, reason)
await ctx.send(
content=f"{member.mention} "
f"**{Texts('admin').get('got a warn')}**"
f"\n**{Texts('admin').get('Reason')}:** `{reason}`"
f"**{Texts('admin', ctx).get('got a warn')}**"
f"\n**{Texts('admin', ctx).get('Reason')}:** `{reason}`"
)
@_warn.command(name='remove', aliases=['revoke'])
@ -366,15 +367,15 @@ class Admin(commands.Cog):
warn = self.bot.engine.query(Warn).filter(Warn.id == warn_id).one()
self.bot.engine.delete(warn)
await ctx.send(f"{Texts('admin').get('Warn with id')} `{warn_id}`"
f" {Texts('admin').get('successfully removed')}")
await ctx.send(f"{Texts('admin', ctx).get('Warn with id')} `{warn_id}`"
f" {Texts('admin', ctx).get('successfully removed')}")
@_warn.command(name='show', aliases=['list'])
async def _warn_show(self, ctx: commands.Context, member: discord.Member):
warns_list, warns = await self.get_warn(ctx, member)
e = discord.Embed(
title=f"{warns.count()} {Texts('admin').get('last warns')}: ",
title=f"{warns.count()} {Texts('admin', ctx).get('last warns')}: ",
description=warns_list
)
@ -386,35 +387,36 @@ class Admin(commands.Cog):
warn.reason = reason
self.bot.engine.commit()
await ctx.send(f"{Texts('admin').get('Warn with id')} `{warn_id}`"
f" {Texts('admin').get('successfully edited')}")
await ctx.send(f"{Texts('admin', ctx).get('Warn with id')} `{warn_id}`"
f" {Texts('admin', ctx).get('successfully edited')}")
"""---------------------------------------------------------------------"""
@commands.command(name='language', aliases=['lang', 'langue', 'langage'])
async def _language(self, ctx: commands.Context, locale):
query = """
SELECT locale
FROM lang
WHERE key = 'available'
"""
async def _language(self, ctx: commands.Context, locale: str):
available = self.bot.engine\
.query(Lang.value)\
.filter(Lang.key == 'available')\
.one()[0]\
.split(', ')
async with self.bot.engine.begin() as con:
await ctx.trigger_typing()
available = list(await con.fetchrow(query))
if locale.lower() not in available:
await ctx.send(Texts('admin', ctx).get('Unable to find this language'))
else:
current = self.bot.engine\
.query(Lang)\
.filter(Lang.key == str(ctx.guild.id))
if str(locale) in available:
query = """
IF EXISTS(SELECT * FROM lang WHERE key = $1 )
then
UPDATE lang
SET locale = $2
WHERE key = $1
ELSE
INSERT INTO lang (key, locale)
VALUES ($1, $2)
"""
await con.fetch(query, str(ctx.guild.id), str(locale))
if current.count() > 0:
current = current.one()
current.value = locale.lower()
self.bot.engine.commit()
else:
new_row = Lang(key=str(ctx.guild.id), value=locale.lower())
self.bot.engine.add(new_row)
self.bot.engine.commit()
await ctx.send(Texts('admin', ctx).get('Language changed successfully'))
def setup(bot: TuxBot):

View file

@ -68,17 +68,17 @@ class Basics(commands.Cog):
with proc.oneshot():
mem = proc.memory_full_info()
e = discord.Embed(
title=f"{Texts('basics').get('Information about TuxBot')}",
title=f"{Texts('basics', ctx).get('Information about TuxBot')}",
color=0x89C4F9)
e.add_field(
name=f"__{Texts('basics').get('Latest changes')}__",
name=f"__{Texts('basics', ctx).get('Latest changes')}__",
value=self._latest_commits(),
inline=False)
e.add_field(
name=f"__:busts_in_silhouette: "
f"{Texts('basics').get('Development')}__",
f"{Texts('basics', ctx).get('Development')}__",
value=f"**Romain#5117:** [git](https://git.gnous.eu/Romain)\n"
f"**Outout#4039:** [git](https://git.gnous.eu/mael)\n",
inline=True
@ -92,41 +92,41 @@ class Basics(commands.Cog):
e.add_field(
name="__:gear: Usage__",
value=f"**{humanize.naturalsize(mem.rss)}** "
f"{Texts('basics').get('physical memory')}\n"
f"{Texts('basics', ctx).get('physical memory')}\n"
f"**{humanize.naturalsize(mem.vms)}** "
f"{Texts('basics').get('virtual memory')}\n",
f"{Texts('basics', ctx).get('virtual memory')}\n",
inline=True
)
e.add_field(
name=f"__{Texts('basics').get('Servers count')}__",
name=f"__{Texts('basics', ctx).get('Servers count')}__",
value=str(len(self.bot.guilds)),
inline=True
)
e.add_field(
name=f"__{Texts('basics').get('Channels count')}__",
name=f"__{Texts('basics', ctx).get('Channels count')}__",
value=str(len([_ for _ in self.bot.get_all_channels()])),
inline=True
)
e.add_field(
name=f"__{Texts('basics').get('Members count')}__",
name=f"__{Texts('basics', ctx).get('Members count')}__",
value=str(len([_ for _ in self.bot.get_all_members()])),
inline=True
)
e.add_field(
name=f"__:file_folder: {Texts('basics').get('Files')}__",
name=f"__:file_folder: {Texts('basics', ctx).get('Files')}__",
value=str(files),
inline=True
)
e.add_field(
name=f"__¶ {Texts('basics').get('Lines')}__",
name=f"__¶ {Texts('basics', ctx).get('Lines')}__",
value=str(lines),
inline=True
)
e.add_field(
name=f"__:link: {Texts('basics').get('Links')}__",
name=f"__:link: {Texts('basics', ctx).get('Links')}__",
value="[tuxbot.gnous.eu](https://tuxbot.gnous.eu/) "
"| [gnous.eu](https://gnous.eu/) "
f"| [{Texts('basics').get('Invite')}](https://discordapp.com/oauth2/authorize?client_id=301062143942590465&scope=bot&permissions=268749888)",
@ -142,7 +142,7 @@ class Basics(commands.Cog):
@commands.command(name='credits', aliases=['contributors', 'authors'])
async def _credits(self, ctx: commands.Context):
e = discord.Embed(
title=Texts('basics').get('Contributors'),
title=Texts('basics', ctx).get('Contributors'),
color=0x36393f
)

View file

@ -28,7 +28,7 @@ class Utility(commands.Cog):
ip = socket.getaddrinfo(addr, None, socket.AF_INET6)[1][4][0]
except socket.gaierror:
return await ctx.send(
Texts('utility').get('ipv6 not available'))
Texts('utility', ctx).get('ipv6 not available'))
else:
ip = socket.gethostbyname(addr)
@ -37,19 +37,19 @@ class Utility(commands.Cog):
if response.get('status') == 'success':
e = discord.Embed(
title=f"{Texts('utility').get('Information for')} "
title=f"{Texts('utility', ctx).get('Information for')} "
f"``{addr}`` *`({response.get('query')})`*",
color=0x5858d7
)
e.add_field(
name=Texts('utility').get('Belongs to :'),
name=Texts('utility', ctx).get('Belongs to :'),
value=response.get('org', 'N/A'),
inline=False
)
e.add_field(
name=Texts('utility').get('Is located at :'),
name=Texts('utility', ctx).get('Is located at :'),
value=response.get('city', 'N/A'),
inline=True
)
@ -68,7 +68,7 @@ class Utility(commands.Cog):
await ctx.send(embed=e)
else:
await ctx.send(
content=f"{Texts('utility').get('info not available')}"
content=f"{Texts('utility', ctx).get('info not available')}"
f"``{response.get('query')}``")
"""---------------------------------------------------------------------"""
@ -82,7 +82,7 @@ class Utility(commands.Cog):
async with self.bot.session.get(addr) as s:
await ctx.trigger_typing()
e = discord.Embed(
title=f"{Texts('utility').get('Headers of')} {addr}",
title=f"{Texts('utility', ctx).get('Headers of')} {addr}",
color=0xd75858
)
e.add_field(name="Status", value=s.status, inline=True)
@ -96,7 +96,7 @@ class Utility(commands.Cog):
await ctx.send(embed=e)
except aiohttp.client_exceptions.ClientConnectorError:
await ctx.send(f"{Texts('utility').get('Cannot connect to host')} "
await ctx.send(f"{Texts('utility', ctx).get('Cannot connect to host')} "
f"{addr}")
"""---------------------------------------------------------------------"""
@ -104,8 +104,8 @@ class Utility(commands.Cog):
@commands.command(name='git', aliases=['sources', 'source', 'github'])
async def _git(self, ctx):
e = discord.Embed(
title=Texts('utility').get('git repo'),
description=Texts('utility').get('git text'),
title=Texts('utility', ctx).get('git repo'),
description=Texts('utility', ctx).get('git text'),
colour=0xE9D460
)
e.set_author(

View file

@ -1,10 +1,15 @@
import gettext
import config
from .models.lang import Lang
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from discord.ext import commands
class Texts:
def __init__(self, base: str = 'base'):
self.locale = config.locale
def __init__(self, base: str = 'base', ctx: commands.Context = None):
self.locale = self.get_locale(ctx)
self.base = base
def get(self, text: str) -> str:
@ -15,3 +20,25 @@ class Texts:
def set(self, lang: str):
self.locale = lang
@staticmethod
def get_locale(ctx):
engine = create_engine(config.postgresql)
Session = sessionmaker()
Session.configure(bind=engine)
session = Session()
if ctx is not None:
current = session\
.query(Lang.value)\
.filter(Lang.key == str(ctx.guild.id))
if current.count() > 0:
return current.one()[0]
default = session\
.query(Lang.value)\
.filter(Lang.key == 'default')\
.one()[0]
return default

13
cogs/utils/models/lang.py Normal file
View file

@ -0,0 +1,13 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String
Base = declarative_base()
class Lang(Base):
__tablename__ = 'lang'
key = Column(String, primary_key=True)
value = Column(String)
def __repr__(self):
return "<Lang(key='%s', locale='%s')>" % (self.key, self.value)