From 118df466303b72d4cd35be2ae28f821f4ee36f83 Mon Sep 17 00:00:00 2001 From: Will Date: Sat, 26 Aug 2017 18:54:51 -0400 Subject: [PATCH] [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 --- .gitignore | 1 - cogs/alias/alias.py | 45 +++--- cogs/alias/locales/messages.pot | 65 ++++++++ cogs/bank/bank.py | 11 +- cogs/bank/locales/messages.pot | 37 +++++ cogs/downloader/downloader.py | 45 +++--- cogs/downloader/locales/de.po | 97 +++++++++++ cogs/downloader/locales/es.po | 97 +++++++++++ cogs/downloader/locales/fr.po | 97 +++++++++++ cogs/downloader/locales/it.po | 93 +++++++++++ cogs/downloader/locales/messages.pot | 93 +++++++++++ cogs/downloader/locales/nl.po | 94 +++++++++++ cogs/downloader/repo_manager.py | 2 +- cogs/economy/economy.py | 135 ++++++++-------- cogs/economy/locales/messages.pot | 199 +++++++++++++++++++++++ cogs/general/general.py | 97 +++++------ cogs/general/locales/messages.pot | 233 +++++++++++++++++++++++++++ cogs/image/image.py | 25 +-- cogs/image/locales/messages.pot | 46 ++++++ core/cog_manager.py | 28 ++-- core/core_commands.py | 128 ++++++++------- core/dev_commands.py | 9 +- core/i18n.py | 203 +++++++++++++++++++++++ core/locales/messages.pot | 223 +++++++++++++++++++++++++ core/locales/regen_messages.py | 17 ++ 25 files changed, 1875 insertions(+), 245 deletions(-) create mode 100644 cogs/alias/locales/messages.pot create mode 100644 cogs/bank/locales/messages.pot create mode 100644 cogs/downloader/locales/de.po create mode 100644 cogs/downloader/locales/es.po create mode 100644 cogs/downloader/locales/fr.po create mode 100644 cogs/downloader/locales/it.po create mode 100644 cogs/downloader/locales/messages.pot create mode 100644 cogs/downloader/locales/nl.po create mode 100644 cogs/economy/locales/messages.pot create mode 100644 cogs/general/locales/messages.pot create mode 100644 cogs/image/locales/messages.pot create mode 100644 core/i18n.py create mode 100644 core/locales/messages.pot create mode 100644 core/locales/regen_messages.py diff --git a/.gitignore b/.gitignore index 1a3cbc603..bb9b7b7d1 100644 --- a/.gitignore +++ b/.gitignore @@ -103,7 +103,6 @@ coverage.xml # Translations *.mo -*.pot # Django stuff: *.log diff --git a/cogs/alias/alias.py b/cogs/alias/alias.py index 23ae4df29..301459196 100644 --- a/cogs/alias/alias.py +++ b/cogs/alias/alias.py @@ -6,8 +6,11 @@ from typing import Generator, Tuple, Iterable from core import Config from core.bot import Red from core.utils.chat_formatting import box +from core.i18n import CogI18n from .alias_entry import AliasEntry +_ = CogI18n("Alias", __file__) + class Alias: """ @@ -132,7 +135,7 @@ class Alias: for p in prefixes: if content.startswith(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, alias: AliasEntry) -> str: @@ -228,8 +231,8 @@ class Alias: await self.add_alias(ctx, alias_name, command) - await ctx.send(("A new alias with the trigger `{}`" - " has been created.").format(alias_name)) + await ctx.send(_("A new alias with the trigger `{}`" + " has been created.").format(alias_name)) @global_.command(name="add") async def _add_global_alias(self, ctx: commands.Context, @@ -264,8 +267,8 @@ class Alias: await self.add_alias(ctx, alias_name, command, global_=True) - await ctx.send(("A new global alias with the trigger `{}`" - " has been created.").format(alias_name)) + await ctx.send(_("A new global alias with the trigger `{}`" + " has been created.").format(alias_name)) @alias.command(name="help") @commands.guild_only() @@ -279,7 +282,7 @@ class Alias: new_msg.content = "{}help {}".format(ctx.prefix, base_cmd) await self.bot.process_commands(new_msg) else: - ctx.send("No such alias exists.") + ctx.send(_("No such alias exists.")) @alias.command(name="show") @commands.guild_only() @@ -288,10 +291,10 @@ class Alias: is_alias, alias = await self.is_alias(ctx.guild, alias_name) if is_alias: - await ctx.send(("The `{}` alias will execute the" - " command `{}`").format(alias_name, alias.command)) + await ctx.send(_("The `{}` alias will execute the" + " command `{}`").format(alias_name, alias.command)) 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") @commands.guild_only() @@ -303,14 +306,14 @@ class Alias: try: next(aliases) except StopIteration: - await ctx.send("There are no aliases on this guild.") + await ctx.send(_("There are no aliases on this guild.")) return if await self.delete_alias(ctx, alias_name): - await ctx.send(("Alias with the name `{}` was successfully" - " deleted.").format(alias_name)) + await ctx.send(_("Alias with the name `{}` was successfully" + " deleted.").format(alias_name)) 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") async def _del_global_alias(self, ctx: commands.Context, alias_name: str): @@ -321,14 +324,14 @@ class Alias: try: next(aliases) except StopIteration: - await ctx.send("There are no aliases on this bot.") + await ctx.send(_("There are no aliases on this bot.")) return if await self.delete_alias(ctx, alias_name, global_=True): - await ctx.send(("Alias with the name `{}` was successfully" - " deleted.").format(alias_name)) + await ctx.send(_("Alias with the name `{}` was successfully" + " deleted.").format(alias_name)) 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") @commands.guild_only() @@ -336,9 +339,9 @@ class Alias: """ 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: - await ctx.send("There are no aliases on this server.") + await ctx.send(_("There are no aliases on this server.")) else: await ctx.send(box("\n".join(names), "diff")) @@ -347,9 +350,9 @@ class Alias: """ 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: - await ctx.send("There are no aliases on this server.") + await ctx.send(_("There are no aliases on this server.")) else: await ctx.send(box("\n".join(names), "diff")) diff --git a/cogs/alias/locales/messages.pot b/cogs/alias/locales/messages.pot new file mode 100644 index 000000000..91acdc538 --- /dev/null +++ b/cogs/alias/locales/messages.pot @@ -0,0 +1,65 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , 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 \n" +"Language-Team: LANGUAGE \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 "" + diff --git a/cogs/bank/bank.py b/cogs/bank/bank.py index 20939b2f8..0e57b5e23 100644 --- a/cogs/bank/bank.py +++ b/cogs/bank/bank.py @@ -2,6 +2,9 @@ from discord.ext import commands from core import checks, bank from core.bot import Red # Only used for type hints +from core.i18n import CogI18n + +_ = CogI18n('Bank', __file__) def check_global_setting_guildowner(): @@ -62,22 +65,22 @@ class Bank: cur_setting = await bank.is_global() 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") @check_global_setting_guildowner() async def bankset_bankname(self, ctx: commands.Context, *, name: str): """Set the bank's name""" 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") @check_global_setting_guildowner() async def bankset_creditsname(self, ctx: commands.Context, *, name: str): """Set the name for the bank's currency""" await bank.set_currency_name(name, ctx.guild) - await ctx.send("Currency name has been set to {}".format(name)) + await ctx.send(_("Currency name has been set to {}").format(name)) # ENDSECTION diff --git a/cogs/bank/locales/messages.pot b/cogs/bank/locales/messages.pot new file mode 100644 index 000000000..f5230f5f3 --- /dev/null +++ b/cogs/bank/locales/messages.pot @@ -0,0 +1,37 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , 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 \n" +"Language-Team: LANGUAGE \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 "" + diff --git a/cogs/downloader/downloader.py b/cogs/downloader/downloader.py index 254e2c6b0..bb2049d4e 100644 --- a/cogs/downloader/downloader.py +++ b/cogs/downloader/downloader.py @@ -11,6 +11,7 @@ from core import Config from core.bot import Red from core import checks from core.utils.chat_formatting import box +from core.i18n import CogI18n from .repo_manager import RepoManager, Repo from .installable import Installable @@ -19,6 +20,8 @@ from .log import log from .errors import CloningError, ExistingGitRepo from .checks import install_agreement +_ = CogI18n('Downloader', __file__) + class Downloader: def __init__(self, bot: Red): @@ -196,12 +199,12 @@ class Downloader: branch=branch ) 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: - await ctx.send("Something went wrong during the cloning process.") - log.exception("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.")) else: - await ctx.send("Repo `{}` successfully added.".format(name)) + await ctx.send(_("Repo `{}` successfully added.").format(name)) @repo.command(name="delete") 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 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") async def _repo_list(self, ctx): @@ -218,7 +221,7 @@ class Downloader: Lists all installed repos. """ 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")) @@ -238,13 +241,13 @@ class Downloader: """ cog = discord.utils.get(repo_name.available_cogs, name=cog_name) if cog is None: - await ctx.send("Error, there is no cog by the name of" - " `{}` in the `{}` repo.".format(cog_name, repo_name.name)) + await ctx.send(_("Error, there is no cog by the name of" + " `{}` in the `{}` repo.").format(cog_name, repo_name.name)) return if not await repo_name.install_requirements(cog, self.LIB_PATH): - await ctx.send("Failed to install the required libraries for" - " `{}`: `{}`".format(cog.name, cog.requirements)) + await ctx.send(_("Failed to install the required libraries for" + " `{}`: `{}`").format(cog.name, cog.requirements)) return 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 ctx.send("`{}` cog successfully installed.".format(cog_name)) + await ctx.send(_("`{}` cog successfully installed.").format(cog_name)) @cog.command(name="uninstall") async def _cog_uninstall(self, ctx, cog_name: InstalledCog): @@ -269,11 +272,11 @@ class Downloader: await self._delete_cog(poss_installed_path) # noinspection PyTypeChecker 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: - 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" - " files manually if it is still usable.") + " files manually if it is still usable.")) @cog.command(name="update") async def _cog_update(self, ctx, cog_name: InstalledCog=None): @@ -295,7 +298,7 @@ class Downloader: # noinspection PyTypeChecker 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") async def _cog_list(self, ctx, repo_name: Repo): @@ -303,7 +306,7 @@ class Downloader: Lists all available cogs from a single repo. """ 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]) await ctx.send(box(cogs, lang="diff")) @@ -315,12 +318,12 @@ class Downloader: """ cog = discord.utils.get(repo_name.available_cogs, name=cog_name) 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 )) 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)) async def is_installed(self, cog_name: str) -> (bool, Union[Installable, None]): @@ -344,7 +347,7 @@ class Downloader: :return: str """ 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_url = repo.url cog_name = cog_installable.name @@ -353,7 +356,7 @@ class Downloader: repo_url = "https://github.com/Twentysix26/Red-DiscordBot" 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) @@ -377,7 +380,7 @@ class Downloader: command = ctx.bot.all_commands.get(command_name) 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 # Check if in installed cogs diff --git a/cogs/downloader/locales/de.po b/cogs/downloader/locales/de.po new file mode 100644 index 000000000..c5add859f --- /dev/null +++ b/cogs/downloader/locales/de.po @@ -0,0 +1,97 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , 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." diff --git a/cogs/downloader/locales/es.po b/cogs/downloader/locales/es.po new file mode 100644 index 000000000..33b3a4ec7 --- /dev/null +++ b/cogs/downloader/locales/es.po @@ -0,0 +1,97 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , 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." diff --git a/cogs/downloader/locales/fr.po b/cogs/downloader/locales/fr.po new file mode 100644 index 000000000..15e99ae9b --- /dev/null +++ b/cogs/downloader/locales/fr.po @@ -0,0 +1,97 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , 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" diff --git a/cogs/downloader/locales/it.po b/cogs/downloader/locales/it.po new file mode 100644 index 000000000..4ab7e28e1 --- /dev/null +++ b/cogs/downloader/locales/it.po @@ -0,0 +1,93 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , 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 \n" +"Language-Team: LANGUAGE \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 "" + diff --git a/cogs/downloader/locales/messages.pot b/cogs/downloader/locales/messages.pot new file mode 100644 index 000000000..a09f4490f --- /dev/null +++ b/cogs/downloader/locales/messages.pot @@ -0,0 +1,93 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , 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 \n" +"Language-Team: LANGUAGE \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 "" + diff --git a/cogs/downloader/locales/nl.po b/cogs/downloader/locales/nl.po new file mode 100644 index 000000000..03d15c7fd --- /dev/null +++ b/cogs/downloader/locales/nl.po @@ -0,0 +1,94 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , 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 "" diff --git a/cogs/downloader/repo_manager.py b/cogs/downloader/repo_manager.py index ef7af974b..87beaa11d 100644 --- a/cogs/downloader/repo_manager.py +++ b/cogs/downloader/repo_manager.py @@ -447,7 +447,7 @@ class RepoManager: self._repos = {} 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 def repos_folder(self) -> Path: diff --git a/cogs/economy/economy.py b/cogs/economy/economy.py index e8cb4bdf7..05035ddc3 100644 --- a/cogs/economy/economy.py +++ b/cogs/economy/economy.py @@ -10,6 +10,9 @@ from core import checks, Config, bank from core.utils.chat_formatting import pagify, box from core.bot import Red 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") @@ -32,42 +35,42 @@ class SMReel(Enum): PAYOUTS = { (SMReel.two, SMReel.two, SMReel.six): { "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): { "payout": lambda x: x + 1000, - "phrase": "4LC! +1000!" + "phrase": _("4LC! +1000!") }, (SMReel.cherries, SMReel.cherries, SMReel.cherries): { "payout": lambda x: x + 800, - "phrase": "Three cherries! +800!" + "phrase": _("Three cherries! +800!") }, (SMReel.two, SMReel.six): { "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): { "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": { "payout": lambda x: x + 500, - "phrase": "Three symbols! +500!" + "phrase": _("Three symbols! +500!") }, "2 symbols": { "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" - "{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".format(**SMReel.__dict__)) +SLOT_PAYOUTS_MSG = _("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").format(**SMReel.__dict__) def guild_only_check(): @@ -149,7 +152,7 @@ class Economy: bal = await bank.get_balance(user) 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)) @_bank.command() @@ -163,7 +166,7 @@ class Economy: except ValueError as 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 )) @@ -183,17 +186,17 @@ class Economy: if creds.operation == "deposit": 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 )) elif creds.operation == "withdraw": 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 )) else: 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 )) @@ -204,8 +207,8 @@ class Economy: """Deletes all guild's bank accounts""" if confirmation is False: await ctx.send( - "This will delete all bank accounts for {}.\nIf you're sure, type " - "{}bank reset yes".format( + _("This will delete all bank accounts for {}.\nIf you're sure, type " + "{}bank reset yes").format( self.bot.user.name if await bank.is_global() else "this guild", ctx.prefix ) @@ -221,8 +224,8 @@ class Economy: user = ctx.guild.owner success = await bank.wipe_bank(user) if success: - await ctx.send("All bank accounts of this guild have been " - "deleted.") + await ctx.send(_("All bank accounts of this guild have been " + "deleted.")) @commands.command() @guild_only_check() @@ -240,8 +243,8 @@ class Economy: next_payday = cur_time + await self.config.PAYDAY_TIME() await self.config.user(author).next_payday.set(next_payday) await ctx.send( - "{} Here, take some {}. Enjoy! (+{}" - " {}!)".format( + _("{} Here, take some {}. Enjoy! (+{}" + " {}!)").format( author.mention, credits_name, str(await self.config.PAYDAY_CREDITS()), credits_name @@ -250,8 +253,8 @@ class Economy: else: dtime = self.display_time(next_payday - cur_time) await ctx.send( - "{} Too soon. For your next payday you have to" - " wait {}.".format(author.mention, dtime) + _("{} Too soon. For your next payday you have to" + " wait {}.").format(author.mention, dtime) ) else: 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() await self.config.member(author).next_payday.set(next_payday) await ctx.send( - "{} Here, take some {}. Enjoy! (+{}" - " {}!)".format( + _("{} Here, take some {}. Enjoy! (+{}" + " {}!)").format( author.mention, credits_name, str(await self.config.guild(guild).PAYDAY_CREDITS()), credits_name)) else: dtime = self.display_time(next_payday - cur_time) await ctx.send( - "{} Too soon. For your next payday you have to" - " wait {}.".format(author.mention, dtime)) + _("{} Too soon. For your next payday you have to" + " wait {}.").format(author.mention, dtime)) @commands.command() @guild_only_check() @@ -305,7 +308,7 @@ class Economy: for page in pagify(highscore, shorten_by=12): await ctx.send(box(page, lang="py")) else: - await ctx.send("There are no accounts in the bank.") + await ctx.send(_("There are no accounts in the bank.")) @commands.command() @guild_only_check() @@ -331,13 +334,13 @@ class Economy: now = calendar.timegm(ctx.message.created_at.utctimetuple()) 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 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 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 if await bank.is_global(): await self.config.user(author).last_slot.set(now) @@ -383,15 +386,15 @@ class Economy: pay = payout["payout"](bid) now = then - bid + pay await bank.set_balance(author, now) - await channel.send("{}\n{} {}\n\nYour bid: {}\n{} → {}!" - "".format(slot, author.mention, + await channel.send(_("{}\n{} {}\n\nYour bid: {}\n{} → {}!" + "").format(slot, author.mention, payout["phrase"], bid, then, now)) else: then = await bank.get_balance(author) await bank.withdraw_credits(author, bid) now = then - bid - await channel.send("{}\n{} Nothing!\nYour bid: {}\n{} → {}!" - "".format(slot, author.mention, bid, then, now)) + await channel.send(_("{}\n{} Nothing!\nYour bid: {}\n{} → {}!" + "").format(slot, author.mention, bid, then, now)) @commands.group() @guild_only_check() @@ -415,17 +418,17 @@ class Economy: payday_amount = await self.config.guild(guild).PAYDAY_CREDITS() register_amount = await bank.get_default_balance(guild) msg = box( - "Minimum slot bid: {}\n" - "Maximum slot bid: {}\n" - "Slot cooldown: {}\n" - "Payday amount: {}\n" - "Payday cooldown: {}\n" - "Amount given at account registration: {}" - "".format( + _("Minimum slot bid: {}\n" + "Maximum slot bid: {}\n" + "Slot cooldown: {}\n" + "Payday amount: {}\n" + "Payday cooldown: {}\n" + "Amount given at account registration: {}" + "").format( slot_min, slot_max, slot_time, payday_amount, payday_time, register_amount ), - "Current Economy settings:" + _("Current Economy settings:") ) await ctx.send(msg) @@ -433,7 +436,7 @@ class Economy: async def slotmin(self, ctx: commands.Context, bid: int): """Minimum slot machine bid""" if bid < 1: - await ctx.send('Invalid min bid amount.') + await ctx.send(_('Invalid min bid amount.')) return guild = ctx.guild if await bank.is_global(): @@ -441,15 +444,15 @@ class Economy: else: await self.config.guild(guild).SLOT_MIN.set(bid) 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() async def slotmax(self, ctx: commands.Context, bid: int): """Maximum slot machine bid""" slot_min = await self.config.SLOT_MIN() if bid < 1 or bid < slot_min: - await ctx.send('Invalid slotmax bid amount. Must be greater' - ' than slotmin.') + await ctx.send(_('Invalid slotmax bid amount. Must be greater' + ' than slotmin.')) return guild = ctx.guild credits_name = await bank.get_currency_name(guild) @@ -457,7 +460,7 @@ class Economy: await self.config.SLOT_MAX.set(bid) else: 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() async def slottime(self, ctx: commands.Context, seconds: int): @@ -467,7 +470,7 @@ class Economy: await self.config.SLOT_TIME.set(seconds) else: 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() async def paydaytime(self, ctx: commands.Context, seconds: int): @@ -477,8 +480,8 @@ class Economy: await self.config.PAYDAY_TIME.set(seconds) else: await self.config.guild(guild).PAYDAY_TIME.set(seconds) - await ctx.send("Value modified. At least {} seconds must pass " - "between each payday.".format(seconds)) + await ctx.send(_("Value modified. At least {} seconds must pass " + "between each payday.").format(seconds)) @economyset.command() async def paydayamount(self, ctx: commands.Context, creds: int): @@ -486,14 +489,14 @@ class Economy: guild = ctx.guild credits_name = await bank.get_currency_name(guild) if creds <= 0: - await ctx.send("Har har so funny.") + await ctx.send(_("Har har so funny.")) return if await bank.is_global(): await self.config.PAYDAY_CREDITS.set(creds) else: await self.config.guild(guild).PAYDAY_CREDITS.set(creds) - await ctx.send("Every payday will now give {} {}." - "".format(creds, credits_name)) + await ctx.send(_("Every payday will now give {} {}." + "").format(creds, credits_name)) @economyset.command() async def registeramount(self, ctx: commands.Context, creds: int): @@ -503,17 +506,17 @@ class Economy: creds = 0 credits_name = await bank.get_currency_name(guild) await bank.set_default_balance(creds, guild) - await ctx.send("Registering an account will now give {} {}." - "".format(creds, credits_name)) + await ctx.send(_("Registering an account will now give {} {}." + "").format(creds, credits_name)) # What would I ever do without stackoverflow? def display_time(self, seconds, granularity=2): intervals = ( # Source: http://stackoverflow.com/a/24542445 - ('weeks', 604800), # 60 * 60 * 24 * 7 - ('days', 86400), # 60 * 60 * 24 - ('hours', 3600), # 60 * 60 - ('minutes', 60), - ('seconds', 1), + (_('weeks'), 604800), # 60 * 60 * 24 * 7 + (_('days'), 86400), # 60 * 60 * 24 + (_('hours'), 3600), # 60 * 60 + (_('minutes'), 60), + (_('seconds'), 1), ) result = [] diff --git a/cogs/economy/locales/messages.pot b/cogs/economy/locales/messages.pot new file mode 100644 index 000000000..1efbf3b76 --- /dev/null +++ b/cogs/economy/locales/messages.pot @@ -0,0 +1,199 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , 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 \n" +"Language-Team: LANGUAGE \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 "" + diff --git a/cogs/general/general.py b/cogs/general/general.py index ab361c13c..9199e19a8 100644 --- a/cogs/general/general.py +++ b/cogs/general/general.py @@ -1,5 +1,6 @@ from discord.ext import commands from core.utils.chat_formatting import escape, italics, pagify +from core.i18n import CogI18n from random import randint, choice from enum import Enum from urllib.parse import quote_plus @@ -8,6 +9,8 @@ import datetime import time import aiohttp +_ = CogI18n("General", __file__) + class RPS(Enum): rock = "\N{MOYAI}" @@ -34,13 +37,13 @@ class General: def __init__(self): self.stopwatches = {} self.ball = [ - "As I see it, yes", "It is certain", "It is decidedly so", - "Most likely", "Outlook good", "Signs point to yes", - "Without a doubt", "Yes", "Yes – definitely", "You may rely on it", - "Reply hazy, try again", "Ask again later", - "Better not tell you now", "Cannot predict now", - "Concentrate and ask again", "Don't count on it", "My reply is no", - "My sources say no", "Outlook not so good", "Very doubtful" + _("As I see it, yes"), _("It is certain"), _("It is decidedly so"), + _("Most likely"), _("Outlook good"), _("Signs point to yes"), + _("Without a doubt"), _("Yes"), _("Yes – definitely"), _("You may rely on it"), + _("Reply hazy, try again"), _("Ask again later"), + _("Better not tell you now"), _("Cannot predict now"), + _("Concentrate and ask again"), _("Don't count on it"), _("My reply is no"), + _("My sources say no"), _("Outlook not so good"), _("Very doubtful") ] @commands.command(hidden=True) @@ -56,7 +59,7 @@ class General: """ choices = [escape(c, mass_mentions=True) for c in choices] if len(choices) < 2: - await ctx.send('Not enough choices to pick from.') + await ctx.send(_('Not enough choices to pick from.')) else: await ctx.send(choice(choices)) @@ -70,10 +73,10 @@ class General: if number > 1: n = randint(1, number) await ctx.send( - "{} :game_die: {} :game_die:".format(author.mention, n) + _("{} :game_die: {} :game_die:").format(author.mention, n) ) 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() async def flip(self, ctx, user: discord.Member=None): @@ -85,8 +88,8 @@ class General: msg = "" if user.id == ctx.bot.user.id: user = ctx.author - msg = "Nice try. You think this is funny?" +\ - "How about *this* instead:\n\n" + msg = _("Nice try. You think this is funny?" + "How about *this* instead:\n\n") char = "abcdefghijklmnopqrstuvwxyz" tran = "ɐqɔpǝɟƃɥᴉɾʞlɯuodbɹsʇnʌʍxʎz" table = str.maketrans(char, tran) @@ -98,7 +101,7 @@ class General: await ctx.send(msg + "(╯°□°)╯︵ " + name[::-1]) else: await ctx.send( - "*flips a coin and... " + choice(["HEADS!*", "TAILS!*"]) + _("*flips a coin and... ") + choice([_("HEADS!*"), _("TAILS!*")]) ) @commands.command() @@ -122,15 +125,15 @@ class General: outcome = cond[(player_choice, red_choice)] if outcome is True: - await ctx.send("{} You win {}!".format( + await ctx.send(_("{} You win {}!").format( red_choice.value, author.mention )) elif outcome is False: - await ctx.send("{} You lose {}!".format( + await ctx.send(_("{} You lose {}!").format( red_choice.value, author.mention )) else: - await ctx.send("{} We're square {}!".format( + await ctx.send(_("{} We're square {}!").format( red_choice.value, author.mention )) @@ -143,7 +146,7 @@ class General: if question.endswith("?") and question != "?": await ctx.send("`" + choice(self.ball) + "`") 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"]) async def stopwatch(self, ctx): @@ -151,11 +154,11 @@ class General: author = ctx.author if not author.id in self.stopwatches: self.stopwatches[author.id] = int(time.perf_counter()) - await ctx.send(author.mention + " Stopwatch started!") + await ctx.send(author.mention + _(" Stopwatch started!")) else: tmp = abs(self.stopwatches[author.id] - int(time.perf_counter())) 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) @commands.command() @@ -208,27 +211,27 @@ class General: member_number = sorted(guild.members, key=lambda m: m.joined_at).index(user) + 1 - created_on = "{}\n({} days ago)".format(user_created, since_created) - joined_on = "{}\n({} days ago)".format(user_joined, since_joined) + created_on = _("{}\n({} days ago)").format(user_created, since_created) + 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: - game = "Streaming: [{}]({})".format(user.game, user.game.url) + game = _("Streaming: [{}]({})").format(user.game, user.game.url) elif user.game and user.game.name: - game = "Playing {}".format(user.game) + game = _("Playing {}").format(user.game) if roles: roles = ", ".join([x.name for x in roles]) else: - roles = "None" + roles = _("None") data = discord.Embed(description=game, colour=user.colour) - 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="Roles", value=roles, inline=False) - data.set_footer(text="Member #{} | User ID: {}" - "".format(member_number, user.id)) + data.add_field(name=_("Joined Discord on"), value=created_on) + data.add_field(name=_("Joined this guild on"), value=joined_on) + data.add_field(name=_("Roles"), value=roles, inline=False) + data.set_footer(text=_("Member #{} | User ID: {}" + "").format(member_number, user.id)) name = str(user) name = " ~ ".join((name, user.nick)) if user.nick else name @@ -242,8 +245,8 @@ class General: try: await ctx.send(embed=data) except discord.HTTPException: - await ctx.send("I need the `Embed links` permission " - "to send this") + await ctx.send(_("I need the `Embed links` permission " + "to send this.")) @commands.command() @commands.guild_only() @@ -257,9 +260,9 @@ class General: text_channels = len(guild.text_channels) voice_channels = len(guild.voice_channels) passed = (ctx.message.created_at - guild.created_at).days - created_at = ("Since {}. That's over {} days ago!" - "".format(guild.created_at.strftime("%d %b %Y %H:%M"), - passed)) + created_at = (_("Since {}. That's over {} days ago!" + "").format(guild.created_at.strftime("%d %b %Y %H:%M"), + passed)) colour = ''.join([choice('0123456789ABCDEF') for x in range(6)]) colour = randint(0, 0xFFFFFF) @@ -267,13 +270,13 @@ class General: data = discord.Embed( description=created_at, colour=discord.Colour(value=colour)) - data.add_field(name="Region", value=str(guild.region)) - data.add_field(name="Users", value="{}/{}".format(online, total_users)) - data.add_field(name="Text Channels", value=text_channels) - data.add_field(name="Voice Channels", value=voice_channels) - data.add_field(name="Roles", value=len(guild.roles)) - data.add_field(name="Owner", value=str(guild.owner)) - data.set_footer(text="Server ID: " + str(guild.id)) + data.add_field(name=_("Region"), value=str(guild.region)) + data.add_field(name=_("Users"), value="{}/{}".format(online, total_users)) + data.add_field(name=_("Text Channels"), value=text_channels) + data.add_field(name=_("Voice Channels"), value=voice_channels) + data.add_field(name=_("Roles"), value=len(guild.roles)) + data.add_field(name=_("Owner"), value=str(guild.owner)) + data.set_footer(text=_("Guild ID: ") + str(guild.id)) if guild.icon_url: data.set_author(name=guild.name, url=guild.icon_url) @@ -284,8 +287,8 @@ class General: try: await ctx.send(embed=data) except discord.HTTPException: - await ctx.send("I need the `Embed links` permission " - "to send this") + await ctx.send(_("I need the `Embed links` permission " + "to send this.")) @commands.command() async def urban(self, ctx, *, search_terms: str, definition_number: int=1): @@ -328,8 +331,8 @@ class General: for page in msg: await ctx.send(page) else: - await ctx.send("Your search terms gave no results.") + await ctx.send(_("Your search terms gave no results.")) except IndexError: - await ctx.send("There is no definition #{}".format(pos+1)) + await ctx.send(_("There is no definition #{}").format(pos+1)) except: - await ctx.send("Error.") + await ctx.send(_("Error.")) diff --git a/cogs/general/locales/messages.pot b/cogs/general/locales/messages.pot new file mode 100644 index 000000000..139538d37 --- /dev/null +++ b/cogs/general/locales/messages.pot @@ -0,0 +1,233 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , 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 \n" +"Language-Team: LANGUAGE \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 "" + diff --git a/cogs/image/image.py b/cogs/image/image.py index 767d93c77..eaa2d6457 100644 --- a/cogs/image/image.py +++ b/cogs/image/image.py @@ -3,6 +3,9 @@ from random import shuffle import aiohttp from core import checks, Config +from core.i18n import CogI18n + +_ = CogI18n("Image", __file__) GIPHY_API_KEY = "dc6zaTOxFJmzC" @@ -42,16 +45,16 @@ class Image: if data["success"]: results = data["data"] if not results: - await ctx.send("Your search returned no results") + await ctx.send(_("Your search returned no results")) return shuffle(results) - msg = "Search results...\n" + msg = _("Search results...\n") for r in results[:3]: msg += r["gifv"] if "gifv" in r else r["link"] msg += "\n" await ctx.send(msg) 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") async def imgur_subreddit(self, ctx, subreddit: str, sort_type: str="top", window: str="day"): @@ -63,7 +66,7 @@ class Image: window = window.lower() 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 elif window not in ("day", "week", "month", "year", "all"): await self.bot.send_cmd_help(ctx) @@ -91,9 +94,9 @@ class Image: if links: await ctx.send("\n".join(links)) else: - await ctx.send("No results found.") + await ctx.send(_("No results found.")) 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() @commands.command() @@ -108,7 +111,7 @@ class Image: enter a description. Check the box for the captcha, then click Next. Your client ID will be on the page that loads""" 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) async def gif(self, ctx, *keywords): @@ -128,9 +131,9 @@ class Image: if result["data"]: await ctx.send(result["data"][0]["url"]) else: - await ctx.send("No results found.") + await ctx.send(_("No results found.")) else: - await ctx.send("Error contacting the API") + await ctx.send(_("Error contacting the API")) @commands.command(pass_context=True, no_pm=True) async def gifr(self, ctx, *keywords): @@ -150,6 +153,6 @@ class Image: if result["data"]: await ctx.send(result["data"]["url"]) else: - await ctx.send("No results found.") + await ctx.send(_("No results found.")) else: - await ctx.send("Error contacting the API") + await ctx.send(_("Error contacting the API")) diff --git a/cogs/image/locales/messages.pot b/cogs/image/locales/messages.pot new file mode 100644 index 000000000..e89a2823b --- /dev/null +++ b/cogs/image/locales/messages.pot @@ -0,0 +1,46 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , 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 \n" +"Language-Team: LANGUAGE \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 "" + diff --git a/core/cog_manager.py b/core/cog_manager.py index cf84b45ff..7f24f24dc 100644 --- a/core/cog_manager.py +++ b/core/cog_manager.py @@ -9,6 +9,7 @@ from discord.ext import commands from core import checks from core.config import Config from core.utils.chat_formatting import box +from core.i18n import CogI18n __all__ = ["CogManager"] @@ -178,6 +179,9 @@ class CogManager: invalidate_caches() +_ = CogI18n("CogManagerUI", __file__) + + class CogManagerUI: @commands.command() @checks.is_owner() @@ -189,7 +193,7 @@ class CogManagerUI: cog_paths = ctx.bot.cog_mgr.paths 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 = [] 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. """ if not path.is_dir(): - await ctx.send("That path is does not exist or does not" - " point to a valid directory.") + await ctx.send(_("That path is does not exist or does not" + " point to a valid directory.")) return try: @@ -214,7 +218,7 @@ class CogManagerUI: except ValueError as e: await ctx.send(str(e)) else: - await ctx.send("Path successfully added.") + await ctx.send(_("Path successfully added.")) @commands.command() @checks.is_owner() @@ -227,11 +231,11 @@ class CogManagerUI: try: to_remove = cog_paths[path_number] except IndexError: - await ctx.send("That is an invalid path number.") + await ctx.send(_("That is an invalid path number.")) return await ctx.bot.cog_mgr.remove_path(to_remove) - await ctx.send("Path successfully removed.") + await ctx.send(_("Path successfully removed.")) @commands.command() @checks.is_owner() @@ -247,17 +251,17 @@ class CogManagerUI: try: to_move = all_paths.pop(from_) except IndexError: - await ctx.send("Invalid 'from' index.") + await ctx.send(_("Invalid 'from' index.")) return try: all_paths.insert(to, to_move) except IndexError: - await ctx.send("Invalid 'to' index.") + await ctx.send(_("Invalid 'to' index.")) return await ctx.bot.cog_mgr.set_paths(all_paths) - await ctx.send("Paths reordered.") + await ctx.send(_("Paths reordered.")) @commands.command() @checks.is_owner() @@ -275,9 +279,9 @@ class CogManagerUI: try: await ctx.bot.cog_mgr.set_install_path(path) except ValueError: - await ctx.send("That path does not exist.") + await ctx.send(_("That path does not exist.")) return install_path = await ctx.bot.cog_mgr.install_path() - await ctx.send("The bot will install new cogs to the `{}`" - " directory.".format(install_path)) + await ctx.send(_("The bot will install new cogs to the `{}`" + " directory.").format(install_path)) diff --git a/core/core_commands.py b/core/core_commands.py index fae97591f..9679ee0cf 100644 --- a/core/core_commands.py +++ b/core/core_commands.py @@ -1,6 +1,7 @@ import itertools from discord.ext import commands from core import checks +from core import i18n from string import ascii_letters, digits from random import SystemRandom 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 " "system.** ⚠") +_ = i18n.CogI18n("Core", __file__) + class Core: """Commands related to core functions""" @@ -29,19 +32,19 @@ class Core: try: spec = await ctx.bot.cog_mgr.find_cog(cog_name) except RuntimeError: - await ctx.send("No module by that name was found in any" - " cog path.") + await ctx.send(_("No module by that name was found in any" + " cog path.")) return try: ctx.bot.load_extension(spec) except Exception as e: log.exception("Package loading failed", exc_info=e) - await ctx.send("Failed to load package. Check your console or " - "logs for details.") + await ctx.send(_("Failed to load package. Check your console or " + "logs for details.")) else: await ctx.bot.add_loaded_package(cog_name) - await ctx.send("Done.") + await ctx.send(_("Done.")) @commands.group() @checks.is_owner() @@ -50,9 +53,9 @@ class Core: if cog_name in ctx.bot.extensions: ctx.bot.unload_extension(cog_name) await ctx.bot.remove_loaded_package(cog_name) - await ctx.send("Done.") + await ctx.send(_("Done.")) else: - await ctx.send("That extension is not loaded.") + await ctx.send(_("That extension is not loaded.")) @commands.command(name="reload") @checks.is_owner() @@ -65,12 +68,12 @@ class Core: ctx.bot.load_extension(spec) except Exception as e: log.exception("Package reloading failed", exc_info=e) - await ctx.send("Failed to reload package. Check your console or " - "logs for details.") + await ctx.send(_("Failed to reload package. Check your console or " + "logs for details.")) else: curr_pkgs = await ctx.bot.db.packages() await ctx.bot.save_packages_status(curr_pkgs) - await ctx.send("Done.") + await ctx.send(_("Done.")) @commands.command(name="shutdown") @checks.is_owner() @@ -80,7 +83,7 @@ class Core: skin = "\N{EMOJI MODIFIER FITZPATRICK TYPE-3}" try: # We don't want missing perms to stop our shutdown if not silently: - await ctx.send("Shutting down... " + wave + skin) + await ctx.send(_("Shutting down... ") + wave + skin) except: pass await ctx.bot.shutdown() @@ -117,7 +120,7 @@ class Core: async def adminrole(self, ctx, *, role: discord.Role): """Sets the admin role for this server""" 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() @checks.guildowner() @@ -125,7 +128,7 @@ class Core: async def modrole(self, ctx, *, role: discord.Role): """Sets the mod role for this server""" 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() @checks.is_owner() @@ -139,13 +142,13 @@ class Core: try: await ctx.bot.user.edit(avatar=data) except discord.HTTPException: - await ctx.send("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.") + await ctx.send(_("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.")) except discord.InvalidArgument: - await ctx.send("JPG / PNG format only.") + await ctx.send(_("JPG / PNG format only.")) else: - await ctx.send("Done.") + await ctx.send(_("Done.")) @_set.command(name="game") @checks.is_owner() @@ -155,7 +158,7 @@ class Core: status = ctx.me.status game = discord.Game(name=game) await ctx.bot.change_presence(status=status, game=game) - await ctx.send("Game set.") + await ctx.send(_("Game set.")) @_set.command() @checks.is_owner() @@ -184,7 +187,7 @@ class Core: else: await ctx.bot.change_presence(status=status, game=game) - await ctx.send("Status changed to %s." % status) + await ctx.send(_("Status changed to %s.") % status) @_set.command() @checks.is_owner() @@ -206,7 +209,7 @@ class Core: return else: await ctx.bot.change_presence(game=None, status=status) - await ctx.send("Done.") + await ctx.send(_("Done.")) @_set.command(name="username", aliases=["name"]) @checks.is_owner() @@ -215,12 +218,12 @@ class Core: try: await ctx.bot.user.edit(username=username) except discord.HTTPException: - await ctx.send("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`".format(ctx.prefix)) + await ctx.send(_("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`").format(ctx.prefix)) else: - await ctx.send("Done.") + await ctx.send(_("Done.")) @_set.command(name="nickname") @checks.admin() @@ -230,8 +233,8 @@ class Core: try: await ctx.bot.user.edit(nick=nickname) except discord.Forbidden: - await ctx.send("I lack the permissions to change my own " - "nickname.") + await ctx.send(_("I lack the permissions to change my own " + "nickname.")) else: await ctx.send("Done.") @@ -244,7 +247,7 @@ class Core: return prefixes = sorted(prefixes, reverse=True) await ctx.bot.db.prefix.set(prefixes) - await ctx.send("Prefix set.") + await ctx.send(_("Prefix set.")) @_set.command(aliases=["serverprefixes"]) @checks.admin() @@ -253,11 +256,11 @@ class Core: """Sets Red's server prefix(es)""" if not prefixes: 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 prefixes = sorted(prefixes, reverse=True) await ctx.bot.db.guild(ctx.guild).prefix.set(prefixes) - await ctx.send("Prefix set.") + await ctx.send(_("Prefix set.")) @_set.command() @commands.cooldown(1, 60 * 10, commands.BucketType.default) @@ -276,29 +279,38 @@ class Core: token += random.choice(chars) log.info("{0} ({0.id}) requested to be set as owner." "".format(ctx.author)) - print("\nVerification token:") + print(_("\nVerification token:")) print(token) - await ctx.send("Remember:\n" + OWNER_DISCLAIMER) + await ctx.send(_("Remember:\n") + OWNER_DISCLAIMER) await asyncio.sleep(5) - await ctx.send("I have printed a one-time token in the console. " - "Copy and paste it here to confirm you are the owner.") + await ctx.send(_("I have printed a one-time token in the console. " + "Copy and paste it here to confirm you are the owner.")) try: message = await ctx.bot.wait_for("message", check=check, timeout=60) except asyncio.TimeoutError: 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: if message.content.strip() == token: self.owner.reset_cooldown(ctx) await ctx.bot.db.owner.set(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: - 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.cooldown(1, 60, commands.BucketType.user) @@ -308,13 +320,13 @@ class Core: owner = discord.utils.get(ctx.bot.get_all_members(), id=ctx.bot.owner_id) author = ctx.message.author - footer = "User ID: %s" % author.id + footer = _("User ID: %s") % author.id if ctx.guild is None: - source = "through DM" + source = _("through DM") else: - source = "from {}".format(guild) - footer += " | Server ID: %s" % guild.id + source = _("from {}").format(guild) + footer += _(" | Server ID: %s") % guild.id # We need to grab the DM command prefix (global) # 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') prefix = ctx.bot.command_prefix(ctx.bot, fake_message(guild=None))[0] - content = ("Use `{}dm {} ` to reply to this user" - "".format(prefix, author.id)) + content = _("Use `{}dm {} ` to reply to this user" + "").format(prefix, author.id) if isinstance(author, discord.Member): colour = author.colour else: colour = discord.Colour.red() - description = "Sent by {} {}".format(author, source) + description = _("Sent by {} {}").format(author, source) e = discord.Embed(colour=colour, description=message) if author.avatar_url: @@ -342,12 +354,12 @@ class Core: try: await owner.send(content, embed=e) except discord.InvalidArgument: - await ctx.send("I cannot send your message, I'm unable to find " - "my owner... *sigh*") + await ctx.send(_("I cannot send your message, I'm unable to find " + "my owner... *sigh*")) except: - await ctx.send("I'm unable to deliver your message. Sorry.") + await ctx.send(_("I'm unable to deliver your message. Sorry.")) else: - await ctx.send("Your message has been sent.") + await ctx.send(_("Your message has been sent.")) @commands.command() @checks.is_owner() @@ -361,17 +373,17 @@ class Core: destination = discord.utils.get(ctx.bot.get_all_members(), id=user_id) if destination is None: - await ctx.send("Invalid ID or user not found. You can only " - "send messages to people I share a server " - "with.") + await ctx.send(_("Invalid ID or user not found. You can only " + "send messages to people I share a server " + "with.")) return 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') prefix = ctx.bot.command_prefix(ctx.bot, fake_message(guild=None))[0] - e.set_footer(text=("You can reply to this message with %scontact" - "" % prefix)) + e.set_footer(text=_("You can reply to this message with %scontact" + "") % prefix) if ctx.bot.user.avatar_url: e.set_author(name=description, icon_url=ctx.bot.user.avatar_url) else: @@ -380,7 +392,7 @@ class Core: try: await destination.send(embed=e) except: - await ctx.send("Sorry, I couldn't deliver your message " - "to %s" % destination) + await ctx.send(_("Sorry, I couldn't deliver your message " + "to %s") % destination) else: - await ctx.send("Message delivered to %s" % destination) + await ctx.send(_("Message delivered to %s") % destination) diff --git a/core/dev_commands.py b/core/dev_commands.py index 1d03dbf50..921ff5c08 100644 --- a/core/dev_commands.py +++ b/core/dev_commands.py @@ -1,6 +1,7 @@ from discord.ext import commands from core.utils.chat_formatting import box, pagify from core import checks +from core.i18n import CogI18n import asyncio import discord import traceback @@ -18,6 +19,8 @@ Notice: https://github.com/Rapptz/RoboDanny/blob/master/cogs/repl.py """ +_ = CogI18n("Dev", __file__) + class Dev: """Various development focused utilities""" @@ -159,11 +162,11 @@ class Dev: } 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 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): return m.author == ctx.author and m.channel == ctx.channel and \ @@ -228,7 +231,7 @@ class Dev: except discord.Forbidden: pass except discord.HTTPException as e: - await ctx.send('Unexpected error: `{}`'.format(e)) + await ctx.send(_('Unexpected error: `{}`').format(e)) @commands.command() @checks.is_owner() diff --git a/core/i18n.py b/core/i18n.py new file mode 100644 index 000000000..e4a2dce8f --- /dev/null +++ b/core/i18n.py @@ -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}) + diff --git a/core/locales/messages.pot b/core/locales/messages.pot new file mode 100644 index 000000000..6d1a1e30c --- /dev/null +++ b/core/locales/messages.pot @@ -0,0 +1,223 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , 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 \n" +"Language-Team: LANGUAGE \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 {} ` 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 "" + diff --git a/core/locales/regen_messages.py b/core/locales/regen_messages.py new file mode 100644 index 000000000..5b24765af --- /dev/null +++ b/core/locales/regen_messages.py @@ -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() \ No newline at end of file