[i18n] Basic Implementation (#948)

* Initial commit

* Beginning of working i18n

* Add some translation files

* Add more strings to translate

* Update and add some more translations

* Update spanish translation

* Update french translation

* Add alias translation templates

* Add bank translations

* Add economy translations

* Add general translations

* Add image translations

* Add core translations
This commit is contained in:
Will 2017-08-26 18:54:51 -04:00 committed by GitHub
parent 3d76f3a787
commit 118df46630
25 changed files with 1875 additions and 245 deletions

1
.gitignore vendored
View File

@ -103,7 +103,6 @@ coverage.xml
# Translations # Translations
*.mo *.mo
*.pot
# Django stuff: # Django stuff:
*.log *.log

View File

@ -6,8 +6,11 @@ from typing import Generator, Tuple, Iterable
from core import Config from core import Config
from core.bot import Red from core.bot import Red
from core.utils.chat_formatting import box from core.utils.chat_formatting import box
from core.i18n import CogI18n
from .alias_entry import AliasEntry from .alias_entry import AliasEntry
_ = CogI18n("Alias", __file__)
class Alias: class Alias:
""" """
@ -132,7 +135,7 @@ class Alias:
for p in prefixes: for p in prefixes:
if content.startswith(p): if content.startswith(p):
return p return p
raise ValueError("No prefix found.") raise ValueError(_("No prefix found."))
def get_extra_args_from_alias(self, message: discord.Message, prefix: str, def get_extra_args_from_alias(self, message: discord.Message, prefix: str,
alias: AliasEntry) -> str: alias: AliasEntry) -> str:
@ -228,7 +231,7 @@ class Alias:
await self.add_alias(ctx, alias_name, command) await self.add_alias(ctx, alias_name, command)
await ctx.send(("A new alias with the trigger `{}`" await ctx.send(_("A new alias with the trigger `{}`"
" has been created.").format(alias_name)) " has been created.").format(alias_name))
@global_.command(name="add") @global_.command(name="add")
@ -264,7 +267,7 @@ class Alias:
await self.add_alias(ctx, alias_name, command, global_=True) await self.add_alias(ctx, alias_name, command, global_=True)
await ctx.send(("A new global alias with the trigger `{}`" await ctx.send(_("A new global alias with the trigger `{}`"
" has been created.").format(alias_name)) " has been created.").format(alias_name))
@alias.command(name="help") @alias.command(name="help")
@ -279,7 +282,7 @@ class Alias:
new_msg.content = "{}help {}".format(ctx.prefix, base_cmd) new_msg.content = "{}help {}".format(ctx.prefix, base_cmd)
await self.bot.process_commands(new_msg) await self.bot.process_commands(new_msg)
else: else:
ctx.send("No such alias exists.") ctx.send(_("No such alias exists."))
@alias.command(name="show") @alias.command(name="show")
@commands.guild_only() @commands.guild_only()
@ -288,10 +291,10 @@ class Alias:
is_alias, alias = await self.is_alias(ctx.guild, alias_name) is_alias, alias = await self.is_alias(ctx.guild, alias_name)
if is_alias: if is_alias:
await ctx.send(("The `{}` alias will execute the" await ctx.send(_("The `{}` alias will execute the"
" command `{}`").format(alias_name, alias.command)) " command `{}`").format(alias_name, alias.command))
else: else:
await ctx.send("There is no alias with the name `{}`".format(alias_name)) await ctx.send(_("There is no alias with the name `{}`").format(alias_name))
@alias.command(name="del") @alias.command(name="del")
@commands.guild_only() @commands.guild_only()
@ -303,14 +306,14 @@ class Alias:
try: try:
next(aliases) next(aliases)
except StopIteration: except StopIteration:
await ctx.send("There are no aliases on this guild.") await ctx.send(_("There are no aliases on this guild."))
return return
if await self.delete_alias(ctx, alias_name): if await self.delete_alias(ctx, alias_name):
await ctx.send(("Alias with the name `{}` was successfully" await ctx.send(_("Alias with the name `{}` was successfully"
" deleted.").format(alias_name)) " deleted.").format(alias_name))
else: else:
await ctx.send("Alias with name `{}` was not found.".format(alias_name)) await ctx.send(_("Alias with name `{}` was not found.").format(alias_name))
@global_.command(name="del") @global_.command(name="del")
async def _del_global_alias(self, ctx: commands.Context, alias_name: str): async def _del_global_alias(self, ctx: commands.Context, alias_name: str):
@ -321,14 +324,14 @@ class Alias:
try: try:
next(aliases) next(aliases)
except StopIteration: except StopIteration:
await ctx.send("There are no aliases on this bot.") await ctx.send(_("There are no aliases on this bot."))
return return
if await self.delete_alias(ctx, alias_name, global_=True): if await self.delete_alias(ctx, alias_name, global_=True):
await ctx.send(("Alias with the name `{}` was successfully" await ctx.send(_("Alias with the name `{}` was successfully"
" deleted.").format(alias_name)) " deleted.").format(alias_name))
else: else:
await ctx.send("Alias with name `{}` was not found.".format(alias_name)) await ctx.send(_("Alias with name `{}` was not found.").format(alias_name))
@alias.command(name="list") @alias.command(name="list")
@commands.guild_only() @commands.guild_only()
@ -336,9 +339,9 @@ class Alias:
""" """
Lists the available aliases on this server. Lists the available aliases on this server.
""" """
names = ["Aliases:", ] + sorted(["+ " + a.name for a in (await self.unloaded_aliases(ctx.guild))]) names = [_("Aliases:"), ] + sorted(["+ " + a.name for a in (await self.unloaded_aliases(ctx.guild))])
if len(names) == 0: if len(names) == 0:
await ctx.send("There are no aliases on this server.") await ctx.send(_("There are no aliases on this server."))
else: else:
await ctx.send(box("\n".join(names), "diff")) await ctx.send(box("\n".join(names), "diff"))
@ -347,9 +350,9 @@ class Alias:
""" """
Lists the available global aliases on this bot. Lists the available global aliases on this bot.
""" """
names = ["Aliases:", ] + sorted(["+ " + a.name for a in await self.unloaded_global_aliases()]) names = [_("Aliases:"), ] + sorted(["+ " + a.name for a in await self.unloaded_global_aliases()])
if len(names) == 0: if len(names) == 0:
await ctx.send("There are no aliases on this server.") await ctx.send(_("There are no aliases on this server."))
else: else:
await ctx.send(box("\n".join(names), "diff")) await ctx.send(box("\n".join(names), "diff"))

View File

@ -0,0 +1,65 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2017-08-26 17:23+EDT\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: ../alias.py:138
msgid "No prefix found."
msgstr ""
#: ../alias.py:234
msgid "A new alias with the trigger `{}` has been created."
msgstr ""
#: ../alias.py:270
msgid "A new global alias with the trigger `{}` has been created."
msgstr ""
#: ../alias.py:285
msgid "No such alias exists."
msgstr ""
#: ../alias.py:294
msgid "The `{}` alias will execute the command `{}`"
msgstr ""
#: ../alias.py:297
msgid "There is no alias with the name `{}`"
msgstr ""
#: ../alias.py:309
msgid "There are no aliases on this guild."
msgstr ""
#: ../alias.py:313 ../alias.py:331
msgid "Alias with the name `{}` was successfully deleted."
msgstr ""
#: ../alias.py:316 ../alias.py:334
msgid "Alias with name `{}` was not found."
msgstr ""
#: ../alias.py:327
msgid "There are no aliases on this bot."
msgstr ""
#: ../alias.py:342 ../alias.py:353
msgid "Aliases:"
msgstr ""
#: ../alias.py:344 ../alias.py:355
msgid "There are no aliases on this server."
msgstr ""

View File

@ -2,6 +2,9 @@ from discord.ext import commands
from core import checks, bank from core import checks, bank
from core.bot import Red # Only used for type hints from core.bot import Red # Only used for type hints
from core.i18n import CogI18n
_ = CogI18n('Bank', __file__)
def check_global_setting_guildowner(): def check_global_setting_guildowner():
@ -62,22 +65,22 @@ class Bank:
cur_setting = await bank.is_global() cur_setting = await bank.is_global()
await bank.set_global(not cur_setting, ctx.author) await bank.set_global(not cur_setting, ctx.author)
word = "per-guild" if cur_setting else "global" word = _("per-guild") if cur_setting else _("global")
await ctx.send("The bank is now {}.".format(word)) await ctx.send(_("The bank is now {}.").format(word))
@bankset.command(name="bankname") @bankset.command(name="bankname")
@check_global_setting_guildowner() @check_global_setting_guildowner()
async def bankset_bankname(self, ctx: commands.Context, *, name: str): async def bankset_bankname(self, ctx: commands.Context, *, name: str):
"""Set the bank's name""" """Set the bank's name"""
await bank.set_bank_name(name, ctx.guild) await bank.set_bank_name(name, ctx.guild)
await ctx.send("Bank's name has been set to {}".format(name)) await ctx.send(_("Bank's name has been set to {}").format(name))
@bankset.command(name="creditsname") @bankset.command(name="creditsname")
@check_global_setting_guildowner() @check_global_setting_guildowner()
async def bankset_creditsname(self, ctx: commands.Context, *, name: str): async def bankset_creditsname(self, ctx: commands.Context, *, name: str):
"""Set the name for the bank's currency""" """Set the name for the bank's currency"""
await bank.set_currency_name(name, ctx.guild) await bank.set_currency_name(name, ctx.guild)
await ctx.send("Currency name has been set to {}".format(name)) await ctx.send(_("Currency name has been set to {}").format(name))
# ENDSECTION # ENDSECTION

View File

@ -0,0 +1,37 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2017-08-26 17:32+EDT\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: ../bank.py:68
msgid "global"
msgstr ""
#: ../bank.py:68
msgid "per-guild"
msgstr ""
#: ../bank.py:70
msgid "The bank is now {}."
msgstr ""
#: ../bank.py:77
msgid "Bank's name has been set to {}"
msgstr ""
#: ../bank.py:84
msgid "Currency name has been set to {}"
msgstr ""

View File

@ -11,6 +11,7 @@ from core import Config
from core.bot import Red from core.bot import Red
from core import checks from core import checks
from core.utils.chat_formatting import box from core.utils.chat_formatting import box
from core.i18n import CogI18n
from .repo_manager import RepoManager, Repo from .repo_manager import RepoManager, Repo
from .installable import Installable from .installable import Installable
@ -19,6 +20,8 @@ from .log import log
from .errors import CloningError, ExistingGitRepo from .errors import CloningError, ExistingGitRepo
from .checks import install_agreement from .checks import install_agreement
_ = CogI18n('Downloader', __file__)
class Downloader: class Downloader:
def __init__(self, bot: Red): def __init__(self, bot: Red):
@ -196,12 +199,12 @@ class Downloader:
branch=branch branch=branch
) )
except ExistingGitRepo: except ExistingGitRepo:
await ctx.send("That git repo has already been added under another name.") await ctx.send(_("That git repo has already been added under another name."))
except CloningError: except CloningError:
await ctx.send("Something went wrong during the cloning process.") await ctx.send(_("Something went wrong during the cloning process."))
log.exception("Something went wrong during the cloning process.") log.exception(_("Something went wrong during the cloning process."))
else: else:
await ctx.send("Repo `{}` successfully added.".format(name)) await ctx.send(_("Repo `{}` successfully added.").format(name))
@repo.command(name="delete") @repo.command(name="delete")
async def _repo_del(self, ctx, repo_name: Repo): async def _repo_del(self, ctx, repo_name: Repo):
@ -210,7 +213,7 @@ class Downloader:
""" """
await self._repo_manager.delete_repo(repo_name.name) await self._repo_manager.delete_repo(repo_name.name)
await ctx.send("The repo `{}` has been deleted successfully.".format(repo_name.name)) await ctx.send(_("The repo `{}` has been deleted successfully.").format(repo_name.name))
@repo.command(name="list") @repo.command(name="list")
async def _repo_list(self, ctx): async def _repo_list(self, ctx):
@ -218,7 +221,7 @@ class Downloader:
Lists all installed repos. Lists all installed repos.
""" """
repos = self._repo_manager.get_all_repo_names() repos = self._repo_manager.get_all_repo_names()
joined = "Installed Repos:\n" + "\n".join(["+ " + r for r in repos]) joined = _("Installed Repos:\n") + "\n".join(["+ " + r for r in repos])
await ctx.send(box(joined, lang="diff")) await ctx.send(box(joined, lang="diff"))
@ -238,13 +241,13 @@ class Downloader:
""" """
cog = discord.utils.get(repo_name.available_cogs, name=cog_name) cog = discord.utils.get(repo_name.available_cogs, name=cog_name)
if cog is None: if cog is None:
await ctx.send("Error, there is no cog by the name of" await ctx.send(_("Error, there is no cog by the name of"
" `{}` in the `{}` repo.".format(cog_name, repo_name.name)) " `{}` in the `{}` repo.").format(cog_name, repo_name.name))
return return
if not await repo_name.install_requirements(cog, self.LIB_PATH): if not await repo_name.install_requirements(cog, self.LIB_PATH):
await ctx.send("Failed to install the required libraries for" await ctx.send(_("Failed to install the required libraries for"
" `{}`: `{}`".format(cog.name, cog.requirements)) " `{}`: `{}`").format(cog.name, cog.requirements))
return return
await repo_name.install_cog(cog, await self.cog_install_path()) await repo_name.install_cog(cog, await self.cog_install_path())
@ -253,7 +256,7 @@ class Downloader:
await repo_name.install_libraries(self.SHAREDLIB_PATH) await repo_name.install_libraries(self.SHAREDLIB_PATH)
await ctx.send("`{}` cog successfully installed.".format(cog_name)) await ctx.send(_("`{}` cog successfully installed.").format(cog_name))
@cog.command(name="uninstall") @cog.command(name="uninstall")
async def _cog_uninstall(self, ctx, cog_name: InstalledCog): async def _cog_uninstall(self, ctx, cog_name: InstalledCog):
@ -269,11 +272,11 @@ class Downloader:
await self._delete_cog(poss_installed_path) await self._delete_cog(poss_installed_path)
# noinspection PyTypeChecker # noinspection PyTypeChecker
await self._remove_from_installed(cog_name) await self._remove_from_installed(cog_name)
await ctx.send("`{}` was successfully removed.".format(real_name)) await ctx.send(_("`{}` was successfully removed.").format(real_name))
else: else:
await ctx.send("That cog was installed but can no longer" await ctx.send(_("That cog was installed but can no longer"
" be located. You may need to remove it's" " be located. You may need to remove it's"
" files manually if it is still usable.") " files manually if it is still usable."))
@cog.command(name="update") @cog.command(name="update")
async def _cog_update(self, ctx, cog_name: InstalledCog=None): async def _cog_update(self, ctx, cog_name: InstalledCog=None):
@ -295,7 +298,7 @@ class Downloader:
# noinspection PyTypeChecker # noinspection PyTypeChecker
await self._reinstall_libraries(installed_and_updated) await self._reinstall_libraries(installed_and_updated)
await ctx.send("Cog update completed successfully.") await ctx.send(_("Cog update completed successfully."))
@cog.command(name="list") @cog.command(name="list")
async def _cog_list(self, ctx, repo_name: Repo): async def _cog_list(self, ctx, repo_name: Repo):
@ -303,7 +306,7 @@ class Downloader:
Lists all available cogs from a single repo. Lists all available cogs from a single repo.
""" """
cogs = repo_name.available_cogs cogs = repo_name.available_cogs
cogs = "Available Cogs:\n" + "\n".join( cogs = _("Available Cogs:\n") + "\n".join(
["+ {}: {}".format(c.name, c.short or "") for c in cogs]) ["+ {}: {}".format(c.name, c.short or "") for c in cogs])
await ctx.send(box(cogs, lang="diff")) await ctx.send(box(cogs, lang="diff"))
@ -315,12 +318,12 @@ class Downloader:
""" """
cog = discord.utils.get(repo_name.available_cogs, name=cog_name) cog = discord.utils.get(repo_name.available_cogs, name=cog_name)
if cog is None: if cog is None:
await ctx.send("There is no cog `{}` in the repo `{}`".format( await ctx.send(_("There is no cog `{}` in the repo `{}`").format(
cog_name, repo_name.name cog_name, repo_name.name
)) ))
return return
msg = "Information on {}:\n{}".format(cog.name, cog.description or "") msg = _("Information on {}:\n{}").format(cog.name, cog.description or "")
await ctx.send(box(msg)) await ctx.send(box(msg))
async def is_installed(self, cog_name: str) -> (bool, Union[Installable, None]): async def is_installed(self, cog_name: str) -> (bool, Union[Installable, None]):
@ -344,7 +347,7 @@ class Downloader:
:return: str :return: str
""" """
if isinstance(cog_installable, Installable): if isinstance(cog_installable, Installable):
made_by = ", ".join(cog_installable.author) or "Missing from info.json" made_by = ", ".join(cog_installable.author) or _("Missing from info.json")
repo = self._repo_manager.get_repo(cog_installable.repo_name) repo = self._repo_manager.get_repo(cog_installable.repo_name)
repo_url = repo.url repo_url = repo.url
cog_name = cog_installable.name cog_name = cog_installable.name
@ -353,7 +356,7 @@ class Downloader:
repo_url = "https://github.com/Twentysix26/Red-DiscordBot" repo_url = "https://github.com/Twentysix26/Red-DiscordBot"
cog_name = cog_installable.__class__.__name__ cog_name = cog_installable.__class__.__name__
msg = "Command: {}\nMade by: {}\nRepo: {}\nCog name: {}" msg = _("Command: {}\nMade by: {}\nRepo: {}\nCog name: {}")
return msg.format(command_name, made_by, repo_url, cog_name) return msg.format(command_name, made_by, repo_url, cog_name)
@ -377,7 +380,7 @@ class Downloader:
command = ctx.bot.all_commands.get(command_name) command = ctx.bot.all_commands.get(command_name)
if command is None: if command is None:
await ctx.send("That command doesn't seem to exist.") await ctx.send(_("That command doesn't seem to exist."))
return return
# Check if in installed cogs # Check if in installed cogs

View File

@ -0,0 +1,97 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2017-08-26 16:31+EDT\n"
"PO-Revision-Date: 2017-08-26 17:00-0400\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Last-Translator: tekulvw\n"
"Language-Team: \n"
"Language: de\n"
"X-Generator: Poedit 1.8.7.1\n"
#: ../downloader.py:202
msgid "That git repo has already been added under another name."
msgstr "Diese git repo wurder bereist unter einem anderem Namen hinzugefügt."
#: ../downloader.py:204 ../downloader.py:205
msgid "Something went wrong during the cloning process."
msgstr "Etwas ist beim klonen schief gelaufen."
#: ../downloader.py:207
msgid "Repo `{}` successfully added."
msgstr "Repo `{}` erfolgreich hinzugefügt."
#: ../downloader.py:216
msgid "The repo `{}` has been deleted successfully."
msgstr "Die Repo `{}` wurde erfolgreich gelöscht."
#: ../downloader.py:224
msgid "Installed Repos:\n"
msgstr "Installierte Repos:\n"
#: ../downloader.py:244
msgid "Error, there is no cog by the name of `{}` in the `{}` repo."
msgstr "Fehler: kein Cog mit dem Namen `{}` in der Repo `{}`."
#: ../downloader.py:249
msgid "Failed to install the required libraries for `{}`: `{}`"
msgstr "Installation erforderliche Abhängigkeiten für`{}` fehlgeschlagen: `{}`"
#: ../downloader.py:259
msgid "`{}` cog successfully installed."
msgstr "`{}` Cog erfolgreich installiert."
#: ../downloader.py:275
msgid "`{}` was successfully removed."
msgstr "`{}` erfolgreich entfernt."
#: ../downloader.py:277
msgid "That cog was installed but can no longer be located. You may need to remove it's files manually if it is still usable."
msgstr "Diese Cog ist installiert konnte aber nicht gefunden werden. Wenn es noch benutzbar ist kann es sein das du die Dateien manuell löschen musst."
#: ../downloader.py:301
msgid "Cog update completed successfully."
msgstr "Cog Update erfolgreich."
#: ../downloader.py:309
msgid "Available Cogs:\n"
msgstr "Vorhandene Cogs:\n"
#: ../downloader.py:321
msgid "There is no cog `{}` in the repo `{}`"
msgstr "Kein Cog namens `{}` in der Repo `{}"
#: ../downloader.py:326
msgid ""
"Information on {}:\n"
"{}"
msgstr ""
"Information zu {}:\n"
"{}"
#: ../downloader.py:350
msgid "Missing from info.json"
msgstr "Nicht in info.json"
#: ../downloader.py:359
msgid ""
"Command: {}\n"
"Made by: {}\n"
"Repo: {}\n"
"Cog name: {}"
msgstr ""
"Befehl: {}\n"
"Von: {}\n"
"Repo: {}\n"
"Cog Name: {}"
#: ../downloader.py:383
msgid "That command doesn't seem to exist."
msgstr "Dieser Befehl existiert nicht."

View File

@ -0,0 +1,97 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2017-08-26 16:31+EDT\n"
"PO-Revision-Date: 2017-08-26 17:12-0400\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Last-Translator: tekulvw\n"
"Language-Team: \n"
"Language: es\n"
"X-Generator: Poedit 1.8.7.1\n"
#: ../downloader.py:202
msgid "That git repo has already been added under another name."
msgstr "Ese repositorio ya ha sido agregado con otro nombre."
#: ../downloader.py:204 ../downloader.py:205
msgid "Something went wrong during the cloning process."
msgstr "Algo malo ha ocurrido durante la clonación."
#: ../downloader.py:207
msgid "Repo `{}` successfully added."
msgstr "Repositorio `{}` agregado exitósamente."
#: ../downloader.py:216
msgid "The repo `{}` has been deleted successfully."
msgstr "Repositorio `{}` eliminado exitósamente."
#: ../downloader.py:224
msgid "Installed Repos:\n"
msgstr "Repositorios instalados:\n"
#: ../downloader.py:244
msgid "Error, there is no cog by the name of `{}` in the `{}` repo."
msgstr "Error: No existe un cog llamado `{}` en el repositorio `{}`."
#: ../downloader.py:249
msgid "Failed to install the required libraries for `{}`: `{}`"
msgstr "Error instalando las librerías requeridas para `{}`: `{}`"
#: ../downloader.py:259
msgid "`{}` cog successfully installed."
msgstr "`{}` instalado exitósamente."
#: ../downloader.py:275
msgid "`{}` was successfully removed."
msgstr "`{}` eliminado exitósamente."
#: ../downloader.py:277
msgid "That cog was installed but can no longer be located. You may need to remove it's files manually if it is still usable."
msgstr "El cog fue instalado pero ya no se puede localizar. Puede ser necesario eliminar sus archivos manualmente si aun es utilizable."
#: ../downloader.py:301
msgid "Cog update completed successfully."
msgstr "Cog actualizado exitósamente."
#: ../downloader.py:309
msgid "Available Cogs:\n"
msgstr "Cogs disponibles:\n"
#: ../downloader.py:321
msgid "There is no cog `{}` in the repo `{}`"
msgstr "No existe un cog `{}` en el repositorio `{}`"
#: ../downloader.py:326
msgid ""
"Information on {}:\n"
"{}"
msgstr ""
"Información sobre {}:\n"
"{}"
#: ../downloader.py:350
msgid "Missing from info.json"
msgstr "Ausente de info.json"
#: ../downloader.py:359
msgid ""
"Command: {}\n"
"Made by: {}\n"
"Repo: {}\n"
"Cog name: {}"
msgstr ""
"Comando: {}\n"
"Creado por: {}\n"
"Repositorio: {}\n"
"Nombre del cog: {}"
#: ../downloader.py:383
msgid "That command doesn't seem to exist."
msgstr "Ese comando no parece existir."

View File

@ -0,0 +1,97 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2017-08-26 16:31+EDT\n"
"PO-Revision-Date: 2017-08-26 23:14+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fr\n"
"X-Generator: Poedit 2.0.1\n"
#: ../downloader.py:202
msgid "That git repo has already been added under another name."
msgstr "Ce repo git a déjà été ajouté sous un autre nom"
#: ../downloader.py:204 ../downloader.py:205
msgid "Something went wrong during the cloning process."
msgstr "Quelque chose s'est mal passé pendant l'installation."
#: ../downloader.py:207
msgid "Repo `{}` successfully added."
msgstr "Le repo `{}` a été ajouté avec succès"
#: ../downloader.py:216
msgid "The repo `{}` has been deleted successfully."
msgstr "Le repo `{}` a été supprimé avec succès"
#: ../downloader.py:224
msgid "Installed Repos:\n"
msgstr "Repos installés:\n"
#: ../downloader.py:244
msgid "Error, there is no cog by the name of `{}` in the `{}` repo."
msgstr "Erreur, il n'y a pas de cog du nom de `{}` dans le repo `{}`."
#: ../downloader.py:249
msgid "Failed to install the required libraries for `{}`: `{}`"
msgstr "Échec lors de l'installation des bibliothèques de `{}`: `{}`"
#: ../downloader.py:259
msgid "`{}` cog successfully installed."
msgstr "Le cog `{}` a été ajouté avec succès"
#: ../downloader.py:275
msgid "`{}` was successfully removed."
msgstr "Le cog `{}` a été retiré avec succès"
#: ../downloader.py:277
msgid "That cog was installed but can no longer be located. You may need to remove it's files manually if it is still usable."
msgstr "Ce cog a été installé mais ne peut plus être trouvé. Vous devez retirer manuellement son dossier si il est encore utilisable."
#: ../downloader.py:301
msgid "Cog update completed successfully."
msgstr "Mise à jour du cog effectuée avec succès"
#: ../downloader.py:309
msgid "Available Cogs:\n"
msgstr "Cogs disponibles:\n"
#: ../downloader.py:321
msgid "There is no cog `{}` in the repo `{}`"
msgstr "Il n'y a pas de cog `{}` dans le repo `{}`"
#: ../downloader.py:326
msgid ""
"Information on {}:\n"
"{}"
msgstr ""
"Informations sur {}:\n"
"{}"
#: ../downloader.py:350
msgid "Missing from info.json"
msgstr "Informations manquantes de info.json"
#: ../downloader.py:359
msgid ""
"Command: {}\n"
"Made by: {}\n"
"Repo: {}\n"
"Cog name: {}"
msgstr ""
"Commande: {]\n"
"Créé par: {}\n"
"Repo: {}\n"
"Nom du cog: {}"
#: ../downloader.py:383
msgid "That command doesn't seem to exist."
msgstr "Cette commande ne semble pas exister"

View File

@ -0,0 +1,93 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2017-08-26 17:05+EDT\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: ../downloader.py:202
msgid "That git repo has already been added under another name."
msgstr ""
#: ../downloader.py:204 ../downloader.py:205
msgid "Something went wrong during the cloning process."
msgstr ""
#: ../downloader.py:207
msgid "Repo `{}` successfully added."
msgstr ""
#: ../downloader.py:216
msgid "The repo `{}` has been deleted successfully."
msgstr ""
#: ../downloader.py:224
msgid ""
"Installed Repos:\n"
msgstr ""
#: ../downloader.py:244
msgid "Error, there is no cog by the name of `{}` in the `{}` repo."
msgstr ""
#: ../downloader.py:249
msgid "Failed to install the required libraries for `{}`: `{}`"
msgstr ""
#: ../downloader.py:259
msgid "`{}` cog successfully installed."
msgstr ""
#: ../downloader.py:275
msgid "`{}` was successfully removed."
msgstr ""
#: ../downloader.py:277
msgid "That cog was installed but can no longer be located. You may need to remove it's files manually if it is still usable."
msgstr ""
#: ../downloader.py:301
msgid "Cog update completed successfully."
msgstr ""
#: ../downloader.py:309
msgid ""
"Available Cogs:\n"
msgstr ""
#: ../downloader.py:321
msgid "There is no cog `{}` in the repo `{}`"
msgstr ""
#: ../downloader.py:326
msgid ""
"Information on {}:\n"
"{}"
msgstr ""
#: ../downloader.py:350
msgid "Missing from info.json"
msgstr ""
#: ../downloader.py:359
msgid ""
"Command: {}\n"
"Made by: {}\n"
"Repo: {}\n"
"Cog name: {}"
msgstr ""
#: ../downloader.py:383
msgid "That command doesn't seem to exist."
msgstr ""

View File

@ -0,0 +1,93 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2017-08-26 16:24+EDT\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: ../downloader.py:202
msgid "That git repo has already been added under another name."
msgstr ""
#: ../downloader.py:204 ../downloader.py:205
msgid "Something went wrong during the cloning process."
msgstr ""
#: ../downloader.py:207
msgid "Repo `{}` successfully added."
msgstr ""
#: ../downloader.py:216
msgid "The repo `{}` has been deleted successfully."
msgstr ""
#: ../downloader.py:224
msgid ""
"Installed Repos:\n"
msgstr ""
#: ../downloader.py:244
msgid "Error, there is no cog by the name of `{}` in the `{}` repo."
msgstr ""
#: ../downloader.py:249
msgid "Failed to install the required libraries for `{}`: `{}`"
msgstr ""
#: ../downloader.py:259
msgid "`{}` cog successfully installed."
msgstr ""
#: ../downloader.py:275
msgid "`{}` was successfully removed."
msgstr ""
#: ../downloader.py:277
msgid "That cog was installed but can no longer be located. You may need to remove it's files manually if it is still usable."
msgstr ""
#: ../downloader.py:301
msgid "Cog update completed successfully."
msgstr ""
#: ../downloader.py:309
msgid ""
"Available Cogs:\n"
msgstr ""
#: ../downloader.py:321
msgid "There is no cog `{}` in the repo `{}`"
msgstr ""
#: ../downloader.py:326
msgid ""
"Information on {}:\n"
"{}"
msgstr ""
#: ../downloader.py:350
msgid "Missing from info.json"
msgstr ""
#: ../downloader.py:359
msgid ""
"Command: {}\n"
"Made by: {}\n"
"Repo: {}\n"
"Cog name: {}"
msgstr ""
#: ../downloader.py:383
msgid "That command doesn't seem to exist."
msgstr ""

View File

@ -0,0 +1,94 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2017-08-26 16:35-0400\n"
"PO-Revision-Date: 2017-08-26 16:42-0400\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"X-Generator: Poedit 1.8.7.1\n"
"Last-Translator: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Language: nl\n"
#: ../downloader.py:202
msgid "That git repo has already been added under another name."
msgstr ""
#: ../downloader.py:204 ../downloader.py:205
msgid "Something went wrong during the cloning process."
msgstr ""
#: ../downloader.py:207
msgid "Repo `{}` successfully added."
msgstr ""
#: ../downloader.py:216
msgid "The repo `{}` has been deleted successfully."
msgstr ""
#: ../downloader.py:224
msgid "Installed Repos:\n"
msgstr ""
#: ../downloader.py:244
msgid "Error, there is no cog by the name of `{}` in the `{}` repo."
msgstr ""
#: ../downloader.py:249
msgid "Failed to install the required libraries for `{}`: `{}`"
msgstr ""
#: ../downloader.py:259
msgid "`{}` cog successfully installed."
msgstr ""
#: ../downloader.py:275
msgid "`{}` was successfully removed."
msgstr ""
#: ../downloader.py:277
msgid ""
"That cog was installed but can no longer be located. You may need to remove "
"it's files manually if it is still usable."
msgstr ""
#: ../downloader.py:301
msgid "Cog update completed successfully."
msgstr ""
#: ../downloader.py:309
msgid "Available Cogs:\n"
msgstr ""
#: ../downloader.py:321
msgid "There is no cog `{}` in the repo `{}`"
msgstr ""
#: ../downloader.py:326
msgid ""
"Information on {}:\n"
"{}"
msgstr ""
#: ../downloader.py:350
msgid "Missing from info.json"
msgstr ""
#: ../downloader.py:359
msgid ""
"Command: {}\n"
"Made by: {}\n"
"Repo: {}\n"
"Cog name: {}"
msgstr ""
#: ../downloader.py:383
msgid "That command doesn't seem to exist."
msgstr ""

View File

@ -447,7 +447,7 @@ class RepoManager:
self._repos = {} self._repos = {}
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
loop.run_until_complete(self._load_repos(set=True)) # str_name: Repo loop.create_task(self._load_repos(set=True)) # str_name: Repo
@property @property
def repos_folder(self) -> Path: def repos_folder(self) -> Path:

View File

@ -10,6 +10,9 @@ from core import checks, Config, bank
from core.utils.chat_formatting import pagify, box from core.utils.chat_formatting import pagify, box
from core.bot import Red from core.bot import Red
from cogs.bank import check_global_setting_guildowner, check_global_setting_admin from cogs.bank import check_global_setting_guildowner, check_global_setting_admin
from core.i18n import CogI18n
_ = CogI18n("Economy", __file__)
logger = logging.getLogger("red.economy") logger = logging.getLogger("red.economy")
@ -32,42 +35,42 @@ class SMReel(Enum):
PAYOUTS = { PAYOUTS = {
(SMReel.two, SMReel.two, SMReel.six): { (SMReel.two, SMReel.two, SMReel.six): {
"payout": lambda x: x * 2500 + x, "payout": lambda x: x * 2500 + x,
"phrase": "JACKPOT! 226! Your bid has been multiplied * 2500!" "phrase": _("JACKPOT! 226! Your bid has been multiplied * 2500!")
}, },
(SMReel.flc, SMReel.flc, SMReel.flc): { (SMReel.flc, SMReel.flc, SMReel.flc): {
"payout": lambda x: x + 1000, "payout": lambda x: x + 1000,
"phrase": "4LC! +1000!" "phrase": _("4LC! +1000!")
}, },
(SMReel.cherries, SMReel.cherries, SMReel.cherries): { (SMReel.cherries, SMReel.cherries, SMReel.cherries): {
"payout": lambda x: x + 800, "payout": lambda x: x + 800,
"phrase": "Three cherries! +800!" "phrase": _("Three cherries! +800!")
}, },
(SMReel.two, SMReel.six): { (SMReel.two, SMReel.six): {
"payout": lambda x: x * 4 + x, "payout": lambda x: x * 4 + x,
"phrase": "2 6! Your bid has been multiplied * 4!" "phrase": _("2 6! Your bid has been multiplied * 4!")
}, },
(SMReel.cherries, SMReel.cherries): { (SMReel.cherries, SMReel.cherries): {
"payout": lambda x: x * 3 + x, "payout": lambda x: x * 3 + x,
"phrase": "Two cherries! Your bid has been multiplied * 3!" "phrase": _("Two cherries! Your bid has been multiplied * 3!")
}, },
"3 symbols": { "3 symbols": {
"payout": lambda x: x + 500, "payout": lambda x: x + 500,
"phrase": "Three symbols! +500!" "phrase": _("Three symbols! +500!")
}, },
"2 symbols": { "2 symbols": {
"payout": lambda x: x * 2 + x, "payout": lambda x: x * 2 + x,
"phrase": "Two consecutive symbols! Your bid has been multiplied * 2!" "phrase": _("Two consecutive symbols! Your bid has been multiplied * 2!")
}, },
} }
SLOT_PAYOUTS_MSG = ("Slot machine payouts:\n" SLOT_PAYOUTS_MSG = _("Slot machine payouts:\n"
"{two.value} {two.value} {six.value} Bet * 2500\n" "{two.value} {two.value} {six.value} Bet * 2500\n"
"{flc.value} {flc.value} {flc.value} +1000\n" "{flc.value} {flc.value} {flc.value} +1000\n"
"{cherries.value} {cherries.value} {cherries.value} +800\n" "{cherries.value} {cherries.value} {cherries.value} +800\n"
"{two.value} {six.value} Bet * 4\n" "{two.value} {six.value} Bet * 4\n"
"{cherries.value} {cherries.value} Bet * 3\n\n" "{cherries.value} {cherries.value} Bet * 3\n\n"
"Three symbols: +500\n" "Three symbols: +500\n"
"Two symbols: Bet * 2".format(**SMReel.__dict__)) "Two symbols: Bet * 2").format(**SMReel.__dict__)
def guild_only_check(): def guild_only_check():
@ -149,7 +152,7 @@ class Economy:
bal = await bank.get_balance(user) bal = await bank.get_balance(user)
currency = await bank.get_currency_name(ctx.guild) currency = await bank.get_currency_name(ctx.guild)
await ctx.send("{}'s balance is {} {}".format( await ctx.send(_("{}'s balance is {} {}").format(
user.display_name, bal, currency)) user.display_name, bal, currency))
@_bank.command() @_bank.command()
@ -163,7 +166,7 @@ class Economy:
except ValueError as e: except ValueError as e:
await ctx.send(str(e)) await ctx.send(str(e))
await ctx.send("{} transferred {} {} to {}".format( await ctx.send(_("{} transferred {} {} to {}").format(
from_.display_name, amount, currency, to.display_name from_.display_name, amount, currency, to.display_name
)) ))
@ -183,17 +186,17 @@ class Economy:
if creds.operation == "deposit": if creds.operation == "deposit":
await bank.deposit_credits(to, creds.sum) await bank.deposit_credits(to, creds.sum)
await ctx.send("{} added {} {} to {}'s account.".format( await ctx.send(_("{} added {} {} to {}'s account.").format(
author.display_name, creds.sum, currency, to.display_name author.display_name, creds.sum, currency, to.display_name
)) ))
elif creds.operation == "withdraw": elif creds.operation == "withdraw":
await bank.withdraw_credits(to, creds.sum) await bank.withdraw_credits(to, creds.sum)
await ctx.send("{} removed {} {} from {}'s account.".format( await ctx.send(_("{} removed {} {} from {}'s account.").format(
author.display_name, creds.sum, currency, to.display_name author.display_name, creds.sum, currency, to.display_name
)) ))
else: else:
await bank.set_balance(to, creds.sum) await bank.set_balance(to, creds.sum)
await ctx.send("{} set {}'s account to {} {}.".format( await ctx.send(_("{} set {}'s account to {} {}.").format(
author.display_name, to.display_name, creds.sum, currency author.display_name, to.display_name, creds.sum, currency
)) ))
@ -204,8 +207,8 @@ class Economy:
"""Deletes all guild's bank accounts""" """Deletes all guild's bank accounts"""
if confirmation is False: if confirmation is False:
await ctx.send( await ctx.send(
"This will delete all bank accounts for {}.\nIf you're sure, type " _("This will delete all bank accounts for {}.\nIf you're sure, type "
"{}bank reset yes".format( "{}bank reset yes").format(
self.bot.user.name if await bank.is_global() else "this guild", self.bot.user.name if await bank.is_global() else "this guild",
ctx.prefix ctx.prefix
) )
@ -221,8 +224,8 @@ class Economy:
user = ctx.guild.owner user = ctx.guild.owner
success = await bank.wipe_bank(user) success = await bank.wipe_bank(user)
if success: if success:
await ctx.send("All bank accounts of this guild have been " await ctx.send(_("All bank accounts of this guild have been "
"deleted.") "deleted."))
@commands.command() @commands.command()
@guild_only_check() @guild_only_check()
@ -240,8 +243,8 @@ class Economy:
next_payday = cur_time + await self.config.PAYDAY_TIME() next_payday = cur_time + await self.config.PAYDAY_TIME()
await self.config.user(author).next_payday.set(next_payday) await self.config.user(author).next_payday.set(next_payday)
await ctx.send( await ctx.send(
"{} Here, take some {}. Enjoy! (+{}" _("{} Here, take some {}. Enjoy! (+{}"
" {}!)".format( " {}!)").format(
author.mention, credits_name, author.mention, credits_name,
str(await self.config.PAYDAY_CREDITS()), str(await self.config.PAYDAY_CREDITS()),
credits_name credits_name
@ -250,8 +253,8 @@ class Economy:
else: else:
dtime = self.display_time(next_payday - cur_time) dtime = self.display_time(next_payday - cur_time)
await ctx.send( await ctx.send(
"{} Too soon. For your next payday you have to" _("{} Too soon. For your next payday you have to"
" wait {}.".format(author.mention, dtime) " wait {}.").format(author.mention, dtime)
) )
else: else:
next_payday = await self.config.member(author).next_payday() next_payday = await self.config.member(author).next_payday()
@ -260,16 +263,16 @@ class Economy:
next_payday = cur_time + await self.config.guild(guild).PAYDAY_TIME() next_payday = cur_time + await self.config.guild(guild).PAYDAY_TIME()
await self.config.member(author).next_payday.set(next_payday) await self.config.member(author).next_payday.set(next_payday)
await ctx.send( await ctx.send(
"{} Here, take some {}. Enjoy! (+{}" _("{} Here, take some {}. Enjoy! (+{}"
" {}!)".format( " {}!)").format(
author.mention, credits_name, author.mention, credits_name,
str(await self.config.guild(guild).PAYDAY_CREDITS()), str(await self.config.guild(guild).PAYDAY_CREDITS()),
credits_name)) credits_name))
else: else:
dtime = self.display_time(next_payday - cur_time) dtime = self.display_time(next_payday - cur_time)
await ctx.send( await ctx.send(
"{} Too soon. For your next payday you have to" _("{} Too soon. For your next payday you have to"
" wait {}.".format(author.mention, dtime)) " wait {}.").format(author.mention, dtime))
@commands.command() @commands.command()
@guild_only_check() @guild_only_check()
@ -305,7 +308,7 @@ class Economy:
for page in pagify(highscore, shorten_by=12): for page in pagify(highscore, shorten_by=12):
await ctx.send(box(page, lang="py")) await ctx.send(box(page, lang="py"))
else: else:
await ctx.send("There are no accounts in the bank.") await ctx.send(_("There are no accounts in the bank."))
@commands.command() @commands.command()
@guild_only_check() @guild_only_check()
@ -331,13 +334,13 @@ class Economy:
now = calendar.timegm(ctx.message.created_at.utctimetuple()) now = calendar.timegm(ctx.message.created_at.utctimetuple())
if (now - last_slot) < slot_time: if (now - last_slot) < slot_time:
await ctx.send("You're on cooldown, try again in a bit.") await ctx.send(_("You're on cooldown, try again in a bit."))
return return
if not valid_bid: if not valid_bid:
await ctx.send("That's an invalid bid amount, sorry :/") await ctx.send(_("That's an invalid bid amount, sorry :/"))
return return
if not await bank.can_spend(author, bid): if not await bank.can_spend(author, bid):
await ctx.send("You ain't got enough money, friend.") await ctx.send(_("You ain't got enough money, friend."))
return return
if await bank.is_global(): if await bank.is_global():
await self.config.user(author).last_slot.set(now) await self.config.user(author).last_slot.set(now)
@ -383,15 +386,15 @@ class Economy:
pay = payout["payout"](bid) pay = payout["payout"](bid)
now = then - bid + pay now = then - bid + pay
await bank.set_balance(author, now) await bank.set_balance(author, now)
await channel.send("{}\n{} {}\n\nYour bid: {}\n{}{}!" await channel.send(_("{}\n{} {}\n\nYour bid: {}\n{}{}!"
"".format(slot, author.mention, "").format(slot, author.mention,
payout["phrase"], bid, then, now)) payout["phrase"], bid, then, now))
else: else:
then = await bank.get_balance(author) then = await bank.get_balance(author)
await bank.withdraw_credits(author, bid) await bank.withdraw_credits(author, bid)
now = then - bid now = then - bid
await channel.send("{}\n{} Nothing!\nYour bid: {}\n{}{}!" await channel.send(_("{}\n{} Nothing!\nYour bid: {}\n{}{}!"
"".format(slot, author.mention, bid, then, now)) "").format(slot, author.mention, bid, then, now))
@commands.group() @commands.group()
@guild_only_check() @guild_only_check()
@ -415,17 +418,17 @@ class Economy:
payday_amount = await self.config.guild(guild).PAYDAY_CREDITS() payday_amount = await self.config.guild(guild).PAYDAY_CREDITS()
register_amount = await bank.get_default_balance(guild) register_amount = await bank.get_default_balance(guild)
msg = box( msg = box(
"Minimum slot bid: {}\n" _("Minimum slot bid: {}\n"
"Maximum slot bid: {}\n" "Maximum slot bid: {}\n"
"Slot cooldown: {}\n" "Slot cooldown: {}\n"
"Payday amount: {}\n" "Payday amount: {}\n"
"Payday cooldown: {}\n" "Payday cooldown: {}\n"
"Amount given at account registration: {}" "Amount given at account registration: {}"
"".format( "").format(
slot_min, slot_max, slot_time, slot_min, slot_max, slot_time,
payday_amount, payday_time, register_amount payday_amount, payday_time, register_amount
), ),
"Current Economy settings:" _("Current Economy settings:")
) )
await ctx.send(msg) await ctx.send(msg)
@ -433,7 +436,7 @@ class Economy:
async def slotmin(self, ctx: commands.Context, bid: int): async def slotmin(self, ctx: commands.Context, bid: int):
"""Minimum slot machine bid""" """Minimum slot machine bid"""
if bid < 1: if bid < 1:
await ctx.send('Invalid min bid amount.') await ctx.send(_('Invalid min bid amount.'))
return return
guild = ctx.guild guild = ctx.guild
if await bank.is_global(): if await bank.is_global():
@ -441,15 +444,15 @@ class Economy:
else: else:
await self.config.guild(guild).SLOT_MIN.set(bid) await self.config.guild(guild).SLOT_MIN.set(bid)
credits_name = await bank.get_currency_name(guild) credits_name = await bank.get_currency_name(guild)
await ctx.send("Minimum bid is now {} {}.".format(bid, credits_name)) await ctx.send(_("Minimum bid is now {} {}.").format(bid, credits_name))
@economyset.command() @economyset.command()
async def slotmax(self, ctx: commands.Context, bid: int): async def slotmax(self, ctx: commands.Context, bid: int):
"""Maximum slot machine bid""" """Maximum slot machine bid"""
slot_min = await self.config.SLOT_MIN() slot_min = await self.config.SLOT_MIN()
if bid < 1 or bid < slot_min: if bid < 1 or bid < slot_min:
await ctx.send('Invalid slotmax bid amount. Must be greater' await ctx.send(_('Invalid slotmax bid amount. Must be greater'
' than slotmin.') ' than slotmin.'))
return return
guild = ctx.guild guild = ctx.guild
credits_name = await bank.get_currency_name(guild) credits_name = await bank.get_currency_name(guild)
@ -457,7 +460,7 @@ class Economy:
await self.config.SLOT_MAX.set(bid) await self.config.SLOT_MAX.set(bid)
else: else:
await self.config.guild(guild).SLOT_MAX.set(bid) await self.config.guild(guild).SLOT_MAX.set(bid)
await ctx.send("Maximum bid is now {} {}.".format(bid, credits_name)) await ctx.send(_("Maximum bid is now {} {}.").format(bid, credits_name))
@economyset.command() @economyset.command()
async def slottime(self, ctx: commands.Context, seconds: int): async def slottime(self, ctx: commands.Context, seconds: int):
@ -467,7 +470,7 @@ class Economy:
await self.config.SLOT_TIME.set(seconds) await self.config.SLOT_TIME.set(seconds)
else: else:
await self.config.guild(guild).SLOT_TIME.set(seconds) await self.config.guild(guild).SLOT_TIME.set(seconds)
await ctx.send("Cooldown is now {} seconds.".format(seconds)) await ctx.send(_("Cooldown is now {} seconds.").format(seconds))
@economyset.command() @economyset.command()
async def paydaytime(self, ctx: commands.Context, seconds: int): async def paydaytime(self, ctx: commands.Context, seconds: int):
@ -477,8 +480,8 @@ class Economy:
await self.config.PAYDAY_TIME.set(seconds) await self.config.PAYDAY_TIME.set(seconds)
else: else:
await self.config.guild(guild).PAYDAY_TIME.set(seconds) await self.config.guild(guild).PAYDAY_TIME.set(seconds)
await ctx.send("Value modified. At least {} seconds must pass " await ctx.send(_("Value modified. At least {} seconds must pass "
"between each payday.".format(seconds)) "between each payday.").format(seconds))
@economyset.command() @economyset.command()
async def paydayamount(self, ctx: commands.Context, creds: int): async def paydayamount(self, ctx: commands.Context, creds: int):
@ -486,14 +489,14 @@ class Economy:
guild = ctx.guild guild = ctx.guild
credits_name = await bank.get_currency_name(guild) credits_name = await bank.get_currency_name(guild)
if creds <= 0: if creds <= 0:
await ctx.send("Har har so funny.") await ctx.send(_("Har har so funny."))
return return
if await bank.is_global(): if await bank.is_global():
await self.config.PAYDAY_CREDITS.set(creds) await self.config.PAYDAY_CREDITS.set(creds)
else: else:
await self.config.guild(guild).PAYDAY_CREDITS.set(creds) await self.config.guild(guild).PAYDAY_CREDITS.set(creds)
await ctx.send("Every payday will now give {} {}." await ctx.send(_("Every payday will now give {} {}."
"".format(creds, credits_name)) "").format(creds, credits_name))
@economyset.command() @economyset.command()
async def registeramount(self, ctx: commands.Context, creds: int): async def registeramount(self, ctx: commands.Context, creds: int):
@ -503,17 +506,17 @@ class Economy:
creds = 0 creds = 0
credits_name = await bank.get_currency_name(guild) credits_name = await bank.get_currency_name(guild)
await bank.set_default_balance(creds, guild) await bank.set_default_balance(creds, guild)
await ctx.send("Registering an account will now give {} {}." await ctx.send(_("Registering an account will now give {} {}."
"".format(creds, credits_name)) "").format(creds, credits_name))
# What would I ever do without stackoverflow? # What would I ever do without stackoverflow?
def display_time(self, seconds, granularity=2): def display_time(self, seconds, granularity=2):
intervals = ( # Source: http://stackoverflow.com/a/24542445 intervals = ( # Source: http://stackoverflow.com/a/24542445
('weeks', 604800), # 60 * 60 * 24 * 7 (_('weeks'), 604800), # 60 * 60 * 24 * 7
('days', 86400), # 60 * 60 * 24 (_('days'), 86400), # 60 * 60 * 24
('hours', 3600), # 60 * 60 (_('hours'), 3600), # 60 * 60
('minutes', 60), (_('minutes'), 60),
('seconds', 1), (_('seconds'), 1),
) )
result = [] result = []

View File

@ -0,0 +1,199 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2017-08-26 17:40+EDT\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: ../economy.py:38
msgid "JACKPOT! 226! Your bid has been multiplied * 2500!"
msgstr ""
#: ../economy.py:42
msgid "4LC! +1000!"
msgstr ""
#: ../economy.py:46
msgid "Three cherries! +800!"
msgstr ""
#: ../economy.py:50
msgid "2 6! Your bid has been multiplied * 4!"
msgstr ""
#: ../economy.py:54
msgid "Two cherries! Your bid has been multiplied * 3!"
msgstr ""
#: ../economy.py:58
msgid "Three symbols! +500!"
msgstr ""
#: ../economy.py:62
msgid "Two consecutive symbols! Your bid has been multiplied * 2!"
msgstr ""
#: ../economy.py:66
msgid ""
"Slot machine payouts:\n"
"{two.value} {two.value} {six.value} Bet * 2500\n"
"{flc.value} {flc.value} {flc.value} +1000\n"
"{cherries.value} {cherries.value} {cherries.value} +800\n"
"{two.value} {six.value} Bet * 4\n"
"{cherries.value} {cherries.value} Bet * 3\n"
"\n"
"Three symbols: +500\n"
"Two symbols: Bet * 2"
msgstr ""
#: ../economy.py:155
msgid "{}'s balance is {} {}"
msgstr ""
#: ../economy.py:169
msgid "{} transferred {} {} to {}"
msgstr ""
#: ../economy.py:189
msgid "{} added {} {} to {}'s account."
msgstr ""
#: ../economy.py:194
msgid "{} removed {} {} from {}'s account."
msgstr ""
#: ../economy.py:199
msgid "{} set {}'s account to {} {}."
msgstr ""
#: ../economy.py:210
msgid ""
"This will delete all bank accounts for {}.\n"
"If you're sure, type {}bank reset yes"
msgstr ""
#: ../economy.py:227
msgid "All bank accounts of this guild have been deleted."
msgstr ""
#: ../economy.py:246 ../economy.py:266
msgid "{} Here, take some {}. Enjoy! (+{} {}!)"
msgstr ""
#: ../economy.py:256 ../economy.py:274
msgid "{} Too soon. For your next payday you have to wait {}."
msgstr ""
#: ../economy.py:311
msgid "There are no accounts in the bank."
msgstr ""
#: ../economy.py:337
msgid "You're on cooldown, try again in a bit."
msgstr ""
#: ../economy.py:340
msgid "That's an invalid bid amount, sorry :/"
msgstr ""
#: ../economy.py:343
msgid "You ain't got enough money, friend."
msgstr ""
#: ../economy.py:389
msgid ""
"{}\n"
"{} {}\n"
"\n"
"Your bid: {}\n"
"{} → {}!"
msgstr ""
#: ../economy.py:396
msgid ""
"{}\n"
"{} Nothing!\n"
"Your bid: {}\n"
"{} → {}!"
msgstr ""
#: ../economy.py:421
msgid ""
"Minimum slot bid: {}\n"
"Maximum slot bid: {}\n"
"Slot cooldown: {}\n"
"Payday amount: {}\n"
"Payday cooldown: {}\n"
"Amount given at account registration: {}"
msgstr ""
#: ../economy.py:431
msgid "Current Economy settings:"
msgstr ""
#: ../economy.py:439
msgid "Invalid min bid amount."
msgstr ""
#: ../economy.py:447
msgid "Minimum bid is now {} {}."
msgstr ""
#: ../economy.py:454
msgid "Invalid slotmax bid amount. Must be greater than slotmin."
msgstr ""
#: ../economy.py:463
msgid "Maximum bid is now {} {}."
msgstr ""
#: ../economy.py:473
msgid "Cooldown is now {} seconds."
msgstr ""
#: ../economy.py:483
msgid "Value modified. At least {} seconds must pass between each payday."
msgstr ""
#: ../economy.py:492
msgid "Har har so funny."
msgstr ""
#: ../economy.py:498
msgid "Every payday will now give {} {}."
msgstr ""
#: ../economy.py:509
msgid "Registering an account will now give {} {}."
msgstr ""
#: ../economy.py:515
msgid "weeks"
msgstr ""
#: ../economy.py:516
msgid "days"
msgstr ""
#: ../economy.py:517
msgid "hours"
msgstr ""
#: ../economy.py:518
msgid "minutes"
msgstr ""
#: ../economy.py:519
msgid "seconds"
msgstr ""

View File

@ -1,5 +1,6 @@
from discord.ext import commands from discord.ext import commands
from core.utils.chat_formatting import escape, italics, pagify from core.utils.chat_formatting import escape, italics, pagify
from core.i18n import CogI18n
from random import randint, choice from random import randint, choice
from enum import Enum from enum import Enum
from urllib.parse import quote_plus from urllib.parse import quote_plus
@ -8,6 +9,8 @@ import datetime
import time import time
import aiohttp import aiohttp
_ = CogI18n("General", __file__)
class RPS(Enum): class RPS(Enum):
rock = "\N{MOYAI}" rock = "\N{MOYAI}"
@ -34,13 +37,13 @@ class General:
def __init__(self): def __init__(self):
self.stopwatches = {} self.stopwatches = {}
self.ball = [ self.ball = [
"As I see it, yes", "It is certain", "It is decidedly so", _("As I see it, yes"), _("It is certain"), _("It is decidedly so"),
"Most likely", "Outlook good", "Signs point to yes", _("Most likely"), _("Outlook good"), _("Signs point to yes"),
"Without a doubt", "Yes", "Yes definitely", "You may rely on it", _("Without a doubt"), _("Yes"), _("Yes definitely"), _("You may rely on it"),
"Reply hazy, try again", "Ask again later", _("Reply hazy, try again"), _("Ask again later"),
"Better not tell you now", "Cannot predict now", _("Better not tell you now"), _("Cannot predict now"),
"Concentrate and ask again", "Don't count on it", "My reply is no", _("Concentrate and ask again"), _("Don't count on it"), _("My reply is no"),
"My sources say no", "Outlook not so good", "Very doubtful" _("My sources say no"), _("Outlook not so good"), _("Very doubtful")
] ]
@commands.command(hidden=True) @commands.command(hidden=True)
@ -56,7 +59,7 @@ class General:
""" """
choices = [escape(c, mass_mentions=True) for c in choices] choices = [escape(c, mass_mentions=True) for c in choices]
if len(choices) < 2: if len(choices) < 2:
await ctx.send('Not enough choices to pick from.') await ctx.send(_('Not enough choices to pick from.'))
else: else:
await ctx.send(choice(choices)) await ctx.send(choice(choices))
@ -70,10 +73,10 @@ class General:
if number > 1: if number > 1:
n = randint(1, number) n = randint(1, number)
await ctx.send( await ctx.send(
"{} :game_die: {} :game_die:".format(author.mention, n) _("{} :game_die: {} :game_die:").format(author.mention, n)
) )
else: else:
await ctx.send("{} Maybe higher than 1? ;P".format(author.mention)) await ctx.send(_("{} Maybe higher than 1? ;P").format(author.mention))
@commands.command() @commands.command()
async def flip(self, ctx, user: discord.Member=None): async def flip(self, ctx, user: discord.Member=None):
@ -85,8 +88,8 @@ class General:
msg = "" msg = ""
if user.id == ctx.bot.user.id: if user.id == ctx.bot.user.id:
user = ctx.author user = ctx.author
msg = "Nice try. You think this is funny?" +\ msg = _("Nice try. You think this is funny?"
"How about *this* instead:\n\n" "How about *this* instead:\n\n")
char = "abcdefghijklmnopqrstuvwxyz" char = "abcdefghijklmnopqrstuvwxyz"
tran = "ɐqɔpǝɟƃɥᴉɾʞlɯuodbɹsʇnʌʍxʎz" tran = "ɐqɔpǝɟƃɥᴉɾʞlɯuodbɹsʇnʌʍxʎz"
table = str.maketrans(char, tran) table = str.maketrans(char, tran)
@ -98,7 +101,7 @@ class General:
await ctx.send(msg + "(╯°□°)╯︵ " + name[::-1]) await ctx.send(msg + "(╯°□°)╯︵ " + name[::-1])
else: else:
await ctx.send( await ctx.send(
"*flips a coin and... " + choice(["HEADS!*", "TAILS!*"]) _("*flips a coin and... ") + choice([_("HEADS!*"), _("TAILS!*")])
) )
@commands.command() @commands.command()
@ -122,15 +125,15 @@ class General:
outcome = cond[(player_choice, red_choice)] outcome = cond[(player_choice, red_choice)]
if outcome is True: if outcome is True:
await ctx.send("{} You win {}!".format( await ctx.send(_("{} You win {}!").format(
red_choice.value, author.mention red_choice.value, author.mention
)) ))
elif outcome is False: elif outcome is False:
await ctx.send("{} You lose {}!".format( await ctx.send(_("{} You lose {}!").format(
red_choice.value, author.mention red_choice.value, author.mention
)) ))
else: else:
await ctx.send("{} We're square {}!".format( await ctx.send(_("{} We're square {}!").format(
red_choice.value, author.mention red_choice.value, author.mention
)) ))
@ -143,7 +146,7 @@ class General:
if question.endswith("?") and question != "?": if question.endswith("?") and question != "?":
await ctx.send("`" + choice(self.ball) + "`") await ctx.send("`" + choice(self.ball) + "`")
else: else:
await ctx.send("That doesn't look like a question.") await ctx.send(_("That doesn't look like a question."))
@commands.command(aliases=["sw"]) @commands.command(aliases=["sw"])
async def stopwatch(self, ctx): async def stopwatch(self, ctx):
@ -151,11 +154,11 @@ class General:
author = ctx.author author = ctx.author
if not author.id in self.stopwatches: if not author.id in self.stopwatches:
self.stopwatches[author.id] = int(time.perf_counter()) self.stopwatches[author.id] = int(time.perf_counter())
await ctx.send(author.mention + " Stopwatch started!") await ctx.send(author.mention + _(" Stopwatch started!"))
else: else:
tmp = abs(self.stopwatches[author.id] - int(time.perf_counter())) tmp = abs(self.stopwatches[author.id] - int(time.perf_counter()))
tmp = str(datetime.timedelta(seconds=tmp)) tmp = str(datetime.timedelta(seconds=tmp))
await ctx.send(author.mention + " Stopwatch stopped! Time: **" + tmp + "**") await ctx.send(author.mention + _(" Stopwatch stopped! Time: **") + tmp + "**")
self.stopwatches.pop(author.id, None) self.stopwatches.pop(author.id, None)
@commands.command() @commands.command()
@ -208,27 +211,27 @@ class General:
member_number = sorted(guild.members, member_number = sorted(guild.members,
key=lambda m: m.joined_at).index(user) + 1 key=lambda m: m.joined_at).index(user) + 1
created_on = "{}\n({} days ago)".format(user_created, since_created) created_on = _("{}\n({} days ago)").format(user_created, since_created)
joined_on = "{}\n({} days ago)".format(user_joined, since_joined) joined_on = _("{}\n({} days ago)").format(user_joined, since_joined)
game = "Chilling in {} status".format(user.status) game = _("Chilling in {} status").format(user.status)
if user.game and user.game.name and user.game.url: if user.game and user.game.name and user.game.url:
game = "Streaming: [{}]({})".format(user.game, user.game.url) game = _("Streaming: [{}]({})").format(user.game, user.game.url)
elif user.game and user.game.name: elif user.game and user.game.name:
game = "Playing {}".format(user.game) game = _("Playing {}").format(user.game)
if roles: if roles:
roles = ", ".join([x.name for x in roles]) roles = ", ".join([x.name for x in roles])
else: else:
roles = "None" roles = _("None")
data = discord.Embed(description=game, colour=user.colour) data = discord.Embed(description=game, colour=user.colour)
data.add_field(name="Joined Discord on", value=created_on) data.add_field(name=_("Joined Discord on"), value=created_on)
data.add_field(name="Joined this server on", value=joined_on) data.add_field(name=_("Joined this guild on"), value=joined_on)
data.add_field(name="Roles", value=roles, inline=False) data.add_field(name=_("Roles"), value=roles, inline=False)
data.set_footer(text="Member #{} | User ID: {}" data.set_footer(text=_("Member #{} | User ID: {}"
"".format(member_number, user.id)) "").format(member_number, user.id))
name = str(user) name = str(user)
name = " ~ ".join((name, user.nick)) if user.nick else name name = " ~ ".join((name, user.nick)) if user.nick else name
@ -242,8 +245,8 @@ class General:
try: try:
await ctx.send(embed=data) await ctx.send(embed=data)
except discord.HTTPException: except discord.HTTPException:
await ctx.send("I need the `Embed links` permission " await ctx.send(_("I need the `Embed links` permission "
"to send this") "to send this."))
@commands.command() @commands.command()
@commands.guild_only() @commands.guild_only()
@ -257,8 +260,8 @@ class General:
text_channels = len(guild.text_channels) text_channels = len(guild.text_channels)
voice_channels = len(guild.voice_channels) voice_channels = len(guild.voice_channels)
passed = (ctx.message.created_at - guild.created_at).days passed = (ctx.message.created_at - guild.created_at).days
created_at = ("Since {}. That's over {} days ago!" created_at = (_("Since {}. That's over {} days ago!"
"".format(guild.created_at.strftime("%d %b %Y %H:%M"), "").format(guild.created_at.strftime("%d %b %Y %H:%M"),
passed)) passed))
colour = ''.join([choice('0123456789ABCDEF') for x in range(6)]) colour = ''.join([choice('0123456789ABCDEF') for x in range(6)])
@ -267,13 +270,13 @@ class General:
data = discord.Embed( data = discord.Embed(
description=created_at, description=created_at,
colour=discord.Colour(value=colour)) colour=discord.Colour(value=colour))
data.add_field(name="Region", value=str(guild.region)) data.add_field(name=_("Region"), value=str(guild.region))
data.add_field(name="Users", value="{}/{}".format(online, total_users)) data.add_field(name=_("Users"), value="{}/{}".format(online, total_users))
data.add_field(name="Text Channels", value=text_channels) data.add_field(name=_("Text Channels"), value=text_channels)
data.add_field(name="Voice Channels", value=voice_channels) data.add_field(name=_("Voice Channels"), value=voice_channels)
data.add_field(name="Roles", value=len(guild.roles)) data.add_field(name=_("Roles"), value=len(guild.roles))
data.add_field(name="Owner", value=str(guild.owner)) data.add_field(name=_("Owner"), value=str(guild.owner))
data.set_footer(text="Server ID: " + str(guild.id)) data.set_footer(text=_("Guild ID: ") + str(guild.id))
if guild.icon_url: if guild.icon_url:
data.set_author(name=guild.name, url=guild.icon_url) data.set_author(name=guild.name, url=guild.icon_url)
@ -284,8 +287,8 @@ class General:
try: try:
await ctx.send(embed=data) await ctx.send(embed=data)
except discord.HTTPException: except discord.HTTPException:
await ctx.send("I need the `Embed links` permission " await ctx.send(_("I need the `Embed links` permission "
"to send this") "to send this."))
@commands.command() @commands.command()
async def urban(self, ctx, *, search_terms: str, definition_number: int=1): async def urban(self, ctx, *, search_terms: str, definition_number: int=1):
@ -328,8 +331,8 @@ class General:
for page in msg: for page in msg:
await ctx.send(page) await ctx.send(page)
else: else:
await ctx.send("Your search terms gave no results.") await ctx.send(_("Your search terms gave no results."))
except IndexError: except IndexError:
await ctx.send("There is no definition #{}".format(pos+1)) await ctx.send(_("There is no definition #{}").format(pos+1))
except: except:
await ctx.send("Error.") await ctx.send(_("Error."))

View File

@ -0,0 +1,233 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2017-08-26 17:50+EDT\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: ../general.py:40
msgid "As I see it, yes"
msgstr ""
#: ../general.py:40
msgid "It is certain"
msgstr ""
#: ../general.py:40
msgid "It is decidedly so"
msgstr ""
#: ../general.py:41
msgid "Most likely"
msgstr ""
#: ../general.py:41
msgid "Outlook good"
msgstr ""
#: ../general.py:41
msgid "Signs point to yes"
msgstr ""
#: ../general.py:42
msgid "Without a doubt"
msgstr ""
#: ../general.py:42
msgid "Yes"
msgstr ""
#: ../general.py:42
msgid "Yes definitely"
msgstr ""
#: ../general.py:42
msgid "You may rely on it"
msgstr ""
#: ../general.py:43
msgid "Ask again later"
msgstr ""
#: ../general.py:43
msgid "Reply hazy, try again"
msgstr ""
#: ../general.py:44
msgid "Better not tell you now"
msgstr ""
#: ../general.py:44
msgid "Cannot predict now"
msgstr ""
#: ../general.py:45
msgid "Concentrate and ask again"
msgstr ""
#: ../general.py:45
msgid "Don't count on it"
msgstr ""
#: ../general.py:45
msgid "My reply is no"
msgstr ""
#: ../general.py:46
msgid "My sources say no"
msgstr ""
#: ../general.py:46
msgid "Outlook not so good"
msgstr ""
#: ../general.py:46
msgid "Very doubtful"
msgstr ""
#: ../general.py:62
msgid "Not enough choices to pick from."
msgstr ""
#: ../general.py:76
msgid "{} :game_die: {} :game_die:"
msgstr ""
#: ../general.py:79
msgid "{} Maybe higher than 1? ;P"
msgstr ""
#: ../general.py:91
msgid ""
"Nice try. You think this is funny?How about *this* instead:\n"
"\n"
msgstr ""
#: ../general.py:104
msgid "*flips a coin and... "
msgstr ""
#: ../general.py:104
msgid "HEADS!*"
msgstr ""
#: ../general.py:104
msgid "TAILS!*"
msgstr ""
#: ../general.py:128
msgid "{} You win {}!"
msgstr ""
#: ../general.py:132
msgid "{} You lose {}!"
msgstr ""
#: ../general.py:136
msgid "{} We're square {}!"
msgstr ""
#: ../general.py:149
msgid "That doesn't look like a question."
msgstr ""
#: ../general.py:157
msgid " Stopwatch started!"
msgstr ""
#: ../general.py:161
msgid " Stopwatch stopped! Time: **"
msgstr ""
#: ../general.py:214 ../general.py:215
msgid ""
"{}\n"
"({} days ago)"
msgstr ""
#: ../general.py:217
msgid "Chilling in {} status"
msgstr ""
#: ../general.py:220
msgid "Streaming: [{}]({})"
msgstr ""
#: ../general.py:222
msgid "Playing {}"
msgstr ""
#: ../general.py:227
msgid "None"
msgstr ""
#: ../general.py:230
msgid "Joined Discord on"
msgstr ""
#: ../general.py:231
msgid "Joined this guild on"
msgstr ""
#: ../general.py:232 ../general.py:277
msgid "Roles"
msgstr ""
#: ../general.py:233
msgid "Member #{} | User ID: {}"
msgstr ""
#: ../general.py:248 ../general.py:290
msgid "I need the `Embed links` permission to send this."
msgstr ""
#: ../general.py:263
msgid "Since {}. That's over {} days ago!"
msgstr ""
#: ../general.py:273
msgid "Region"
msgstr ""
#: ../general.py:274
msgid "Users"
msgstr ""
#: ../general.py:275
msgid "Text Channels"
msgstr ""
#: ../general.py:276
msgid "Voice Channels"
msgstr ""
#: ../general.py:278
msgid "Owner"
msgstr ""
#: ../general.py:279
msgid "Guild ID: "
msgstr ""
#: ../general.py:334
msgid "Your search terms gave no results."
msgstr ""
#: ../general.py:336
msgid "There is no definition #{}"
msgstr ""
#: ../general.py:338
msgid "Error."
msgstr ""

View File

@ -3,6 +3,9 @@ from random import shuffle
import aiohttp import aiohttp
from core import checks, Config from core import checks, Config
from core.i18n import CogI18n
_ = CogI18n("Image", __file__)
GIPHY_API_KEY = "dc6zaTOxFJmzC" GIPHY_API_KEY = "dc6zaTOxFJmzC"
@ -42,16 +45,16 @@ class Image:
if data["success"]: if data["success"]:
results = data["data"] results = data["data"]
if not results: if not results:
await ctx.send("Your search returned no results") await ctx.send(_("Your search returned no results"))
return return
shuffle(results) shuffle(results)
msg = "Search results...\n" msg = _("Search results...\n")
for r in results[:3]: for r in results[:3]:
msg += r["gifv"] if "gifv" in r else r["link"] msg += r["gifv"] if "gifv" in r else r["link"]
msg += "\n" msg += "\n"
await ctx.send(msg) await ctx.send(msg)
else: else:
await ctx.send("Something went wrong. Error code is {}".format(data["status"])) await ctx.send(_("Something went wrong. Error code is {}").format(data["status"]))
@_imgur.command(name="subreddit") @_imgur.command(name="subreddit")
async def imgur_subreddit(self, ctx, subreddit: str, sort_type: str="top", window: str="day"): async def imgur_subreddit(self, ctx, subreddit: str, sort_type: str="top", window: str="day"):
@ -63,7 +66,7 @@ class Image:
window = window.lower() window = window.lower()
if sort_type not in ("new", "top"): if sort_type not in ("new", "top"):
await ctx.send("Only 'new' and 'top' are a valid sort type.") await ctx.send(_("Only 'new' and 'top' are a valid sort type."))
return return
elif window not in ("day", "week", "month", "year", "all"): elif window not in ("day", "week", "month", "year", "all"):
await self.bot.send_cmd_help(ctx) await self.bot.send_cmd_help(ctx)
@ -91,9 +94,9 @@ class Image:
if links: if links:
await ctx.send("\n".join(links)) await ctx.send("\n".join(links))
else: else:
await ctx.send("No results found.") await ctx.send(_("No results found."))
else: else:
await ctx.send("Something went wrong. Error code is {}".format(data["status"])) await ctx.send(_("Something went wrong. Error code is {}").format(data["status"]))
@checks.is_owner() @checks.is_owner()
@commands.command() @commands.command()
@ -108,7 +111,7 @@ class Image:
enter a description. Check the box for the captcha, then click Next. enter a description. Check the box for the captcha, then click Next.
Your client ID will be on the page that loads""" Your client ID will be on the page that loads"""
await self.settings.imgur_client_id.set(imgur_client_id) await self.settings.imgur_client_id.set(imgur_client_id)
await ctx.send("Set the imgur client id!") await ctx.send(_("Set the imgur client id!"))
@commands.command(pass_context=True, no_pm=True) @commands.command(pass_context=True, no_pm=True)
async def gif(self, ctx, *keywords): async def gif(self, ctx, *keywords):
@ -128,9 +131,9 @@ class Image:
if result["data"]: if result["data"]:
await ctx.send(result["data"][0]["url"]) await ctx.send(result["data"][0]["url"])
else: else:
await ctx.send("No results found.") await ctx.send(_("No results found."))
else: else:
await ctx.send("Error contacting the API") await ctx.send(_("Error contacting the API"))
@commands.command(pass_context=True, no_pm=True) @commands.command(pass_context=True, no_pm=True)
async def gifr(self, ctx, *keywords): async def gifr(self, ctx, *keywords):
@ -150,6 +153,6 @@ class Image:
if result["data"]: if result["data"]:
await ctx.send(result["data"]["url"]) await ctx.send(result["data"]["url"])
else: else:
await ctx.send("No results found.") await ctx.send(_("No results found."))
else: else:
await ctx.send("Error contacting the API") await ctx.send(_("Error contacting the API"))

View File

@ -0,0 +1,46 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2017-08-26 17:57+EDT\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: ../image.py:48
msgid "Your search returned no results"
msgstr ""
#: ../image.py:51
msgid ""
"Search results...\n"
msgstr ""
#: ../image.py:57 ../image.py:99
msgid "Something went wrong. Error code is {}"
msgstr ""
#: ../image.py:69
msgid "Only 'new' and 'top' are a valid sort type."
msgstr ""
#: ../image.py:97 ../image.py:134 ../image.py:156
msgid "No results found."
msgstr ""
#: ../image.py:114
msgid "Set the imgur client id!"
msgstr ""
#: ../image.py:136 ../image.py:158
msgid "Error contacting the API"
msgstr ""

View File

@ -9,6 +9,7 @@ from discord.ext import commands
from core import checks from core import checks
from core.config import Config from core.config import Config
from core.utils.chat_formatting import box from core.utils.chat_formatting import box
from core.i18n import CogI18n
__all__ = ["CogManager"] __all__ = ["CogManager"]
@ -178,6 +179,9 @@ class CogManager:
invalidate_caches() invalidate_caches()
_ = CogI18n("CogManagerUI", __file__)
class CogManagerUI: class CogManagerUI:
@commands.command() @commands.command()
@checks.is_owner() @checks.is_owner()
@ -189,7 +193,7 @@ class CogManagerUI:
cog_paths = ctx.bot.cog_mgr.paths cog_paths = ctx.bot.cog_mgr.paths
cog_paths = [p for p in cog_paths if p != install_path] cog_paths = [p for p in cog_paths if p != install_path]
msg = "Install Path: {}\n\n".format(install_path) msg = _("Install Path: {}\n\n").format(install_path)
partial = [] partial = []
for i, p in enumerate(cog_paths, start=1): for i, p in enumerate(cog_paths, start=1):
@ -205,8 +209,8 @@ class CogManagerUI:
Add a path to the list of available cog paths. Add a path to the list of available cog paths.
""" """
if not path.is_dir(): if not path.is_dir():
await ctx.send("That path is does not exist or does not" await ctx.send(_("That path is does not exist or does not"
" point to a valid directory.") " point to a valid directory."))
return return
try: try:
@ -214,7 +218,7 @@ class CogManagerUI:
except ValueError as e: except ValueError as e:
await ctx.send(str(e)) await ctx.send(str(e))
else: else:
await ctx.send("Path successfully added.") await ctx.send(_("Path successfully added."))
@commands.command() @commands.command()
@checks.is_owner() @checks.is_owner()
@ -227,11 +231,11 @@ class CogManagerUI:
try: try:
to_remove = cog_paths[path_number] to_remove = cog_paths[path_number]
except IndexError: except IndexError:
await ctx.send("That is an invalid path number.") await ctx.send(_("That is an invalid path number."))
return return
await ctx.bot.cog_mgr.remove_path(to_remove) await ctx.bot.cog_mgr.remove_path(to_remove)
await ctx.send("Path successfully removed.") await ctx.send(_("Path successfully removed."))
@commands.command() @commands.command()
@checks.is_owner() @checks.is_owner()
@ -247,17 +251,17 @@ class CogManagerUI:
try: try:
to_move = all_paths.pop(from_) to_move = all_paths.pop(from_)
except IndexError: except IndexError:
await ctx.send("Invalid 'from' index.") await ctx.send(_("Invalid 'from' index."))
return return
try: try:
all_paths.insert(to, to_move) all_paths.insert(to, to_move)
except IndexError: except IndexError:
await ctx.send("Invalid 'to' index.") await ctx.send(_("Invalid 'to' index."))
return return
await ctx.bot.cog_mgr.set_paths(all_paths) await ctx.bot.cog_mgr.set_paths(all_paths)
await ctx.send("Paths reordered.") await ctx.send(_("Paths reordered."))
@commands.command() @commands.command()
@checks.is_owner() @checks.is_owner()
@ -275,9 +279,9 @@ class CogManagerUI:
try: try:
await ctx.bot.cog_mgr.set_install_path(path) await ctx.bot.cog_mgr.set_install_path(path)
except ValueError: except ValueError:
await ctx.send("That path does not exist.") await ctx.send(_("That path does not exist."))
return return
install_path = await ctx.bot.cog_mgr.install_path() install_path = await ctx.bot.cog_mgr.install_path()
await ctx.send("The bot will install new cogs to the `{}`" await ctx.send(_("The bot will install new cogs to the `{}`"
" directory.".format(install_path)) " directory.").format(install_path))

View File

@ -1,6 +1,7 @@
import itertools import itertools
from discord.ext import commands from discord.ext import commands
from core import checks from core import checks
from core import i18n
from string import ascii_letters, digits from string import ascii_letters, digits
from random import SystemRandom from random import SystemRandom
from collections import namedtuple from collections import namedtuple
@ -18,6 +19,8 @@ OWNER_DISCLAIMER = ("⚠ **Only** the person who is hosting Red should be "
"owner can access any data that is present on the host " "owner can access any data that is present on the host "
"system.** ⚠") "system.** ⚠")
_ = i18n.CogI18n("Core", __file__)
class Core: class Core:
"""Commands related to core functions""" """Commands related to core functions"""
@ -29,19 +32,19 @@ class Core:
try: try:
spec = await ctx.bot.cog_mgr.find_cog(cog_name) spec = await ctx.bot.cog_mgr.find_cog(cog_name)
except RuntimeError: except RuntimeError:
await ctx.send("No module by that name was found in any" await ctx.send(_("No module by that name was found in any"
" cog path.") " cog path."))
return return
try: try:
ctx.bot.load_extension(spec) ctx.bot.load_extension(spec)
except Exception as e: except Exception as e:
log.exception("Package loading failed", exc_info=e) log.exception("Package loading failed", exc_info=e)
await ctx.send("Failed to load package. Check your console or " await ctx.send(_("Failed to load package. Check your console or "
"logs for details.") "logs for details."))
else: else:
await ctx.bot.add_loaded_package(cog_name) await ctx.bot.add_loaded_package(cog_name)
await ctx.send("Done.") await ctx.send(_("Done."))
@commands.group() @commands.group()
@checks.is_owner() @checks.is_owner()
@ -50,9 +53,9 @@ class Core:
if cog_name in ctx.bot.extensions: if cog_name in ctx.bot.extensions:
ctx.bot.unload_extension(cog_name) ctx.bot.unload_extension(cog_name)
await ctx.bot.remove_loaded_package(cog_name) await ctx.bot.remove_loaded_package(cog_name)
await ctx.send("Done.") await ctx.send(_("Done."))
else: else:
await ctx.send("That extension is not loaded.") await ctx.send(_("That extension is not loaded."))
@commands.command(name="reload") @commands.command(name="reload")
@checks.is_owner() @checks.is_owner()
@ -65,12 +68,12 @@ class Core:
ctx.bot.load_extension(spec) ctx.bot.load_extension(spec)
except Exception as e: except Exception as e:
log.exception("Package reloading failed", exc_info=e) log.exception("Package reloading failed", exc_info=e)
await ctx.send("Failed to reload package. Check your console or " await ctx.send(_("Failed to reload package. Check your console or "
"logs for details.") "logs for details."))
else: else:
curr_pkgs = await ctx.bot.db.packages() curr_pkgs = await ctx.bot.db.packages()
await ctx.bot.save_packages_status(curr_pkgs) await ctx.bot.save_packages_status(curr_pkgs)
await ctx.send("Done.") await ctx.send(_("Done."))
@commands.command(name="shutdown") @commands.command(name="shutdown")
@checks.is_owner() @checks.is_owner()
@ -80,7 +83,7 @@ class Core:
skin = "\N{EMOJI MODIFIER FITZPATRICK TYPE-3}" skin = "\N{EMOJI MODIFIER FITZPATRICK TYPE-3}"
try: # We don't want missing perms to stop our shutdown try: # We don't want missing perms to stop our shutdown
if not silently: if not silently:
await ctx.send("Shutting down... " + wave + skin) await ctx.send(_("Shutting down... ") + wave + skin)
except: except:
pass pass
await ctx.bot.shutdown() await ctx.bot.shutdown()
@ -117,7 +120,7 @@ class Core:
async def adminrole(self, ctx, *, role: discord.Role): async def adminrole(self, ctx, *, role: discord.Role):
"""Sets the admin role for this server""" """Sets the admin role for this server"""
await ctx.bot.db.guild(ctx.guild).admin_role.set(role.id) await ctx.bot.db.guild(ctx.guild).admin_role.set(role.id)
await ctx.send("The admin role for this server has been set.") await ctx.send(_("The admin role for this guild has been set."))
@_set.command() @_set.command()
@checks.guildowner() @checks.guildowner()
@ -125,7 +128,7 @@ class Core:
async def modrole(self, ctx, *, role: discord.Role): async def modrole(self, ctx, *, role: discord.Role):
"""Sets the mod role for this server""" """Sets the mod role for this server"""
await ctx.bot.db.guild(ctx.guild).mod_role.set(role.id) await ctx.bot.db.guild(ctx.guild).mod_role.set(role.id)
await ctx.send("The mod role for this server has been set.") await ctx.send(_("The mod role for this guild has been set."))
@_set.command() @_set.command()
@checks.is_owner() @checks.is_owner()
@ -139,13 +142,13 @@ class Core:
try: try:
await ctx.bot.user.edit(avatar=data) await ctx.bot.user.edit(avatar=data)
except discord.HTTPException: except discord.HTTPException:
await ctx.send("Failed. Remember that you can edit my avatar " await ctx.send(_("Failed. Remember that you can edit my avatar "
"up to two times a hour. The URL must be a " "up to two times a hour. The URL must be a "
"direct link to a JPG / PNG.") "direct link to a JPG / PNG."))
except discord.InvalidArgument: except discord.InvalidArgument:
await ctx.send("JPG / PNG format only.") await ctx.send(_("JPG / PNG format only."))
else: else:
await ctx.send("Done.") await ctx.send(_("Done."))
@_set.command(name="game") @_set.command(name="game")
@checks.is_owner() @checks.is_owner()
@ -155,7 +158,7 @@ class Core:
status = ctx.me.status status = ctx.me.status
game = discord.Game(name=game) game = discord.Game(name=game)
await ctx.bot.change_presence(status=status, game=game) await ctx.bot.change_presence(status=status, game=game)
await ctx.send("Game set.") await ctx.send(_("Game set."))
@_set.command() @_set.command()
@checks.is_owner() @checks.is_owner()
@ -184,7 +187,7 @@ class Core:
else: else:
await ctx.bot.change_presence(status=status, await ctx.bot.change_presence(status=status,
game=game) game=game)
await ctx.send("Status changed to %s." % status) await ctx.send(_("Status changed to %s.") % status)
@_set.command() @_set.command()
@checks.is_owner() @checks.is_owner()
@ -206,7 +209,7 @@ class Core:
return return
else: else:
await ctx.bot.change_presence(game=None, status=status) await ctx.bot.change_presence(game=None, status=status)
await ctx.send("Done.") await ctx.send(_("Done."))
@_set.command(name="username", aliases=["name"]) @_set.command(name="username", aliases=["name"])
@checks.is_owner() @checks.is_owner()
@ -215,12 +218,12 @@ class Core:
try: try:
await ctx.bot.user.edit(username=username) await ctx.bot.user.edit(username=username)
except discord.HTTPException: except discord.HTTPException:
await ctx.send("Failed to change name. Remember that you can " await ctx.send(_("Failed to change name. Remember that you can "
"only do it up to 2 times an hour. Use " "only do it up to 2 times an hour. Use "
"nicknames if you need frequent changes. " "nicknames if you need frequent changes. "
"`{}set nickname`".format(ctx.prefix)) "`{}set nickname`").format(ctx.prefix))
else: else:
await ctx.send("Done.") await ctx.send(_("Done."))
@_set.command(name="nickname") @_set.command(name="nickname")
@checks.admin() @checks.admin()
@ -230,8 +233,8 @@ class Core:
try: try:
await ctx.bot.user.edit(nick=nickname) await ctx.bot.user.edit(nick=nickname)
except discord.Forbidden: except discord.Forbidden:
await ctx.send("I lack the permissions to change my own " await ctx.send(_("I lack the permissions to change my own "
"nickname.") "nickname."))
else: else:
await ctx.send("Done.") await ctx.send("Done.")
@ -244,7 +247,7 @@ class Core:
return return
prefixes = sorted(prefixes, reverse=True) prefixes = sorted(prefixes, reverse=True)
await ctx.bot.db.prefix.set(prefixes) await ctx.bot.db.prefix.set(prefixes)
await ctx.send("Prefix set.") await ctx.send(_("Prefix set."))
@_set.command(aliases=["serverprefixes"]) @_set.command(aliases=["serverprefixes"])
@checks.admin() @checks.admin()
@ -253,11 +256,11 @@ class Core:
"""Sets Red's server prefix(es)""" """Sets Red's server prefix(es)"""
if not prefixes: if not prefixes:
await ctx.bot.db.guild(ctx.guild).prefix.set([]) await ctx.bot.db.guild(ctx.guild).prefix.set([])
await ctx.send("Server prefixes have been reset.") await ctx.send(_("Guild prefixes have been reset."))
return return
prefixes = sorted(prefixes, reverse=True) prefixes = sorted(prefixes, reverse=True)
await ctx.bot.db.guild(ctx.guild).prefix.set(prefixes) await ctx.bot.db.guild(ctx.guild).prefix.set(prefixes)
await ctx.send("Prefix set.") await ctx.send(_("Prefix set."))
@_set.command() @_set.command()
@commands.cooldown(1, 60 * 10, commands.BucketType.default) @commands.cooldown(1, 60 * 10, commands.BucketType.default)
@ -276,29 +279,38 @@ class Core:
token += random.choice(chars) token += random.choice(chars)
log.info("{0} ({0.id}) requested to be set as owner." log.info("{0} ({0.id}) requested to be set as owner."
"".format(ctx.author)) "".format(ctx.author))
print("\nVerification token:") print(_("\nVerification token:"))
print(token) print(token)
await ctx.send("Remember:\n" + OWNER_DISCLAIMER) await ctx.send(_("Remember:\n") + OWNER_DISCLAIMER)
await asyncio.sleep(5) await asyncio.sleep(5)
await ctx.send("I have printed a one-time token in the console. " await ctx.send(_("I have printed a one-time token in the console. "
"Copy and paste it here to confirm you are the owner.") "Copy and paste it here to confirm you are the owner."))
try: try:
message = await ctx.bot.wait_for("message", check=check, message = await ctx.bot.wait_for("message", check=check,
timeout=60) timeout=60)
except asyncio.TimeoutError: except asyncio.TimeoutError:
self.owner.reset_cooldown(ctx) self.owner.reset_cooldown(ctx)
await ctx.send("The set owner request has timed out.") await ctx.send(_("The set owner request has timed out."))
else: else:
if message.content.strip() == token: if message.content.strip() == token:
self.owner.reset_cooldown(ctx) self.owner.reset_cooldown(ctx)
await ctx.bot.db.owner.set(ctx.author.id) await ctx.bot.db.owner.set(ctx.author.id)
ctx.bot.owner_id = ctx.author.id ctx.bot.owner_id = ctx.author.id
await ctx.send("You have been set as owner.") await ctx.send(_("You have been set as owner."))
else: else:
await ctx.send("Invalid token.") await ctx.send(_("Invalid token."))
@_set.command()
@checks.is_owner()
async def locale(self, ctx: commands.Context, locale_name: str):
"""
Changes bot locale.
"""
i18n.set_locale(locale_name)
await ctx.send(_("Locale has been set."))
@commands.command() @commands.command()
@commands.cooldown(1, 60, commands.BucketType.user) @commands.cooldown(1, 60, commands.BucketType.user)
@ -308,13 +320,13 @@ class Core:
owner = discord.utils.get(ctx.bot.get_all_members(), owner = discord.utils.get(ctx.bot.get_all_members(),
id=ctx.bot.owner_id) id=ctx.bot.owner_id)
author = ctx.message.author author = ctx.message.author
footer = "User ID: %s" % author.id footer = _("User ID: %s") % author.id
if ctx.guild is None: if ctx.guild is None:
source = "through DM" source = _("through DM")
else: else:
source = "from {}".format(guild) source = _("from {}").format(guild)
footer += " | Server ID: %s" % guild.id footer += _(" | Server ID: %s") % guild.id
# We need to grab the DM command prefix (global) # We need to grab the DM command prefix (global)
# Since it can also be set through cli flags, bot.db is not a reliable # Since it can also be set through cli flags, bot.db is not a reliable
@ -322,15 +334,15 @@ class Core:
fake_message = namedtuple('Message', 'guild') fake_message = namedtuple('Message', 'guild')
prefix = ctx.bot.command_prefix(ctx.bot, fake_message(guild=None))[0] prefix = ctx.bot.command_prefix(ctx.bot, fake_message(guild=None))[0]
content = ("Use `{}dm {} <text>` to reply to this user" content = _("Use `{}dm {} <text>` to reply to this user"
"".format(prefix, author.id)) "").format(prefix, author.id)
if isinstance(author, discord.Member): if isinstance(author, discord.Member):
colour = author.colour colour = author.colour
else: else:
colour = discord.Colour.red() colour = discord.Colour.red()
description = "Sent by {} {}".format(author, source) description = _("Sent by {} {}").format(author, source)
e = discord.Embed(colour=colour, description=message) e = discord.Embed(colour=colour, description=message)
if author.avatar_url: if author.avatar_url:
@ -342,12 +354,12 @@ class Core:
try: try:
await owner.send(content, embed=e) await owner.send(content, embed=e)
except discord.InvalidArgument: except discord.InvalidArgument:
await ctx.send("I cannot send your message, I'm unable to find " await ctx.send(_("I cannot send your message, I'm unable to find "
"my owner... *sigh*") "my owner... *sigh*"))
except: except:
await ctx.send("I'm unable to deliver your message. Sorry.") await ctx.send(_("I'm unable to deliver your message. Sorry."))
else: else:
await ctx.send("Your message has been sent.") await ctx.send(_("Your message has been sent."))
@commands.command() @commands.command()
@checks.is_owner() @checks.is_owner()
@ -361,17 +373,17 @@ class Core:
destination = discord.utils.get(ctx.bot.get_all_members(), destination = discord.utils.get(ctx.bot.get_all_members(),
id=user_id) id=user_id)
if destination is None: if destination is None:
await ctx.send("Invalid ID or user not found. You can only " await ctx.send(_("Invalid ID or user not found. You can only "
"send messages to people I share a server " "send messages to people I share a server "
"with.") "with."))
return return
e = discord.Embed(colour=discord.Colour.red(), description=message) e = discord.Embed(colour=discord.Colour.red(), description=message)
description = "Owner of %s" % ctx.bot.user description = _("Owner of %s") % ctx.bot.user
fake_message = namedtuple('Message', 'guild') fake_message = namedtuple('Message', 'guild')
prefix = ctx.bot.command_prefix(ctx.bot, fake_message(guild=None))[0] prefix = ctx.bot.command_prefix(ctx.bot, fake_message(guild=None))[0]
e.set_footer(text=("You can reply to this message with %scontact" e.set_footer(text=_("You can reply to this message with %scontact"
"" % prefix)) "") % prefix)
if ctx.bot.user.avatar_url: if ctx.bot.user.avatar_url:
e.set_author(name=description, icon_url=ctx.bot.user.avatar_url) e.set_author(name=description, icon_url=ctx.bot.user.avatar_url)
else: else:
@ -380,7 +392,7 @@ class Core:
try: try:
await destination.send(embed=e) await destination.send(embed=e)
except: except:
await ctx.send("Sorry, I couldn't deliver your message " await ctx.send(_("Sorry, I couldn't deliver your message "
"to %s" % destination) "to %s") % destination)
else: else:
await ctx.send("Message delivered to %s" % destination) await ctx.send(_("Message delivered to %s") % destination)

View File

@ -1,6 +1,7 @@
from discord.ext import commands from discord.ext import commands
from core.utils.chat_formatting import box, pagify from core.utils.chat_formatting import box, pagify
from core import checks from core import checks
from core.i18n import CogI18n
import asyncio import asyncio
import discord import discord
import traceback import traceback
@ -18,6 +19,8 @@ Notice:
https://github.com/Rapptz/RoboDanny/blob/master/cogs/repl.py https://github.com/Rapptz/RoboDanny/blob/master/cogs/repl.py
""" """
_ = CogI18n("Dev", __file__)
class Dev: class Dev:
"""Various development focused utilities""" """Various development focused utilities"""
@ -159,11 +162,11 @@ class Dev:
} }
if ctx.channel.id in self.sessions: if ctx.channel.id in self.sessions:
await ctx.send('Already running a REPL session in this channel. Exit it with `quit`.') await ctx.send(_('Already running a REPL session in this channel. Exit it with `quit`.'))
return return
self.sessions.add(ctx.channel.id) self.sessions.add(ctx.channel.id)
await ctx.send('Enter code to execute or evaluate. `exit()` or `quit` to exit.') await ctx.send(_('Enter code to execute or evaluate. `exit()` or `quit` to exit.'))
def msg_check(m): def msg_check(m):
return m.author == ctx.author and m.channel == ctx.channel and \ return m.author == ctx.author and m.channel == ctx.channel and \
@ -228,7 +231,7 @@ class Dev:
except discord.Forbidden: except discord.Forbidden:
pass pass
except discord.HTTPException as e: except discord.HTTPException as e:
await ctx.send('Unexpected error: `{}`'.format(e)) await ctx.send(_('Unexpected error: `{}`').format(e))
@commands.command() @commands.command()
@checks.is_owner() @checks.is_owner()

203
core/i18n.py Normal file
View File

@ -0,0 +1,203 @@
import re
from pathlib import Path
__all__ = ['get_locale', 'set_locale', 'reload_locales', 'CogI18n']
_current_locale = 'en_us'
WAITING_FOR_MSGID = 1
IN_MSGID = 2
WAITING_FOR_MSGSTR = 3
IN_MSGSTR = 4
MSGID = 'msgid "'
MSGSTR = 'msgstr "'
_i18n_cogs = {}
def get_locale():
return _current_locale
def set_locale(locale):
global _current_locale
_current_locale = locale
reload_locales()
def reload_locales():
for cog_name, i18n in _i18n_cogs.items():
i18n.load_translations()
def _parse(translation_file):
"""
Custom gettext parsing of translation files. All credit for this code goes
to ProgVal/Valentin Lorentz and the Limnoria project.
https://github.com/ProgVal/Limnoria/blob/master/src/i18n.py
:param translation_file:
An open file-like object containing translations.
:return:
A set of 2-tuples containing the original string and the translated version.
"""
step = WAITING_FOR_MSGID
translations = set()
for line in translation_file:
line = line[0:-1] # Remove the ending \n
line = line
if line.startswith(MSGID):
# Don't check if step is WAITING_FOR_MSGID
untranslated = ''
translated = ''
data = line[len(MSGID):-1]
if len(data) == 0: # Multiline mode
step = IN_MSGID
else:
untranslated += data
step = WAITING_FOR_MSGSTR
elif step is IN_MSGID and line.startswith('"') and \
line.endswith('"'):
untranslated += line[1:-1]
elif step is IN_MSGID and untranslated == '': # Empty MSGID
step = WAITING_FOR_MSGID
elif step is IN_MSGID: # the MSGID is finished
step = WAITING_FOR_MSGSTR
if step is WAITING_FOR_MSGSTR and line.startswith(MSGSTR):
data = line[len(MSGSTR):-1]
if len(data) == 0: # Multiline mode
step = IN_MSGSTR
else:
translations |= {(untranslated, data)}
step = WAITING_FOR_MSGID
elif step is IN_MSGSTR and line.startswith('"') and \
line.endswith('"'):
translated += line[1:-1]
elif step is IN_MSGSTR: # the MSGSTR is finished
step = WAITING_FOR_MSGID
if translated == '':
translated = untranslated
translations |= {(untranslated, translated)}
if step is IN_MSGSTR:
if translated == '':
translated = untranslated
translations |= {(untranslated, translated)}
return translations
def _normalize(string, remove_newline=False):
"""
String normalization.
All credit for this code goes
to ProgVal/Valentin Lorentz and the Limnoria project.
https://github.com/ProgVal/Limnoria/blob/master/src/i18n.py
:param string:
:param remove_newline:
:return:
"""
def normalize_whitespace(s):
"""Normalizes the whitespace in a string; \s+ becomes one space."""
if not s:
return str(s) # not the same reference
starts_with_space = (s[0] in ' \n\t\r')
ends_with_space = (s[-1] in ' \n\t\r')
if remove_newline:
newline_re = re.compile('[\r\n]+')
s = ' '.join(filter(bool, newline_re.split(s)))
s = ' '.join(filter(bool, s.split('\t')))
s = ' '.join(filter(bool, s.split(' ')))
if starts_with_space:
s = ' ' + s
if ends_with_space:
s += ' '
return s
string = string.replace('\\n\\n', '\n\n')
string = string.replace('\\n', ' ')
string = string.replace('\\"', '"')
string = string.replace("\'", "'")
string = normalize_whitespace(string)
string = string.strip('\n')
string = string.strip('\t')
return string
def get_locale_path(cog_folder: Path, extension: str) -> Path:
"""
Gets the folder path containing localization files.
:param Path cog_folder:
The cog folder that we want localizations for.
:param str extension:
Extension of localization files.
:return:
Path of possible localization file, it may not exist.
"""
return cog_folder / 'locales' / "{}.{}".format(get_locale(), extension)
class CogI18n:
def __init__(self, name, file_location):
"""
Initializes the internationalization object for a given cog.
:param name: Your cog name.
:param file_location:
This should always be ``__file__`` otherwise your localizations
will not load.
"""
self.cog_folder = Path(file_location).resolve().parent
self.cog_name = name
self.translations = {}
_i18n_cogs.update({self.cog_name: self})
self.load_translations()
def __call__(self, untranslated: str):
normalized_untranslated = _normalize(untranslated, True)
try:
return self.translations[normalized_untranslated]
except KeyError:
return untranslated
def load_translations(self):
"""
Loads the current translations for this cog.
"""
self.translations = {}
translation_file = None
locale_path = get_locale_path(self.cog_folder, 'po')
try:
try:
translation_file = locale_path.open('ru')
except ValueError: # We are using Windows
translation_file = locale_path.open('r')
self._parse(translation_file)
except (IOError, FileNotFoundError): # The translation is unavailable
pass
finally:
if translation_file is not None:
translation_file.close()
def _parse(self, translation_file):
self.translations = {}
for translation in _parse(translation_file):
self._add_translation(*translation)
def _add_translation(self, untranslated, translated):
untranslated = _normalize(untranslated, True)
translated = _normalize(translated)
if translated:
self.translations.update({untranslated: translated})

223
core/locales/messages.pot Normal file
View File

@ -0,0 +1,223 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2017-08-26 18:11+EDT\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: ../cog_manager.py:196
msgid ""
"Install Path: {}\n"
"\n"
msgstr ""
#: ../cog_manager.py:212
msgid "That path is does not exist or does not point to a valid directory."
msgstr ""
#: ../cog_manager.py:221
msgid "Path successfully added."
msgstr ""
#: ../cog_manager.py:234
msgid "That is an invalid path number."
msgstr ""
#: ../cog_manager.py:238
msgid "Path successfully removed."
msgstr ""
#: ../cog_manager.py:254
msgid "Invalid 'from' index."
msgstr ""
#: ../cog_manager.py:260
msgid "Invalid 'to' index."
msgstr ""
#: ../cog_manager.py:264
msgid "Paths reordered."
msgstr ""
#: ../cog_manager.py:282
msgid "That path does not exist."
msgstr ""
#: ../cog_manager.py:286
msgid "The bot will install new cogs to the `{}` directory."
msgstr ""
#: ../core_commands.py:35
msgid "No module by that name was found in any cog path."
msgstr ""
#: ../core_commands.py:43
msgid "Failed to load package. Check your console or logs for details."
msgstr ""
#: ../core_commands.py:47 ../core_commands.py:56 ../core_commands.py:76
#: ../core_commands.py:151 ../core_commands.py:212 ../core_commands.py:226
msgid "Done."
msgstr ""
#: ../core_commands.py:58
msgid "That extension is not loaded."
msgstr ""
#: ../core_commands.py:71
msgid "Failed to reload package. Check your console or logs for details."
msgstr ""
#: ../core_commands.py:86
msgid "Shutting down... "
msgstr ""
#: ../core_commands.py:123
msgid "The admin role for this guild has been set."
msgstr ""
#: ../core_commands.py:131
msgid "The mod role for this guild has been set."
msgstr ""
#: ../core_commands.py:145
msgid "Failed. Remember that you can edit my avatar up to two times a hour. The URL must be a direct link to a JPG / PNG."
msgstr ""
#: ../core_commands.py:149
msgid "JPG / PNG format only."
msgstr ""
#: ../core_commands.py:161
msgid "Game set."
msgstr ""
#: ../core_commands.py:190
msgid "Status changed to %s."
msgstr ""
#: ../core_commands.py:221
msgid "Failed to change name. Remember that you can only do it up to 2 times an hour. Use nicknames if you need frequent changes. `{}set nickname`"
msgstr ""
#: ../core_commands.py:236
msgid "I lack the permissions to change my own nickname."
msgstr ""
#: ../core_commands.py:250 ../core_commands.py:263
msgid "Prefix set."
msgstr ""
#: ../core_commands.py:259
msgid "Guild prefixes have been reset."
msgstr ""
#: ../core_commands.py:282
msgid ""
"\n"
"Verification token:"
msgstr ""
#: ../core_commands.py:285
msgid ""
"Remember:\n"
msgstr ""
#: ../core_commands.py:288
msgid "I have printed a one-time token in the console. Copy and paste it here to confirm you are the owner."
msgstr ""
#: ../core_commands.py:296
msgid "The set owner request has timed out."
msgstr ""
#: ../core_commands.py:302
msgid "You have been set as owner."
msgstr ""
#: ../core_commands.py:304
msgid "Invalid token."
msgstr ""
#: ../core_commands.py:313
msgid "Locale has been set."
msgstr ""
#: ../core_commands.py:323
msgid "User ID: %s"
msgstr ""
#: ../core_commands.py:326
msgid "through DM"
msgstr ""
#: ../core_commands.py:328
msgid "from {}"
msgstr ""
#: ../core_commands.py:329
msgid " | Server ID: %s"
msgstr ""
#: ../core_commands.py:337
msgid "Use `{}dm {} <text>` to reply to this user"
msgstr ""
#: ../core_commands.py:345
msgid "Sent by {} {}"
msgstr ""
#: ../core_commands.py:357
msgid "I cannot send your message, I'm unable to find my owner... *sigh*"
msgstr ""
#: ../core_commands.py:360
msgid "I'm unable to deliver your message. Sorry."
msgstr ""
#: ../core_commands.py:362
msgid "Your message has been sent."
msgstr ""
#: ../core_commands.py:376
msgid "Invalid ID or user not found. You can only send messages to people I share a server with."
msgstr ""
#: ../core_commands.py:382
msgid "Owner of %s"
msgstr ""
#: ../core_commands.py:385
msgid "You can reply to this message with %scontact"
msgstr ""
#: ../core_commands.py:395
msgid "Sorry, I couldn't deliver your message to %s"
msgstr ""
#: ../core_commands.py:398
msgid "Message delivered to %s"
msgstr ""
#: ../dev_commands.py:165
msgid "Already running a REPL session in this channel. Exit it with `quit`."
msgstr ""
#: ../dev_commands.py:169
msgid "Enter code to execute or evaluate. `exit()` or `quit` to exit."
msgstr ""
#: ../dev_commands.py:234
msgid "Unexpected error: `{}`"
msgstr ""

View File

@ -0,0 +1,17 @@
import subprocess
TO_TRANSLATE = [
'../cog_manager.py',
'../core_commands.py',
'../dev_commands.py'
]
def regen_messages():
subprocess.run(
['pygettext', '-n'] + TO_TRANSLATE
)
if __name__ == "__main__":
regen_messages()