diff --git a/.gitignore b/.gitignore index fb2b897..4a9dbac 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ lastchange.txt /venv/ /lokalize-scripts/ /venvv/ +/.idea/ __pycache__ *.bat *.code-workspace diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a25256c..0edcec6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,17 +1,47 @@ -image: python:3.6-alpine +image: python:3.7-alpine include: - template: Code-Quality.gitlab-ci.yml +variables: + PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" + +stages: + - test + - pytest + +cache: + paths: + - settings.json + - .cache/pip + - venv/ + test: - type: test + stage: test script: - apk add libxml2-dev libxslt-dev libxml2 gcc musl-dev linux-headers - - pip3.6 install -r requirements.txt + - pip3.7 install virtualenv + - virtualenv venv + - source venv/bin/activate + - pip3.7 install -r requirements.txt - sed -i -e "s/111111111111111111/$DISCORD1/g" settings.json.example - sed -i -e "s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/$DISCORD2/g" settings.json.example - mv settings.json.example settings.json - - python3.6 start.py --test + - python3.7 start.py --test only: - testing - - merge_requests + +pytest: + stage: pytest + needs: ['test'] + script: + - source venv/bin/activate + - pip3.7 install -U pytest + - pytest --junitxml=report.xml + artifacts: + when: always + reports: + junit: report.xml + only: + - testing + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3395c0d..6594a82 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,4 +9,4 @@ If you contribute, I ask of you to create merge requests based on testing branch `testing `- testing branch is what all of my hosted scripts run. It is used to test the code before merging it with master branch. ## Translations ## -If you speak in other languages than English, you are more than welcome to. There are several ways you can contribute your translation, first the easiest one is to signup at [our weblate instance](https://weblate.frisk.space) and [contact me directly with request to review your account](https://minecraft.gamepedia.com/User:Frisk#Contact). You can also contact me so I send you the translation files you can fill in. If you know how .po files work, you are also free to send Merge Requests with translated files. +If you speak in other languages than English, you are more than welcome to. There are several ways you can contribute your translation, first the easiest one is to signup at [our weblate instance](https://translate.wikibot.de) and [contact me directly with request to review your account](https://minecraft.gamepedia.com/User:Frisk#Contact). You can also contact me so I send you the translation files you can fill in. If you know how .po files work, you are also free to send Merge Requests with translated files. diff --git a/README.md b/README.md index 43e3088..5e82978 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ * Very customizable ### Dependencies ### -* **Python 3.6+** +* **Python 3.7+** * requests 2.18.4+ * beautifulsoup 4.6.0+ * schedule 0.5.0+ @@ -31,15 +31,23 @@ * MarkusRost – German translation * JSBM – French translation * [Eduaddad](https://eduardoaddad.com.br) – Brazilian Portuguese translation -* BabylonAS and Russian Minecraft Wiki community – Russian translation +* BabylonAS, Philo and Russian Minecraft Wiki community – Russian translation * Mak_and_Iv – Ukrainian translation +* Tamara Carvallo – Spanish translation +* Lakejason0 - Simplified Chinese translation Thank you! -[![Translation status](https://weblate.frisk.space/widgets/rcgcdw/-/multi-auto.svg)](https://weblate.frisk.space/engage/rcgcdw/?utm_source=widget) +[![Translation status](https://translate.wikibot.de/widgets/rcgcdw/-/multi-auto.svg)](https://translate.wikibot.de/engage/rcgcdw/?utm_source=widget) -### Other extensions/compatible programs ### +### Extensions/compatible programs ### * [Wiki Utilities](https://github.com/Sidemen19/Wiki-Utilities) – an integration that allows wiki administrators to revert edits, block editors, and delete pages on the wiki by reacting to messages created by RcGcDw/RcGcDb. Author: [Sidemen19](https://github.com/Sidemen19) +### Alternatives ### +There are various alternatives to RcGcDw you may want to consider if for some reason RcGcDw doesn't satisfy your needs: +* [Wiki-Bot](https://wiki.wikibot.de/wiki/Wiki-Bot_Wiki) - while it's not exactly an alternative since Wiki-Bot is running a modified version of RcGcDw in the backend, you can use its rcscript feature to add a webhook for your wiki and have it work similarly to how RcGcDw does without hosting anything on your own, +* [Extension:Discord](https://www.mediawiki.org/wiki/Extension:Discord) - MediaWiki extension to do the same thing, +* [Extension:DiscordNotifications](https://www.mediawiki.org/wiki/Extension:DiscordNotifications) - another MediaWiki extension with the same goal. + ### Wiki ### For more information, check the [wiki](https://gitlab.com/piotrex43/RcGcDw/wikis/Home)! \ No newline at end of file diff --git a/docs/API spec.md b/docs/API spec.md new file mode 100644 index 0000000..4e331bb --- /dev/null +++ b/docs/API spec.md @@ -0,0 +1,151 @@ +## About +This is a specification for RcGcDw API extending formatters and allowing to add additional pre and post processing hooks for message contents. +This document assumes you have at least a basic understanding of Python, concept of classes, objects and decorators. + +### Pre-processing hook +A class allowing to change the raw event values obtained for a change via query.recentchanges endpoint on the wiki and/or execute additional actions each time given event gets read. This type of hook executes before a formatter. + +### Formatters +Formatters allow specifying how does a Discord message look like depending on message mode (embed, compact) and type of the event that had happened on the wiki (new, edit etc). +If formatter for given event is not registered, the script will look for formatter for event "generic" and if this is also not found it will throw a warning. + +### Post-processing hook +A class allowing to change the message content and/or execute additional actions after message has been processed by the formatter. This type of hook executes after a formatter. + +## File structure +Directory with extensions is specified by setting `extensions_dir` in settings.json. +The directory with hooks and formatters needs to be below root directory (directory in which start.py is located) and every directory inside it needs to be a Python package importing its child packages and modules. + +. +├── extensions +│   ├── base +│   │   ├── abusefilter.py +│   │   ├── my_formatters.py +│   │   ├── \_\_init\_\_.py +│   ├── hooks +│   │   ├── my_hooks.py +│   │   ├── \_\_init\_\_.py +│   ├── \_\_init\_\_.py +├── start.py + +## API +api object exposes various data which allows to extend the usefulness of what can be then sent to Discord. It also contains +common functions that can be used to interact with the script and the wiki. + +### Formatter +**Path**: `src.api.formatter` +_Formatter module implements two decorators: `embed` and `compact`. Both of them can take the following keyword arguments:_ +- `event` - string - event type for formatter, in case the event is a [log event](https://www.mediawiki.org/wiki/Manual:Log_actions) it's constructed by taking log_type and combining it with log_action with / character in between (for example `upload/overwrite`). If the event however is not a log event but action like edit, the type will consist only of `type` value. +- `aliases` - list[str] - list of strings containing all the events given event should alias for, it helps in case you want the same function be used for multiple event types. + +Both `event` and `aliases` arguments are optional in formatters. However, every formatter needs to have some kind of event specified. If it's not specified in the decorator, a fallback method will be used which constructs event type in format `{func.__module__}/{func.__name__.split("_", 1)[1]}`, in other terms taking the name of the file in which formatter is defined as first part and entire function name after first _ character as second part. Note that this fallback works only for log events. +There are also additional, made up event types that are special cases, they are listed below: +- `abuselog` – reserved for AbuseFilter filter logs +- `discussion/{post_type.lower()}` – reserved for Fandom's Discussion/Feeds integration +- `suppressed` – reserved for logs that were [suppressed](https://www.mediawiki.org/wiki/Special:MyLanguage/Help:RevisionDelete) and cannot be read by the script + +Formatter decorator registers a Python function and calls it each time a specific event is being processed from the wiki. Function is then called with Context and change arguments where context is [Context object](#Context) and change is a dict object containing the body of a change. +Every formatter **must** return a DiscordMessage object. + +#### Usage + +```python +from src.discord.message import DiscordMessage +from src.api import formatter +from src.i18n import formatters_i18n +from src.api.context import Context +from src.api.util import embed_helper, compact_author, create_article_path, sanitize_to_markdown, sanitize_to_url, \ + clean_link + +# Setup translation function which is used to translate english strings to other languages +_ = formatters_i18n.gettext + +# Call a decorator and register embed_sprite_sprite function for all sprite/sprite events +@formatter.embed(event="sprite/sprite") +def embed_sprite_sprite(ctx: Context, change: dict) -> DiscordMessage: + # Create DiscordMessage object which constructs Discord embed content + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + # embed_helper function can be used to automatically populate DiscordMessage object with some common useful information such as setting author name/url, adding fields for tags/categories, or setting default description + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Edited the sprite for {article}").format(article=sanitize_to_markdown(change["title"])) + # return populated DiscordMessage object + return embed + + +@formatter.compact(event="sprite/sprite") +def compact_sprite_sprite(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _("[{author}]({author_url}) edited the sprite for [{article}]({article_url})").format(author=author, + author_url=author_url, + article=sanitize_to_markdown(change[ + "title"]), + article_url=link) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) +``` + +### Client +**Path**: `src.api.client.Client` +_Client is a class containing most of usable methods and communication layer with the core functionality._ +Client consists of the following fields: +- `WIKI_API_PATH` - string - URL path leading to API (`WIKI_DOMAIN/api.php`) +- `WIKI_ARTICLE_PATH` - string - URL path leading to article path (`WIKI_DOMAIN/articlepath`) +- `WIKI_SCRIPT_PATH` - string - URL path leading to script path of the wiki (`WIKI_DOMAIN/`) +- `WIKI_JUST_DOMAIN` - string - URL path leading just to the wiki domain (`WIKI_DOMAIN`) +- `content_parser` - class - a reference to HTMLParser implementation that parses edit diffs +- `tags` - dict - a container storing all [tags](https://www.mediawiki.org/wiki/Manual:Tags) the wiki has configured +- `namespaces` - dict - a dictionary of [namespaces](https://www.mediawiki.org/wiki/Manual:Namespace) on the wiki +- `LinkParser` - class - a class of LinkParser which is usually used to parse parsed_comment from events including turning URLs into Markdown links +Client consists of the following methods: +- `refresh_internal_data()` - requests namespaces, tags and MediaWiki messages to be retrieved and updated in internal storage +- `parse_links(text: str)` - parses links using LinkParser object +- `pull_curseprofile_comment(comment_id: Union[str, int])` - allows retrieving CurseProfile comment from wikis originated from Gamepedia +- `make_api_request(params: Union[str, OrderedDict], *json_path: str, timeout: int = 10, allow_redirects: bool = False)` - allows to make a request to the wiki with parameters specified in params argument, json_path additionally allows to provide a list of strings that will be iterated over and json path of the result of this iteration returned. Timeout in float (seconds) can be added to limit the time for response, allow_redirects can be set to disallow or allow redirects +- `get_formatters()` - returns a dictionary of all formatters in format of `{'eventtype': func}` +- `get_ipmapper()` - returns ip mapper which tracks edit counts of IP editors + +### Context +**Path**: `src.api.context.Context` +_Context is a class which objects of are only used as first argument of formatter definitions._ +Context can consist of the following fields: +- `client` - [Client](#Client) object +- `webhook_url` - string - webhook url for given formatter +- `message_type` - string - can be either `embed` or `compact` +- `categories` - {"new": set(), "removed": set()} - each set containing strings of added or removed categories for given page +- `parsedcomment` - string - contains escaped and Markdown parsed summary (parsed_comment) of a log/edit action +- `event` - string - action called, should be the same as formatter event action +- `comment_page` - dict - containing `fullUrl` and `article` with strings both to full article url and its name + +### Util +**Path**: `src.api.util` +_Util is a module with a few common functions that can be useful for generating Discord messages, parsing changes in formatting and more._ +Util provides the following functionalities: +- `clean_link(link: str)` – returns a string wrapped with <> brackets, so the link given as a string doesn't embed in Discord +- `sanitize_to_markdown(text: str)` – returns a string with Discord Markdown characters escaped +- `sanitize_to_url(text: str)` – returns a string that should be safe to be part of URL with special characters either escaped or encoded +- `parse_mediawiki_changes(ctx: Context, content: str, embed: DiscordMessage)` – populates embed with two new fields "Added" and "Removed" containing diff of changes within content argument retrieved using action=compare request between two revisions +- `create_article_path(article: str)` – returns a string with URL leading to an article page (basically taking into account wiki's article path) +- `compact_author(ctx: Context, content: dict)` – returns two strings - first containing the name of the author with hide_ips setting taken into account and second a URL leading to author's contribution page, this makes it easier for compact formatters to include author detail in messages +- `embed_helper(ctx: Context, message: DiscordMessage, change: dict, set_user=True, set_edit_meta=True, set_desc=True)` – a function populating the message (Discord embed message) with most essential fields accordingly. Populating includes the following fields: author, author_url, category and tags fields, description + +### DiscordMessage +**Path**: `src.discord.message.DiscordMessage` +_DiscordMessage is a class taking care of creation of Discord messages that can be sent via send_to_discord function later on._ +DiscordMessage object when created with message_type == embed will take all assignments and reads using object[key] as ones reading/setting the actual embed object. +DiscordMessage consists of the following: +- `__init__(message_type: str, event_type: str, webhook_url: str, content=None)` – constructor which takes message type (can be either `embed` or `compact`), event_type (for example `protect/protect`), webhook_url (full URL of webhook message is intended to be sent to), content optional parameter used in compact messages as main body +- `set_author(name, url, icon_url="")` – a method that can be used to set username, URL to their profile and optionally an icon for the embed +- `add_field(name, value, inline=False)` – a method to add a field with given name and value, optional inline argument can be set if field should be inline +- `set_avatar(url)` – sets avatar for WEBHOOK MESSAGE (not to be confused with actual embed) +- `set_name(name)` – sets name for WEBHOOK MESSAGE +- `set_link(link)` – equivalent to object["link"] = link for embed messages + +### Language support +RcGcDw implements i18n with gettext and already exposes Translations instance with its `src.i18` module. formatters_i18n variable is used for instance of all formatters inside base directory. + +### Pre/post hooks +**Path**: `src.api.hook` +There are two decorator functions available in the module: `pre_hook` and `post_hook`. They don't take arguments and simply register the function as a hook. +Pre-hook functions take the following arguments: `context` ([Context object](#Context)) and `change` (dict object with change). +Post-hook functions take the following arguments: `message` ([Discord message object](#DiscordMessage)), `metadata` ([Discord message metadata](#DiscordMessageMetadata)), `context` ([Context object](#Context)) and `change` (dictionary of main change body) \ No newline at end of file diff --git a/extensions/__init__.py b/extensions/__init__.py new file mode 100644 index 0000000..c2cc1c1 --- /dev/null +++ b/extensions/__init__.py @@ -0,0 +1,17 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +import extensions.base +import extensions.hooks \ No newline at end of file diff --git a/extensions/base/__init__.py b/extensions/base/__init__.py new file mode 100644 index 0000000..e6ffd54 --- /dev/null +++ b/extensions/base/__init__.py @@ -0,0 +1,26 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +import extensions.base.mediawiki +import extensions.base.abusefilter +import extensions.base.managewiki +import extensions.base.cargo +import extensions.base.datadump +import extensions.base.sprite +import extensions.base.translate +import extensions.base.discussions +import extensions.base.curseprofile +import extensions.base.interwiki +import extensions.base.renameuser \ No newline at end of file diff --git a/extensions/base/abusefilter.py b/extensions/base/abusefilter.py new file mode 100644 index 0000000..d54226c --- /dev/null +++ b/extensions/base/abusefilter.py @@ -0,0 +1,125 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +import ipaddress +import logging +from src.discord.message import DiscordMessage +from src.api import formatter +from src.i18n import formatters_i18n +from src.api.context import Context +from src.api.util import embed_helper, sanitize_to_url, parse_mediawiki_changes, clean_link, compact_author, \ + create_article_path, sanitize_to_markdown +from src.configloader import settings + +_ = formatters_i18n.gettext +ngettext = formatters_i18n.ngettext + +abusefilter_results = {"": _("None"), "warn": _("Warning issued"), "block": _("**Blocked user**"), "tag": _("Tagged the edit"), "disallow": _("Disallowed the action"), "rangeblock": _("**IP range blocked**"), "throttle": _("Throttled actions"), "blockautopromote": _("Removed autoconfirmed group"), "degroup": _("**Removed from privileged groups**")} +abusefilter_actions = {"edit": _("Edit"), "upload": _("Upload"), "move": _("Move"), "stashupload": _("Stash upload"), "delete": _("Deletion"), "createaccount": _("Account creation"), "autocreateaccount": _("Auto account creation")} + +logger = logging.getLogger("extensions.base") + +# AbuseFilter - https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:AbuseFilter +# Processing Abuselog LOG events, separate from RC logs + +def abuse_filter_format_user(change): + author = change["user"] + if settings.get("hide_ips", False): + try: + ipaddress.ip_address(change["user"]) + except ValueError: + pass + else: + author = _("Unregistered user") + return author + + +@formatter.embed(event="abuselog") +def embed_abuselog(ctx: Context, change: dict): + action = "abuselog/{}".format(change["result"]) + embed = DiscordMessage(ctx.message_type, action, ctx.webhook_url) + author = abuse_filter_format_user(change) + embed["title"] = _("{user} triggered \"{abuse_filter}\"").format(user=author, abuse_filter=sanitize_to_markdown(change["filter"])) + embed.add_field(_("Performed"), abusefilter_actions.get(change["action"], _("Unknown"))) + embed.add_field(_("Action taken"), abusefilter_results.get(change["result"], _("Unknown"))) + embed.add_field(_("Title"), sanitize_to_markdown(change.get("title", _("Unknown")))) + return embed + + +@formatter.compact(event="abuselog") +def compact_abuselog(ctx: Context, change: dict): + action = "abuselog/{}".format(change["result"]) + author_url = clean_link(create_article_path("User:{user}".format(user=change["user"]))) + author = abuse_filter_format_user(change) + message = _("[{author}]({author_url}) triggered *{abuse_filter}*, performing the action \"{action}\" on *[{target}]({target_url})* - action taken: {result}.").format( + author=author, author_url=author_url, abuse_filter=sanitize_to_markdown(change["filter"]), + action=abusefilter_actions.get(change["action"], _("Unknown")), target=change.get("title", _("Unknown")), + target_url=clean_link(create_article_path(sanitize_to_url(change.get("title", _("Unknown"))))), + result=abusefilter_results.get(change["result"], _("Unknown"))) + return DiscordMessage(ctx.message_type, action, ctx.webhook_url, content=message) + +# abusefilter/modify - AbuseFilter filter modification + + +@formatter.embed(event="abusefilter/modify") +def embed_abuselog_modify(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path( + "Special:AbuseFilter/history/{number}/diff/prev/{historyid}".format(number=change["logparams"]['newId'], + historyid=change["logparams"]["historyId"])) + embed["title"] = _("Edited abuse filter number {number}").format(number=change["logparams"]['newId']) + return embed + + +@formatter.compact(event="abusefilter/modify") +def compact_abuselog_modify(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path( + "Special:AbuseFilter/history/{number}/diff/prev/{historyid}".format(number=change["logparams"]['newId'], + historyid=change["logparams"][ + "historyId"]))) + + content = _("[{author}]({author_url}) edited abuse filter [number {number}]({filter_url})").format(author=author, + author_url=author_url, + number=change[ + "logparams"][ + 'newId'], + filter_url=link) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# abusefilter/create - AbuseFilter filter creation + + +@formatter.embed(event="abusefilter/create") +def embed_abuselog_create(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path("Special:AbuseFilter/{number}".format(number=change["logparams"]['newId'])) + embed["title"] = _("Created abuse filter number {number}").format(number=change["logparams"]['newId']) + return embed + +@formatter.compact(event="abusefilter/create") +def compact_abuselog_create(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + link = clean_link( + create_article_path("Special:AbuseFilter/{number}".format(number=change["logparams"]['newId']))) + content = _("[{author}]({author_url}) created abuse filter [number {number}]({filter_url})").format(author=author, + author_url=author_url, + number=change[ + "logparams"][ + 'newId'], + filter_url=link) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) diff --git a/extensions/base/cargo.py b/extensions/base/cargo.py new file mode 100644 index 0000000..af7d484 --- /dev/null +++ b/extensions/base/cargo.py @@ -0,0 +1,115 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +import logging +import re +from src.discord.message import DiscordMessage +from src.api import formatter +from src.i18n import formatters_i18n +from src.api.context import Context +from src.api.util import embed_helper, compact_author, create_article_path, sanitize_to_markdown + +_ = formatters_i18n.gettext +ngettext = formatters_i18n.ngettext + + +# Cargo - https://www.mediawiki.org/wiki/Extension:Cargo +# cargo/createtable - Creation of Cargo table + +@formatter.embed(event="cargo/createtable") +def embed_cargo_createtable(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + table = re.search(r"\[(.*?)]\(<(.*?)>\)", ctx.client.parse_links(change["logparams"]["0"])) + embed["url"] = table.group(2) + embed["title"] = _("Created the Cargo table \"{table}\"").format(table=table.group(1)) + return embed + + +@formatter.compact(event="cargo/createtable") +def compact_cargo_createtable(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + table = re.search(r"\[(.*?)]\(<(.*?)>\)", ctx.client.parse_links(change["logparams"]["0"])) + content = _("[{author}]({author_url}) created the Cargo table \"{table}\"").format(author=author, + author_url=author_url, + table=table) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# cargo/recreatetable - Recreating a Cargo table + + +@formatter.embed(event="cargo/recreatetable") +def embed_cargo_recreatetable(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + table = re.search(r"\[(.*?)]\(<(.*?)>\)", ctx.client.parse_links(change["logparams"]["0"])) + embed["url"] = table.group(2) + embed["title"] = _("Recreated the Cargo table \"{table}\"").format(table=table.group(1)) + return embed + + +@formatter.compact(event="cargo/recreatetable") +def compact_cargo_recreatetable(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + table = re.search(r"\[(.*?)]\(<(.*?)>\)", ctx.client.parse_links(change["logparams"]["0"])) + content = _("[{author}]({author_url}) recreated the Cargo table \"{table}\"").format(author=author, + author_url=author_url, + table=table) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# cargo/replacetable - Replacing a Cargo table + + +@formatter.embed(event="cargo/replacetable") +def embed_cargo_replacetable(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + table = re.search(r"\[(.*?)]\(<(.*?)>\)", ctx.client.parse_links(change["logparams"]["0"])) + embed["url"] = table.group(2) + embed["title"] = _("Replaced the Cargo table \"{table}\"").format(table=table.group(1)) + return embed + + +@formatter.compact(event="cargo/replacetable") +def compact_cargo_replacetable(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + table = re.search(r"\[(.*?)]\(<(.*?)>\)", ctx.client.parse_links(change["logparams"]["0"])) + content = _("[{author}]({author_url}) replaced the Cargo table \"{table}\"").format(author=author, + author_url=author_url, + table=table) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# cargo/deletetable - Deleting a table in Cargo + + +@formatter.embed(event="cargo/deletetable") +def embed_cargo_deletetable(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path("Special:CargoTables") + embed["title"] = _("Deleted the Cargo table \"{table}\"").format(table=sanitize_to_markdown(change["logparams"]["0"])) + return embed + + +@formatter.compact(event="cargo/deletetable") +def compact_cargo_deletetable(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + content = _("[{author}]({author_url}) deleted the Cargo table \"{table}\"").format(author=author, + author_url=author_url, + table=sanitize_to_markdown(change["logparams"]["0"])) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) diff --git a/extensions/base/curseprofile.py b/extensions/base/curseprofile.py new file mode 100644 index 0000000..3582a79 --- /dev/null +++ b/extensions/base/curseprofile.py @@ -0,0 +1,234 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + + +import logging +from src.configloader import settings +from src.discord.message import DiscordMessage +from src.api import formatter +from src.i18n import formatters_i18n +from src.api.context import Context +from src.api.util import embed_helper, clean_link, compact_author, create_article_path, sanitize_to_markdown, sanitize_to_url +from src.misc import profile_field_name + +_ = formatters_i18n.gettext +ngettext = formatters_i18n.ngettext + + +# CurseProfile - https://help.fandom.com/wiki/Extension:CurseProfile +# curseprofile/profile-edited - Editing user profile + + +@formatter.embed(event="curseprofile/profile-edited") +def embed_curseprofile_profile_edited(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + target_user = change["title"].split(':', 1)[1] + if target_user != change["user"]: + embed["title"] = _("Edited {target}'s profile").format(target=sanitize_to_markdown(target_user)) + else: + embed["title"] = _("Edited their own profile") + if ctx.parsedcomment is None: # If the field is empty + embed["description"] = _("Cleared the {field} field").format(field=profile_field_name(change["logparams"]['4:section'], True)) + else: + embed["description"] = _("{field} field changed to: {desc}").format(field=profile_field_name(change["logparams"]['4:section'], True), desc=ctx.parsedcomment) + embed["url"] = create_article_path("UserProfile:" + sanitize_to_url(target_user)) + return embed + + +@formatter.compact(event="curseprofile/profile-edited") +def compact_curseprofile_profile_edited(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + target_user = change["title"].split(':', 1)[1] + link = clean_link(create_article_path("UserProfile:" + sanitize_to_url(target_user))) + if target_user != author: + if ctx.parsedcomment is None: # If the field is empty + edit_clear_message = _("[{author}]({author_url}) cleared the {field} on [{target}]({target_url})'s profile.") + else: + edit_clear_message = _("[{author}]({author_url}) edited the {field} on [{target}]({target_url})'s profile. *({desc})*") + content = edit_clear_message.format(author=author, author_url=author_url, target=sanitize_to_markdown(target_user), target_url=link, + field=profile_field_name(change["logparams"]['4:section'], False), desc=ctx.parsedcomment) + else: + if ctx.parsedcomment is None: # If the field is empty + edit_clear_message = _("[{author}]({author_url}) cleared the {field} on [their own]({target_url}) profile.") + else: + edit_clear_message = _("[{author}]({author_url}) edited the {field} on [their own]({target_url}) profile. *({desc})*") + content = edit_clear_message.format(author=author, author_url=author_url, target_url=link, + field=profile_field_name(change["logparams"]['4:section'], False), desc=ctx.parsedcomment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# curseprofile/comment-created - Creating comment on user profile + + +@formatter.embed(event="curseprofile/comment-created") +def embed_curseprofile_comment_created(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + target_user = change["title"].split(':', 1)[1] + if target_user != change["user"]: + embed["title"] = _("Left a comment on {target}'s profile").format(target=sanitize_to_markdown(target_user)) + else: + embed["title"] = _("Left a comment on their own profile") + if settings["appearance"]["embed"]["show_edit_changes"]: + embed["description"] = ctx.client.pull_curseprofile_comment(change["logparams"]["4:comment_id"]) + embed["url"] = create_article_path("Special:CommentPermalink/{commentid}".format(commentid=change["logparams"]["4:comment_id"])) + return embed + + +@formatter.compact(event="curseprofile/comment-created") +def compact_curseprofile_comment_created(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + target_user = change["title"].split(':', 1)[1] + link = clean_link(create_article_path("Special:CommentPermalink/{commentid}".format(commentid=change["logparams"]["4:comment_id"]))) + if target_user != author: + content = _("[{author}]({author_url}) left a [comment]({comment}) on {target}'s profile.").format( + author=author, author_url=author_url, comment=link, target=sanitize_to_markdown(target_user)) + else: + content = _("[{author}]({author_url}) left a [comment]({comment}) on their own profile.").format(author=author, author_url=author_url, comment=link) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# curseprofile/comment-edited - Editing comment on user profile + + +@formatter.embed(event="curseprofile/comment-edited") +def embed_curseprofile_comment_edited(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + target_user = change["title"].split(':', 1)[1] + if target_user != change["user"]: + embed["title"] = _("Edited a comment on {target}'s profile").format(target=sanitize_to_markdown(target_user)) + else: + embed["title"] = _("Edited a comment on their own profile") + if settings["appearance"]["embed"]["show_edit_changes"]: + embed["description"] = ctx.client.pull_curseprofile_comment(change["logparams"]["4:comment_id"]) + embed["url"] = create_article_path("Special:CommentPermalink/{commentid}".format(commentid=change["logparams"]["4:comment_id"])) + return embed + + +@formatter.compact(event="curseprofile/comment-edited") +def compact_curseprofile_comment_edited(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + target_user = change["title"].split(':', 1)[1] + link = clean_link(create_article_path("Special:CommentPermalink/{commentid}".format(commentid=change["logparams"]["4:comment_id"]))) + if target_user != author: + content = _("[{author}]({author_url}) edited a [comment]({comment}) on {target}'s profile.").format( + author=author, author_url=author_url, comment=link, target=sanitize_to_markdown(target_user)) + else: + content = _("[{author}]({author_url}) edited a [comment]({comment}) on their own profile.").format(author=author, author_url=author_url, comment=link) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# curseprofile/comment-replied - Replying to comment on user profile + + +@formatter.embed(event="curseprofile/comment-replied") +def embed_curseprofile_comment_replied(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + target_user = change["title"].split(':', 1)[1] + if target_user != change["user"]: + embed["title"] = _("Replied to a comment on {target}'s profile").format(target=sanitize_to_markdown(target_user)) + else: + embed["title"] = _("Replied to a comment on their own profile") + if settings["appearance"]["embed"]["show_edit_changes"]: + embed["description"] = ctx.client.pull_curseprofile_comment(change["logparams"]["4:comment_id"]) + embed["url"] = create_article_path("Special:CommentPermalink/{commentid}".format(commentid=change["logparams"]["4:comment_id"])) + return embed + + +@formatter.compact(event="curseprofile/comment-replied") +def compact_curseprofile_comment_replied(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + target_user = change["title"].split(':', 1)[1] + link = clean_link(create_article_path("Special:CommentPermalink/{commentid}".format(commentid=change["logparams"]["4:comment_id"]))) + if target_user != author: + content = _("[{author}]({author_url}) replied to a [comment]({comment}) on {target}'s profile.").format( + author=author, author_url=author_url, comment=link, target=sanitize_to_markdown(target_user)) + else: + content = _("[{author}]({author_url}) replied to a [comment]({comment}) on their own profile.").format(author=author, author_url=author_url, comment=link) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# curseprofile/comment-deleted - Deleting comment on user profile + + +@formatter.embed(event="curseprofile/comment-deleted") +def embed_curseprofile_comment_deleted(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + target_user = change["title"].split(':', 1)[1] + if target_user != change["user"]: + embed["title"] = _("Deleted a comment on {target}'s profile").format(target=sanitize_to_markdown(target_user)) + else: + embed["title"] = _("Deleted a comment on their own profile") + if ctx.parsedcomment is not None: + embed["description"] = ctx.parsedcomment + if "4:comment_id" in change["logparams"]: + embed["url"] = create_article_path("Special:CommentPermalink/{commentid}".format(commentid=change["logparams"]["4:comment_id"])) + else: + embed["url"] = create_article_path("UserProfile:" + sanitize_to_url(target_user)) + return embed + + +@formatter.compact(event="curseprofile/comment-deleted") +def compact_curseprofile_comment_deleted(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + target_user = change["title"].split(':', 1)[1] + if "4:comment_id" in change["logparams"]: + link = clean_link(create_article_path("Special:CommentPermalink/{commentid}".format(commentid=change["logparams"]["4:comment_id"]))) + else: + link = clean_link(create_article_path("UserProfile:" + sanitize_to_url(target_user))) + parsed_comment = "" if ctx.parsedcomment is None else " *(" + ctx.parsedcomment + ")*" + if target_user != author: + content = _("[{author}]({author_url}) deleted a [comment]({comment}) on {target}'s profile.{reason}").format( + author=author, author_url=author_url, comment=link, target=sanitize_to_markdown(target_user), reason=parsed_comment) + else: + content = _("[{author}]({author_url}) deleted a [comment]({comment}) on their own profile.{reason}").format( + author=author, author_url=author_url, comment=link, reason=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# curseprofile/comment-purged - Purging comment on user profile + + +@formatter.embed(event="curseprofile/comment-purged") +def embed_curseprofile_comment_purged(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + target_user = change["title"].split(':', 1)[1] + if target_user != change["user"]: + embed["title"] = _("Purged a comment on {target}'s profile").format(target=sanitize_to_markdown(target_user)) + else: + embed["title"] = _("Purged a comment on their own profile") + if ctx.parsedcomment is not None: + embed["description"] = ctx.parsedcomment + embed["url"] = create_article_path("UserProfile:" + sanitize_to_url(target_user)) + return embed + + +@formatter.compact(event="curseprofile/comment-purged") +def compact_curseprofile_comment_purged(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + target_user = change["title"].split(':', 1)[1] + link = clean_link(create_article_path("UserProfile:" + sanitize_to_url(target_user))) + parsed_comment = "" if ctx.parsedcomment is None else " *(" + ctx.parsedcomment + ")*" + if target_user != author: + content = _("[{author}]({author_url}) purged a comment on [{target}]({link})'s profile.{reason}").format( + author=author, author_url=author_url, link=link, target=sanitize_to_markdown(target_user), reason=parsed_comment) + else: + content = _("[{author}]({author_url}) purged a comment on [their own]({link}) profile.{reason}").format(author=author, author_url=author_url, link=link) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content, reason=parsed_comment) diff --git a/extensions/base/datadump.py b/extensions/base/datadump.py new file mode 100644 index 0000000..82eeae8 --- /dev/null +++ b/extensions/base/datadump.py @@ -0,0 +1,71 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + + +import logging +from src.discord.message import DiscordMessage +from src.api import formatter +from src.i18n import formatters_i18n +from src.api.context import Context +from src.api.util import embed_helper, compact_author, create_article_path, sanitize_to_markdown, sanitize_to_url, compact_summary + +_ = formatters_i18n.gettext +ngettext = formatters_i18n.ngettext + + +# DataDumps - https://www.mediawiki.org/wiki/Extension:DataDump +# datadump/generate - Generating a dump of wiki + + +@formatter.embed(event="datadump/generate") +def embed_datadump_generate(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["title"] = _("Generated {file} dump").format(file=change["logparams"]["filename"]) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + return embed + + +@formatter.compact(event="mdatadump/generate") +def compact_datadump_generate(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) generated *{file}* dump{comment}").format( + author=author, author_url=author_url, file=sanitize_to_markdown(change["logparams"]["filename"]), + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# datadump/delete - Deleting a dump of a wiki + + +@formatter.embed(event="datadump/delete") +def embed_datadump_delete(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["title"] = _("Deleted {file} dump").format(file=sanitize_to_markdown(change["logparams"]["filename"])) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + return embed + + +@formatter.compact(event="mdatadump/delete") +def compact_datadump_delete(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) deleted *{file}* dump{comment}").format( + author=author, author_url=author_url, file=sanitize_to_markdown(change["logparams"]["filename"]), + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) diff --git a/extensions/base/discussions.py b/extensions/base/discussions.py new file mode 100644 index 0000000..db609e5 --- /dev/null +++ b/extensions/base/discussions.py @@ -0,0 +1,368 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +# Discussions - Custom Fandom technology which apparently doesn't have any documentation or homepage, not even open-source, go figure + +import json +import datetime, logging +import gettext +from urllib.parse import quote_plus + +from src.configloader import settings +from src.api.util import create_article_path, clean_link, sanitize_to_markdown +from src.api.context import Context +from src.discord.queue import send_to_discord +from src.discord.message import DiscordMessage, DiscordMessageMetadata +from src.api import formatter +from src.i18n import formatters_i18n + +_ = formatters_i18n.gettext + + +logger = logging.getLogger("rcgcdw.discussion_formatter") + + +class DiscussionsFromHellParser: + """This class converts fairly convoluted Fandom jsonModal of a discussion post into Markdown formatted usable thing. + Takes string, returns string. Kudos to MarkusRost for allowing me to implement this formatter based on his code in Wiki-Bot.""" + + def __init__(self, post): + self.post = post + self.jsonModal = json.loads(post.get("jsonModel", "{}")) + self.markdown_text = "" + self.item_num = 1 + self.image_last = None + + def parse(self) -> str: + """Main parsing logic""" + self.parse_content(self.jsonModal["content"]) + if len(self.markdown_text) > 2000: + self.markdown_text = self.markdown_text[0:2000] + "…" + return self.markdown_text + + def parse_content(self, content, ctype=None): + self.image_last = None + for item in content: + if ctype == "bulletList": + self.markdown_text += "\t• " + if ctype == "orderedList": + self.markdown_text += "\t{num}. ".format(num=self.item_num) + self.item_num += 1 + if item["type"] == "text": + if "marks" in item: + prefix, suffix = self.convert_marks(item["marks"]) + self.markdown_text = "{old}{pre}{text}{suf}".format(old=self.markdown_text, pre=prefix, + text=sanitize_to_markdown(item["text"]), + suf=suffix) + else: + if ctype == "code_block": + self.markdown_text += item["text"] # ignore formatting on preformatted text which cannot have additional formatting anyways + else: + self.markdown_text += sanitize_to_markdown(item["text"]) + elif item["type"] == "paragraph": + if "content" in item: + self.parse_content(item["content"], item["type"]) + self.markdown_text += "\n" + elif item["type"] == "openGraph": + if not item["attrs"]["wasAddedWithInlineLink"]: + self.markdown_text = "{old}{link}\n".format(old=self.markdown_text, link=item["attrs"]["url"]) + elif item["type"] == "image": + try: + logger.debug(item["attrs"]["id"]) + if item["attrs"]["id"] is not None: + self.markdown_text = "{old}{img_url}\n".format(old=self.markdown_text, img_url= + self.post["_embedded"]["contentImages"][int(item["attrs"]["id"])]["url"]) + self.image_last = self.post["_embedded"]["contentImages"][int(item["attrs"]["id"])]["url"] + except (IndexError, ValueError): + logger.warning("Image {} not found.".format(item["attrs"]["id"])) + logger.debug(self.markdown_text) + elif item["type"] == "code_block": + self.markdown_text += "```\n" + if "content" in item: + self.parse_content(item["content"], item["type"]) + self.markdown_text += "\n```\n" + elif item["type"] == "bulletList": + if "content" in item: + self.parse_content(item["content"], item["type"]) + elif item["type"] == "orderedList": + self.item_num = 1 + if "content" in item: + self.parse_content(item["content"], item["type"]) + elif item["type"] == "listItem": + self.parse_content(item["content"], item["type"]) + + @staticmethod + def convert_marks(marks): + prefix = "" + suffix = "" + for mark in marks: + if mark["type"] == "mention": + prefix += "[" + suffix = "]({wiki}f/u/{userid}){suffix}".format(wiki=settings["fandom_discussions"]["wiki_url"], + userid=mark["attrs"]["userId"], suffix=suffix) + elif mark["type"] == "strong": + prefix += "**" + suffix = "**{suffix}".format(suffix=suffix) + elif mark["type"] == "link": + prefix += "[" + suffix = "]({link}){suffix}".format(link=mark["attrs"]["href"], suffix=suffix) + elif mark["type"] == "em": + prefix += "_" + suffix = "_" + suffix + return prefix, suffix + + +def common_discussions(post: dict, embed: DiscordMessage): + """A method to setup embeds with common info shared between all types of discussion posts""" + if settings["fandom_discussions"]["appearance"]["embed"]["show_content"]: + if post.get("jsonModel") is not None: + npost = DiscussionsFromHellParser(post) + embed["description"] = npost.parse() + if npost.image_last: + embed["image"]["url"] = npost.image_last + embed["description"] = embed["description"].replace(npost.image_last, "") + else: # Fallback when model is not available + embed["description"] = post.get("rawContent", "") + embed["footer"]["text"] = post["forumName"] + embed["timestamp"] = datetime.datetime.fromtimestamp(post["creationDate"]["epochSecond"], + tz=datetime.timezone.utc).isoformat() + +# discussion/forum - Discussions on the "forum" available via "Discuss" button + +@formatter.embed(event="discussion/forum") +def embed_discussion_forum(ctx: Context, post: dict): + embed = DiscordMessage("embed", "discussion", settings["fandom_discussions"]["webhookURL"]) + common_discussions(post, embed) + author = _("unknown") # Fail safe + if post["createdBy"]["name"]: + author = post["createdBy"]["name"] + embed.set_author(author, "{url}f/u/{creatorId}".format(url=settings["fandom_discussions"]["wiki_url"], + creatorId=post["creatorId"]), + icon_url=post["createdBy"]["avatarUrl"]) + if not post["isReply"]: + embed["url"] = "{url}f/p/{threadId}".format(url=settings["fandom_discussions"]["wiki_url"], + threadId=post["threadId"]) + embed["title"] = _("Created \"{title}\"").format(title=post["title"]) + thread_funnel = post.get("funnel") + if thread_funnel == "POLL": + embed.event_type = "discussion/forum/poll" + embed["title"] = _("Created a poll \"{title}\"").format(title=post["title"]) + if settings["fandom_discussions"]["appearance"]["embed"]["show_content"]: + poll = post["poll"] + image_type = False + if poll["answers"][0]["image"] is not None: + image_type = True + for num, option in enumerate(poll["answers"]): + embed.add_field(option["text"] if image_type is True else _("Option {}").format(num + 1), + option["text"] if image_type is False else _( + "__[View image]({image_url})__").format(image_url=option["image"]["url"]), + inline=True) + elif thread_funnel == "QUIZ": + embed.event_type = "discussion/forum/quiz" + embed["title"] = _("Created a quiz \"{title}\"").format(title=post["title"]) + if settings["fandom_discussions"]["appearance"]["embed"]["show_content"]: + quiz = post["_embedded"]["quizzes"][0] + embed["description"] = quiz["title"] + if quiz["image"] is not None: + embed["image"]["url"] = quiz["image"] + elif thread_funnel == "TEXT": + embed.event_type = "discussion/forum/post" + else: + logger.warning( + "The type of {} is an unknown discussion post type. Please post an issue on the project page to have it added https://gitlab.com/piotrex43/RcGcDw/-/issues.".format( + thread_funnel)) + embed.event_type = "unknown" + if post["_embedded"]["thread"][0]["tags"]: + tag_displayname = [] + for tag in post["_embedded"]["thread"][0]["tags"]: + tag_displayname.append("[{title}]({url})".format(title=tag["articleTitle"], url=create_article_path( + quote_plus(tag["articleTitle"].replace(" ", "_"), "/:?=&")))) + if len(", ".join(tag_displayname)) > 1000: + embed.add_field(formatters_i18n.pgettext("Fandom discussions Tags/Forums", "Tags"), formatters_i18n.pgettext("Fandom discussions amount of Tags/Forums", "{} tags").format(len(post["_embedded"]["thread"][0]["tags"]))) + else: + embed.add_field(formatters_i18n.pgettext("Fandom discussions Tags/Forums", "Tags"), ", ".join(tag_displayname)) + else: + embed.event_type = "discussion/forum/reply" + embed["title"] = _("Replied to \"{title}\"").format(title=post["_embedded"]["thread"][0]["title"]) + embed["url"] = "{url}f/p/{threadId}/r/{postId}".format(url=settings["fandom_discussions"]["wiki_url"], + threadId=post["threadId"], postId=post["id"]) + return embed + + +@formatter.compact(event="discussion/forum") +def compact_discussion_forum(ctx: Context, post: dict): + message = None + author = _("unknown") # Fail safe + if post["createdBy"]["name"]: + author = post["createdBy"]["name"] + author_url = "<{url}f/u/{creatorId}>".format(url=settings["fandom_discussions"]["wiki_url"], + creatorId=post["creatorId"]) + if not post["isReply"]: + thread_funnel = post.get("funnel") + msg_text = _("[{author}]({author_url}) created [{title}](<{url}f/p/{threadId}>) in {forumName}") + if thread_funnel == "POLL": + event_type = "discussion/forum/poll" + msg_text = _("[{author}]({author_url}) created a poll [{title}](<{url}f/p/{threadId}>) in {forumName}") + elif thread_funnel == "QUIZ": + event_type = "discussion/forum/quiz" + msg_text = _("[{author}]({author_url}) created a quiz [{title}](<{url}f/p/{threadId}>) in {forumName}") + elif thread_funnel == "TEXT": + event_type = "discussion/forum/post" + else: + logger.warning( + "The type of {} is an unknown discussion post type. Please post an issue on the project page to have it added https://gitlab.com/piotrex43/RcGcDw/-/issues.".format( + thread_funnel)) + event_type = "unknown" + message = msg_text.format(author=author, author_url=author_url, title=post["title"], + url=settings["fandom_discussions"]["wiki_url"], threadId=post["threadId"], + forumName=post["forumName"]) + else: + event_type = "discussion/forum/reply" + message = _( + "[{author}]({author_url}) created a [reply](<{url}f/p/{threadId}/r/{postId}>) to [{title}](<{url}f/p/{threadId}>) in {forumName}").format( + author=author, author_url=author_url, url=settings["fandom_discussions"]["wiki_url"], + threadId=post["threadId"], postId=post["id"], title=post["_embedded"]["thread"][0]["title"], + forumName=post["forumName"]) + return DiscordMessage("compact", event_type, ctx.webhook_url, content=message) + +# discussion/wall - Wall posts/replies + + +def compact_author_discussions(post: dict): + """A common function for a few discussion related foramtters, it's formatting author's name and URL to their profile""" + author = _("unknown") # Fail safe + if post["creatorIp"]: + author = post["creatorIp"][1:] if settings.get("hide_ips", False) is False else _("Unregistered user") + author_url = "<{url}wiki/Special:Contributions{creatorIp}>".format(url=settings["fandom_discussions"]["wiki_url"], + creatorIp=post["creatorIp"]) + else: + if post["createdBy"]["name"]: + author = post["createdBy"]["name"] + author_url = clean_link(create_article_path("User:{user}".format(user=author))) + else: + author_url = "<{url}f/u/{creatorId}>".format(url=settings["fandom_discussions"]["wiki_url"], + creatorId=post["creatorId"]) + return author, author_url + + +def embed_author_discussions(post: dict, embed: DiscordMessage): + author = _("unknown") # Fail safe + if post["creatorIp"]: + author = post["creatorIp"][1:] + embed.set_author(author if settings.get("hide_ips", False) is False else _("Unregistered user"), + "{url}wiki/Special:Contributions{creatorIp}".format( + url=settings["fandom_discussions"]["wiki_url"], creatorIp=post["creatorIp"])) + else: + if post["createdBy"]["name"]: + author = post["createdBy"]["name"] + embed.set_author(author, "{url}wiki/User:{creator}".format(url=settings["fandom_discussions"]["wiki_url"], + creator=author.replace(" ", "_")), + icon_url=post["createdBy"]["avatarUrl"]) + else: + embed.set_author(author, "{url}f/u/{creatorId}".format(url=settings["fandom_discussions"]["wiki_url"], + creatorId=post["creatorId"]), + icon_url=post["createdBy"]["avatarUrl"]) + + +@formatter.embed(event="discussion/wall") +def embed_discussion_wall(ctx: Context, post: dict): + embed = DiscordMessage("embed", "discussion", settings["fandom_discussions"]["webhookURL"]) + common_discussions(post, embed) + embed_author_discussions(post, embed) + user_wall = _("unknown") # Fail safe + if post["forumName"].endswith(' Message Wall'): + user_wall = post["forumName"][:-13] + if not post["isReply"]: + embed.event_type = "discussion/wall/post" + embed["url"] = "{url}wiki/Message_Wall:{user_wall}?threadId={threadId}".format( + url=settings["fandom_discussions"]["wiki_url"], user_wall=quote_plus(user_wall.replace(" ", "_")), + threadId=post["threadId"]) + embed["title"] = _("Created \"{title}\" on {user}'s Message Wall").format(title=post["title"], user=user_wall) + else: + embed.event_type = "discussion/wall/reply" + embed["url"] = "{url}wiki/Message_Wall:{user_wall}?threadId={threadId}#{replyId}".format( + url=settings["fandom_discussions"]["wiki_url"], user_wall=quote_plus(user_wall.replace(" ", "_")), + threadId=post["threadId"], replyId=post["id"]) + embed["title"] = _("Replied to \"{title}\" on {user}'s Message Wall").format( + title=post["_embedded"]["thread"][0]["title"], user=user_wall) + return embed + + +@formatter.compact(event="discussion/wall") +def compact_discussion_wall(ctx: Context, post: dict): + author, author_url = compact_author_discussions(post) + user_wall = _("unknown") # Fail safe + if post["forumName"].endswith(' Message Wall'): + user_wall = post["forumName"][:-13] + if not post["isReply"]: + event_type = "discussion/wall/post" + message = _( + "[{author}]({author_url}) created [{title}](<{url}wiki/Message_Wall:{user_wall}?threadId={threadId}>) on [{user}'s Message Wall](<{url}wiki/Message_Wall:{user_wall}>)").format( + author=author, author_url=author_url, title=post["title"], url=settings["fandom_discussions"]["wiki_url"], + user=user_wall, user_wall=quote_plus(user_wall.replace(" ", "_")), threadId=post["threadId"]) + else: + event_type = "discussion/wall/reply" + message = _( + "[{author}]({author_url}) created a [reply](<{url}wiki/Message_Wall:{user_wall}?threadId={threadId}#{replyId}>) to [{title}](<{url}wiki/Message_Wall:{user_wall}?threadId={threadId}>) on [{user}'s Message Wall](<{url}wiki/Message_Wall:{user_wall}>)").format( + author=author, author_url=author_url, url=settings["fandom_discussions"]["wiki_url"], + title=post["_embedded"]["thread"][0]["title"], user=user_wall, + user_wall=quote_plus(user_wall.replace(" ", "_")), threadId=post["threadId"], replyId=post["id"]) + return DiscordMessage("compact", event_type, ctx.webhook_url, content=message) + +# discussion/article_comment - Article comments + + +@formatter.embed(event="discussion/article_comment") +def embed_discussion_article_comment(ctx: Context, post: dict): + embed = DiscordMessage("embed", "discussion", settings["fandom_discussions"]["webhookURL"]) + common_discussions(post, embed) + embed_author_discussions(post, embed) + article_paths = ctx.comment_page + if article_paths is None: + article_page = {"title": _("unknown"), "fullUrl": settings["fandom_discussions"]["wiki_url"]} # No page known + if not post["isReply"]: + embed.event_type = "discussion/comment/post" + embed["url"] = "{url}?commentId={commentId}".format(url=article_paths["fullUrl"], commentId=post["threadId"]) + embed["title"] = _("Commented on {article}").format(article=article_paths["title"]) + else: + embed.event_type = "discussion/comment/reply" + embed["url"] = "{url}?commentId={commentId}&replyId={replyId}".format(url=article_paths["fullUrl"], + commentId=post["threadId"], + replyId=post["id"]) + embed["title"] = _("Replied to a comment on {article}").format(article=article_paths["title"]) + embed["footer"]["text"] = article_paths["title"] + return embed + + +@formatter.compact(event="discussion/article_comment") +def compact_discussion_article_comment(ctx: Context, post: dict): + author, author_url = compact_author_discussions(post) + article_paths = ctx.comment_page + if article_paths is None: + article_paths = {"title": _("unknown"), "fullUrl": settings["fandom_discussions"]["wiki_url"]} # No page known + article_paths["fullUrl"] = article_paths["fullUrl"].replace(")", "\)").replace("()", "\(") + if not post["isReply"]: + event_type = "discussion/comment/post" + message = _( + "[{author}]({author_url}) created a [comment](<{url}?commentId={commentId}>) on [{article}](<{url}>)").format( + author=author, author_url=author_url, url=article_paths["fullUrl"], article=article_paths["title"], + commentId=post["threadId"]) + else: + event_type = "discussion/comment/reply" + message = _( + "[{author}]({author_url}) created a [reply](<{url}?commentId={commentId}&replyId={replyId}>) to a [comment](<{url}?commentId={commentId}>) on [{article}](<{url}>)").format( + author=author, author_url=author_url, url=article_paths["fullUrl"], article=article_paths["title"], + commentId=post["threadId"], replyId=post["id"]) + return DiscordMessage("compact", event_type, ctx.webhook_url, content=message) \ No newline at end of file diff --git a/extensions/base/interwiki.py b/extensions/base/interwiki.py new file mode 100644 index 0000000..a9dffd2 --- /dev/null +++ b/extensions/base/interwiki.py @@ -0,0 +1,108 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + + +import logging +from src.discord.message import DiscordMessage +from src.api import formatter +from src.i18n import formatters_i18n +from src.api.context import Context +from src.api.util import embed_helper, clean_link, compact_author, create_article_path, sanitize_to_url, compact_summary + +_ = formatters_i18n.gettext +ngettext = formatters_i18n.ngettext + + +# Interwiki - https://www.mediawiki.org/wiki/Extension:Interwiki +# interwiki/iw_add - Added entry to interwiki table + + +@formatter.embed(event="interwiki/iw_add", mode="embed") +def embed_interwiki_iw_add(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change, set_desc=False) + embed["url"] = create_article_path("Special:Interwiki") + embed["title"] = _("Added an entry to the interwiki table") + embed["description"] = _("Prefix: {prefix}, website: {website} | {desc}").format(desc=ctx.parsedcomment, + prefix=change["logparams"]['0'], + website=change["logparams"]['1']) + return embed + + +@formatter.compact(event="interwiki/iw_add") +def compact_interwiki_iw_add(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path("Special:Interwiki")) + parsed_comment = compact_summary(ctx) + content = _( + "[{author}]({author_url}) added an entry to the [interwiki table]({table_url}) pointing to {website} with {prefix} prefix").format( + author=author, author_url=author_url, desc=parsed_comment, prefix=change["logparams"]['0'], + website=change["logparams"]['1'], table_url=link) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# interwiki/iw_edit - Editing interwiki entry + + +@formatter.embed(event="interwiki/iw_edit", mode="embed") +def embed_interwiki_iw_edit(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change, set_desc=False) + embed["url"] = create_article_path("Special:Interwiki") + embed["title"] = _("Edited an entry in interwiki table") + embed["description"] = _("Prefix: {prefix}, website: {website} | {desc}").format(desc=ctx.parsedcomment, + prefix=change["logparams"]['0'], + website=change["logparams"]['1']) + return embed + + +@formatter.compact(event="interwiki/iw_edit") +def compact_interwiki_iw_edit(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path("Special:Interwiki")) + parsed_comment = compact_summary(ctx) + content = _( + "[{author}]({author_url}) edited an entry in [interwiki table]({table_url}) pointing to {website} with {prefix} prefix").format( + author=author, author_url=author_url, desc=parsed_comment, prefix=change["logparams"]['0'], + website=change["logparams"]['1'], table_url=link) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# interwiki/iw_delete - Deleting interwiki entry + + +@formatter.embed(event="interwiki/iw_delete", mode="embed") +def embed_interwiki_iw_delete(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change, set_desc=False) + embed["url"] = create_article_path("Special:Interwiki") + embed["title"] = _("Deleted an entry in interwiki table") + embed["description"] = _("Prefix: {prefix} | {desc}").format(desc=ctx.parsedcomment, + prefix=change["logparams"]['0']) + return embed + + +@formatter.compact(event="interwiki/iw_delete") +def compact_interwiki_iw_delete(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path("Special:Interwiki")) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) deleted an entry in [interwiki table]({table_url}){desc}").format( + author=author, + author_url=author_url, + table_url=link, + desc=parsed_comment) + + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) diff --git a/extensions/base/managewiki.py b/extensions/base/managewiki.py new file mode 100644 index 0000000..7675441 --- /dev/null +++ b/extensions/base/managewiki.py @@ -0,0 +1,229 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +from src.discord.message import DiscordMessage +from src.api import formatter +from src.i18n import formatters_i18n +from src.api.context import Context +from src.api.util import embed_helper, compact_author, create_article_path, sanitize_to_markdown, sanitize_to_url, compact_summary + +_ = formatters_i18n.gettext +ngettext = formatters_i18n.ngettext + + +# ManageWiki - https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:ManageWiki +# managewiki/settings - Changing wiki settings + +@formatter.embed(event="managewiki/settings") +def embed_managewiki_settings(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Changed wiki settings") + if change["logparams"].get("changes", ""): + embed.add_field("Setting", sanitize_to_markdown(change["logparams"].get("changes"))) + return embed + + +@formatter.compact(event="managewiki/settings") +def compact_managewiki_settings(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) changed wiki settings{reason}".format(author=author, author_url=author_url, reason=parsed_comment)) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# managewiki/delete - Deleting a wiki + + +@formatter.embed(event="managewiki/delete") +def embed_managewiki_delete(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Deleted a \"{wiki}\" wiki").format(wiki=change["logparams"].get("wiki", _("Unknown"))) + return embed + + +@formatter.compact(event="managewiki/delete") +def compact_managewiki_delete(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) deleted a wiki *{wiki_name}*{comment}").format(author=author, + author_url=author_url, + wiki_name=change[ + "logparams"].get("wiki", + _("Unknown")), + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# managewiki/delete-group - Deleting a group + + +@formatter.embed(event="managewiki/delete-group") +def embed_managewiki_delete_group(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + group = change["title"].split("/")[-1] + embed["title"] = _("Deleted a \"{group}\" user group").format(wiki=group) + return embed + + +@formatter.compact(event="managewiki/delete-group") +def compact_managewiki_delete_group(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + group = change["title"].split("/")[-1] + content = _("[{author}]({author_url}) deleted a usergroup *{group}*{comment}").format(author=author, + author_url=author_url, + group=group, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# managewiki/lock - Locking a wiki + + +@formatter.embed(event="managewiki/lock") +def embed_managewiki_lock(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Locked a \"{wiki}\" wiki").format(wiki=change["logparams"].get("wiki", _("Unknown"))) + return embed + + +@formatter.compact(event="managewiki/lock") +def compact_managewiki_lock(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) locked a wiki *{wiki_name}*{comment}").format( + author=author, author_url=author_url, wiki_name=change["logparams"].get("wiki", _("Unknown")), + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# managewiki/namespaces - Modirying a wiki namespace + + +@formatter.embed(event="managewiki/namespaces") +def embed_managewiki_namespaces(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Modified \"{namespace_name}\" namespace").format( + namespace_name=change["logparams"].get("namespace", _("Unknown"))) + embed.add_field(_('Wiki'), change["logparams"].get("wiki", _("Unknown"))) + return embed + + +@formatter.compact(event="managewiki/namespaces") +def compact_managewiki_namespaces(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) modified namespace *{namespace_name}* on *{wiki_name}*{comment}").format( + author=author, author_url=author_url, namespace_name=change["logparams"].get("namespace", _("Unknown")), + wiki_name=change["logparams"].get("wiki", _("Unknown")), comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# managewiki/namespaces-delete - Deleteing a namespace + + +@formatter.embed(event="managewiki/namespaces-delete") +def embed_managewiki_namespaces_delete(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Deleted a \"{namespace_name}\" namespace").format( + namespace_name=change["logparams"].get("namespace", _("Unknown"))) + embed.add_field(_('Wiki'), change["logparams"].get("wiki", _("Unknown"))) + return embed + + +@formatter.compact(event="managewiki/namespaces-delete") +def compact_managewiki_namespaces_delete(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = _( + "[{author}]({author_url}) deleted a namespace *{namespace_name}* on *{wiki_name}*{comment}").format( + author=author, author_url=author_url, + namespace_name=change["logparams"].get("namespace", _("Unknown")), + wiki_name=change["logparams"].get("wiki", _("Unknown")), comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# managewiki/rights - Modifying user groups + + +@formatter.embed(event="managewiki/rights") +def embed_managewiki_rights(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + group_name = change["title"].split("/permissions/", 1)[1] + embed["title"] = _("Modified \"{usergroup_name}\" usergroup").format(usergroup_name=group_name) + return embed + + +@formatter.compact(event="managewiki/rights") +def compact_managewiki_rights(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + group_name = change["title"].split("/permissions/", 1)[1] + content = _("[{author}]({author_url}) modified user group *{group_name}*{comment}").format( + author=author, author_url=author_url, group_name=group_name, comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# managewiki/undelete - Restoring a wiki + + +@formatter.embed(event="managewiki/undelete") +def embed_managewiki_undelete(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Undeleted a \"{wiki}\" wiki").format(wiki=change["logparams"].get("wiki", _("Unknown"))) + return embed + + +@formatter.compact(event="managewiki/undelete") +def compact_managewiki_undelete(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) undeleted a wiki *{wiki_name}*{comment}").format( + author=author, author_url=author_url, wiki_name=change["logparams"].get("wiki", _("Unknown")), + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# managewiki/unlock - Unlocking a wiki + + +@formatter.embed(event="managewiki/unlock") +def embed_managewiki_unlock(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Unlocked a \"{wiki}\" wiki").format(wiki=change["logparams"].get("wiki", _("Unknown"))) + return embed + + +@formatter.compact(event="managewiki/unlock") +def compact_managewiki_unlock(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) unlocked a wiki *{wiki_name}*{comment}").format( + author=author, author_url=author_url, wiki_name=change["logparams"].get("wiki", _("Unknown")), + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) diff --git a/extensions/base/mediawiki.py b/extensions/base/mediawiki.py new file mode 100644 index 0000000..f5b81d0 --- /dev/null +++ b/extensions/base/mediawiki.py @@ -0,0 +1,1189 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . +import ipaddress +import logging +import math +import re +import time +import datetime +from collections import OrderedDict +from src.discord.message import DiscordMessage +from src.api import formatter +from src.i18n import formatters_i18n +from src.api.context import Context +from src.api.util import embed_helper, sanitize_to_url, parse_mediawiki_changes, clean_link, compact_author, \ + create_article_path, sanitize_to_markdown, compact_summary +from src.configloader import settings +from src.exceptions import * + +_ = formatters_i18n.gettext +ngettext = formatters_i18n.ngettext + +logger = logging.getLogger("extensions.base") + +if 1 == 2: # additional translation strings in unreachable code + print(_("director"), _("bot"), _("editor"), _("directors"), _("sysop"), _("bureaucrat"), _("reviewer"), + _("autoreview"), _("autopatrol"), _("wiki_guardian")) + + +# Page edit - event edit, New - page creation + + +@formatter.embed(event="edit", mode="embed", aliases=["new"]) +def embed_edit(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + action = ctx.event + editsize = change["newlen"] - change["oldlen"] + if editsize > 0: + embed["color"] = min(65280, 35840 + (math.floor(editsize / 52)) * 256) # Choose shade of green + elif editsize < 0: + embed["color"] = min(16711680, 9175040 + (math.floor(abs(editsize) / 52)) * 65536) # Choose shade of red + elif editsize == 0: + embed["color"] = 8750469 + if change["title"].startswith("MediaWiki:Tag-"): # Refresh tag list when tag display name is edited + ctx.client.refresh_internal_data() + # Sparse is better than dense. + # Readability counts. + embed["url"] = "{wiki}index.php?title={article}&curid={pageid}&diff={diff}&oldid={oldrev}".format( + wiki=ctx.client.WIKI_SCRIPT_PATH, + pageid=change["pageid"], + diff=change["revid"], + oldrev=change["old_revid"], + article=sanitize_to_url(change["title"]) + ) + embed["title"] = "{redirect}{article} ({new}{minor}{bot}{space}{editsize})".format( + redirect="⤷ " if "redirect" in change else "", + article=sanitize_to_markdown(change["title"]), + editsize="+" + str(editsize) if editsize > 0 else editsize, + new=_("(N!) ") if action == "new" else "", + minor=_("m") if action == "edit" and "minor" in change else "", + bot=_('b') if "bot" in change else "", + space=" " if "bot" in change or (action == "edit" and "minor" in change) or action == "new" else "") + if settings["appearance"]["embed"]["show_edit_changes"]: + try: + if action == "new": + changed_content = ctx.client.make_api_request( + "?action=compare&format=json&fromslots=main&torev={diff}&fromtext-main=&topst=1&prop=diff".format( + diff=change["revid"]), "compare", "*") + else: + changed_content = ctx.client.make_api_request( + "?action=compare&format=json&fromrev={oldrev}&torev={diff}&topst=1&prop=diff".format( + diff=change["revid"], oldrev=change["old_revid"]), "compare", "*") + except ServerError: + changed_content = None + if changed_content: + parse_mediawiki_changes(ctx, changed_content, embed) + else: + logger.warning("Unable to download data on the edit content!") + embed_helper(ctx, embed, change) + return embed + + +@formatter.compact(event="edit", mode="compact", aliases=["new"]) +def compact_edit(ctx: Context, change: dict) -> DiscordMessage: + parsed_comment = compact_summary(ctx) + author, author_url = compact_author(ctx, change) + action = ctx.event + edit_link = clean_link("{wiki}index.php?title={article}&curid={pageid}&diff={diff}&oldid={oldrev}".format( + wiki=ctx.client.WIKI_SCRIPT_PATH, pageid=change["pageid"], diff=change["revid"], oldrev=change["old_revid"], + article=sanitize_to_url(change["title"]))) + logger.debug(edit_link) + edit_size = change["newlen"] - change["oldlen"] + sign = "" + if edit_size > 0: + sign = "+" + bold = "" + if abs(edit_size) > 500: + bold = "**" + if action == "edit": + content = _( + "[{author}]({author_url}) edited [{article}]({edit_link}){comment} {bold}({sign}{edit_size}){bold}").format( + author=author, author_url=author_url, article=sanitize_to_markdown(change["title"]), edit_link=edit_link, comment=parsed_comment, + edit_size=edit_size, sign=sign, bold=bold) + else: + content = _( + "[{author}]({author_url}) created [{article}]({edit_link}){comment} {bold}({sign}{edit_size}){bold}").format( + author=author, author_url=author_url, article=sanitize_to_markdown(change["title"]), edit_link=edit_link, comment=parsed_comment, + edit_size=edit_size, sign=sign, bold=bold) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# Upload - upload/reupload, upload/upload +@formatter.embed(event="upload/upload", mode="embed", aliases=["upload/overwrite", "upload/revert"]) +def embed_upload_upload(ctx, change) -> DiscordMessage: + license = None + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + action = ctx.event + # Requesting more information on the image + request_for_image_data = None + try: + params = OrderedDict() + params["action"] = "query" + params["format"] = "json" + if settings["license_detection"] and action == "upload/upload": + params["prop"] = "imageinfo|revisions" + params["rvprop"] = "content" + params["rvslots"] = "main" + else: + params["prop"] = "imageinfo" + params["titles"] = change["title"] + params["iiprop"] = "timestamp|url|archivename" + params["iilimit"] = "5" + request_for_image_data = ctx.client.make_api_request(params, "query", "pages") + except (ServerError, MediaWikiError): + logger.exception( + "Couldn't retrieve more information about the image {} because of server/MediaWiki error".format( + change["title"])) + except (ClientError, BadRequest): + raise + except KeyError: + logger.exception( + "Couldn't retrieve more information about the image {} because of unknown error".format( + change["title"])) + else: + if "-1" not in request_for_image_data: # Image still exists and not removed + image_data = next(iter(request_for_image_data.values())) + else: + logger.warning("Request for additional image information have failed. The preview will not be shown.") + request_for_image_data = None + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + image_direct_url = None + # Make a request for file revisions so we can get direct URL to the image for embed + if request_for_image_data is not None: + try: + urls = image_data["imageinfo"] + for num, revision in enumerate(urls): + if revision["timestamp"] == change["logparams"][ + "img_timestamp"]: # find the correct revision corresponding for this log entry + image_direct_url = "{rev}?{cache}".format(rev=revision["url"], + cache=int(time.time() * 5)) # cachebusting + break + except KeyError: + logger.exception( + "Wiki did not respond with extended information about file. The preview will not be shown.") + else: + logger.warning("Request for additional image information have failed. The preview will not be shown.") + if action in ("upload/overwrite", "upload/revert"): + if image_direct_url: + try: + revision = image_data["imageinfo"][num + 1] + except IndexError: + logger.exception( + "Could not analize the information about the image (does it have only one version when expected more in overwrite?) which resulted in no Options field: {}".format( + image_data["imageinfo"])) + else: + undolink = "{wiki}index.php?title={filename}&action=revert&oldimage={archiveid}".format( + wiki=ctx.client.WIKI_SCRIPT_PATH, filename=sanitize_to_url(change["title"]), + archiveid=revision["archivename"]) + embed.add_field(_("Options"), _("([preview]({link}) | [undo]({undolink}))").format( + link=image_direct_url, undolink=undolink)) + if settings["appearance"]["embed"]["embed_images"]: + embed["image"]["url"] = image_direct_url + if action == "upload/overwrite": + embed["title"] = _("Uploaded a new version of {name}").format(name=sanitize_to_markdown(change["title"])) + elif action == "upload/revert": + embed["title"] = _("Reverted a version of {name}").format(name=sanitize_to_markdown(change["title"])) + else: + embed["title"] = _("Uploaded {name}").format(name=sanitize_to_markdown(change["title"])) + if settings["license_detection"] and image_direct_url: + try: + content = image_data['revisions'][0]["slots"]["main"]['*'] + matches = re.search(re.compile(settings["license_regex"], re.IGNORECASE), content) + if matches is not None: + license = matches.group("license") + else: + if re.search(re.compile(settings["license_regex_detect"], re.IGNORECASE), content) is None: + license = _("**No license!**") + else: + license = "?" + except IndexError: + logger.error( + "Given regex for the license detection is incorrect. It does not have a capturing group called \"license\" specified. Please fix license_regex value in the config!") + license = "?" + except re.error: + logger.error( + "Given regex for the license detection is incorrect. Please fix license_regex or license_regex_detect values in the config!") + license = "?" + except KeyError: + logger.exception( + "Unknown error when retriefing the image data for a license, full content: {}".format(image_data)) + if image_direct_url: + embed.add_field(_("Options"), _("([preview]({link}))").format(link=image_direct_url)) + if settings["appearance"]["embed"]["embed_images"]: + embed["image"]["url"] = image_direct_url + embed_helper(ctx, embed, change) + if license is not None: + embed["description"] += _("\nLicense: {}").format(license) + return embed + + +@formatter.compact(event="upload/revert", mode="compact") +def compact_upload_revert(ctx, change) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + file_link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) reverted a version of [{file}]({file_link}){comment}").format( + author=author, author_url=author_url, file=sanitize_to_markdown(change["title"]), file_link=file_link, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +@formatter.compact(event="upload/overwrite", mode="compact") +def compact_upload_overwrite(ctx, change) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + file_link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) uploaded a new version of [{file}]({file_link}){comment}").format( + author=author, author_url=author_url, file=sanitize_to_markdown(change["title"]), file_link=file_link, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +@formatter.compact(event="upload/upload", mode="compact") +def compact_upload_upload(ctx, change) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + file_link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) uploaded [{file}]({file_link}){comment}").format(author=author, + author_url=author_url, + file=sanitize_to_markdown( + change["title"]), + file_link=file_link, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# delete/delete - Page deletion +@formatter.embed(event="delete/delete", mode="embed") +def embed_delete_delete(ctx, change) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed['url'] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Deleted page {article}").format(article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="delete/delete", mode="compact") +def compact_delete_delete(ctx, change) -> DiscordMessage: + parsed_comment = compact_summary(ctx) + author, author_url = compact_author(ctx, change) + page_link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _("[{author}]({author_url}) deleted [{page}]({page_link}){comment}").format(author=author, + author_url=author_url, + page=sanitize_to_markdown( + change["title"]), + page_link=page_link, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# delete/delete_redir - Redirect deletion +@formatter.embed(event="delete/delete_redir", mode="embed") +def embed_delete_delete_redir(ctx, change) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed['url'] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Deleted redirect {article} by overwriting").format( + article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="delete/delete_redir", mode="compact") +def compact_delete_delete_redir(ctx, change) -> DiscordMessage: + page_link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) deleted redirect by overwriting [{page}]({page_link}){comment}").format( + author=author, author_url=author_url, page=sanitize_to_markdown(change["title"]), page_link=page_link, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# delete/restore - Restoring a page + + +@formatter.embed(event="delete/restore", mode="embed") +def embed_delete_restore(ctx, change) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed['url'] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Restored {article}").format(article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="delete/restore", mode="compact") +def compact_delete_restore(ctx, change) -> DiscordMessage: + page_link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) restored [{article}]({article_url}){comment}").format(author=author, + author_url=author_url, + article=sanitize_to_markdown( + change["title"]), + article_url=page_link, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# delete/event - Deleting an event with revdelete feature + + +@formatter.embed(event="delete/event", mode="embed") +def embed_delete_event(ctx, change) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed['url'] = create_article_path("Special:RecentChanges") + embed["title"] = _("Changed visibility of log events") + return embed + + +@formatter.compact(event="delete/event", mode="compact") +def compact_delete_event(ctx, change) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) changed visibility of log events{comment}").format(author=author, + author_url=author_url, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# delete/revision - Deleting revision information + +@formatter.embed(event="delete/revision", mode="embed") +def embed_delete_revision(ctx, change) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + amount = len(change["logparams"]["ids"]) + embed['url'] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = ngettext("Changed visibility of revision on page {article} ", + "Changed visibility of {amount} revisions on page {article} ", amount).format( + article=sanitize_to_markdown(change["title"]), amount=amount) + return embed + + +@formatter.compact(event="delete/revision", mode="compact") +def compact_delete_revision(ctx, change) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + amount = len(change["logparams"]["ids"]) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + parsed_comment = compact_summary(ctx) + content = ngettext( + "[{author}]({author_url}) changed visibility of revision on page [{article}]({article_url}){comment}", + "[{author}]({author_url}) changed visibility of {amount} revisions on page [{article}]({article_url}){comment}", + amount).format(author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, amount=amount, comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# move/move - Moving pages + + +@formatter.embed(event="move/move", mode="embed") +def embed_move_move(ctx, change) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change, set_desc=False) + embed["url"] = create_article_path(sanitize_to_url(change["logparams"]['target_title'])) + embed["description"] = "{supress}. {desc}".format(desc=ctx.parsedcomment, + supress=_("No redirect has been made") if "suppressredirect" in + change["logparams"] else _("A redirect has been made")) + embed["title"] = _("Moved {redirect}{article} to {target}").format(redirect="⤷ " if "redirect" in change else "", + article=sanitize_to_markdown(change["title"]), + target=sanitize_to_markdown( + change["logparams"]['target_title'])) + return embed + + +@formatter.compact(event="move/move", mode="compact") +def compact_move_move(ctx, change) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["logparams"]['target_title']))) + redirect_status = _("without making a redirect") if "suppressredirect" in change["logparams"] else _( + "with a redirect") + parsed_comment = compact_summary(ctx) + content = _( + "[{author}]({author_url}) moved {redirect}*{article}* to [{target}]({target_url}) {made_a_redirect}{comment}").format( + author=author, author_url=author_url, redirect="⤷ " if "redirect" in change else "", article=sanitize_to_markdown(change["title"]), + target=sanitize_to_markdown(change["logparams"]['target_title']), target_url=link, comment=parsed_comment, + made_a_redirect=redirect_status) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# move/move_redir - Move over redirect + + +@formatter.embed(event="move/move_redir", mode="embed") +def embed_move_move_redir(ctx, change) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change, set_desc=False) + embed["url"] = create_article_path(sanitize_to_url(change["logparams"]['target_title'])) + embed["description"] = "{supress}. {desc}".format(desc=ctx.parsedcomment, + supress=_("No redirect has been made") if "suppressredirect" in + change["logparams"] else _("A redirect has been made")) + embed["title"] = _("Moved {redirect}{article} to {title} over redirect").format( + redirect="⤷ " if "redirect" in change else "", article=sanitize_to_markdown(change["title"]), + title=sanitize_to_markdown(change["logparams"]["target_title"])) + return embed + + +@formatter.compact(event="move/move_redir", mode="compact") +def compact_move_move_redir(ctx, change) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["logparams"]['target_title']))) + redirect_status = _("without making a redirect") if "suppressredirect" in change["logparams"] else _( + "with a redirect") + parsed_comment = compact_summary(ctx) + content = _( + "[{author}]({author_url}) moved {redirect}*{article}* over redirect to [{target}]({target_url}) {made_a_redirect}{comment}").format( + author=author, author_url=author_url, redirect="⤷ " if "redirect" in change else "", + article=sanitize_to_markdown(change["title"]), + target=sanitize_to_markdown(change["logparams"]['target_title']), target_url=link, comment=parsed_comment, + made_a_redirect=redirect_status) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# protect/move_prot - Moving protection + + +@formatter.embed(event="protect/move_prot", mode="embed") +def embed_protect_move_prot(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["logparams"]["oldtitle_title"])) + embed["title"] = _("Moved protection settings from {redirect}{article} to {title}").format( + redirect="⤷ " if "redirect" in change else "", + article=sanitize_to_markdown(change["logparams"]["oldtitle_title"]), + title=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="protect/move_prot", mode="compact") +def compact_protect_move_prot(ctx, change): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["logparams"]["oldtitle_title"]))) + parsed_comment = compact_summary(ctx) + content = _( + "[{author}]({author_url}) moved protection settings from {redirect}*{article}* to [{target}]({target_url}){comment}").format( + author=author, author_url=author_url, redirect="⤷ " if "redirect" in change else "", + article=sanitize_to_markdown(change["logparams"]["oldtitle_title"]), + target=sanitize_to_markdown(change["title"]), target_url=link, comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# protect/protect - Creating protection + + +@formatter.embed(event="protect/protect", mode="embed") +def embed_protect_protect(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change, set_desc=False) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Protected {target}").format(target=sanitize_to_markdown(change["title"])) + embed["description"] = "{settings}{cascade} | {reason}".format( + settings=sanitize_to_markdown(change["logparams"].get("description", "")), + cascade=_(" [cascading]") if "cascade" in change["logparams"] else "", + reason=ctx.parsedcomment) + return embed + + +@formatter.compact(event="protect/protect", mode="compact") +def compact_protect_protect(ctx, change): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + parsed_comment = compact_summary(ctx) + content = _( + "[{author}]({author_url}) protected [{article}]({article_url}) with the following settings: {settings}{comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + settings=change["logparams"].get("description", "") + ( + _(" [cascading]") if "cascade" in change["logparams"] else ""), + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# protect/modify - Changing protection settings + + +@formatter.embed(event="protect/modify", mode="embed") +def embed_protect_modify(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change, set_desc=False) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Changed protection level for {article}").format(article=sanitize_to_markdown(change["title"])) + embed["description"] = "{settings}{cascade} | {reason}".format( + settings=sanitize_to_markdown(change["logparams"].get("description", "")), + cascade=_(" [cascading]") if "cascade" in change["logparams"] else "", + reason=ctx.parsedcomment) + return embed + + +@formatter.compact(event="protect/modify", mode="compact") +def compact_protect_modify(ctx, change): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + parsed_comment = compact_summary(ctx) + content = _( + "[{author}]({author_url}) modified protection settings of [{article}]({article_url}) to: {settings}{comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + settings=sanitize_to_markdown(change["logparams"].get("description", "")) + ( + _(" [cascading]") if "cascade" in change["logparams"] else ""), + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# protect/unprotect - Unprotecting a page + + +@formatter.embed(event="protect/unprotect", mode="embed") +def embed_protect_unprotect(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Removed protection from {article}").format(article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="protect/unprotect", mode="compact") +def compact_protect_unprotect(ctx, change): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) removed protection from [{article}]({article_url}){comment}").format( + author=author, author_url=author_url, article=sanitize_to_markdown(change["title"]), article_url=link, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# block/block - Blocking an user +def block_expiry(change: dict) -> str: + if change["logparams"]["duration"] in ["infinite", "indefinite", "infinity", "never"]: + return _("for infinity and beyond") + else: + if "expiry" in change["logparams"]: + expiry_date_time_obj = datetime.datetime.strptime(change["logparams"]["expiry"], '%Y-%m-%dT%H:%M:%SZ') + timestamp_date_time_obj = datetime.datetime.strptime(change["timestamp"], '%Y-%m-%dT%H:%M:%SZ') + timedelta_for_expiry = (expiry_date_time_obj - timestamp_date_time_obj).total_seconds() + years, days, hours, minutes = timedelta_for_expiry // 31557600, timedelta_for_expiry % 31557600 // 86400, \ + timedelta_for_expiry % 86400 // 3600, timedelta_for_expiry % 3600 // 60 + if not any([years, days, hours, minutes]): + return _("for less than a minute") + time_names = ( + ngettext("year", "years", years), ngettext("day", "days", days), ngettext("hour", "hours", hours), + ngettext("minute", "minutes", minutes)) + final_time = [] + for num, timev in enumerate([years, days, hours, minutes]): + if timev: + final_time.append( + _("for {time_number} {time_unit}").format(time_unit=time_names[num], time_number=int(timev))) + return ", ".join(final_time) + else: + return change["logparams"]["duration"] # Temporary? Should be rare? We will see in testing + + +@formatter.embed(event="block/block", mode="embed") +def embed_block_block(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + user = change["title"].split(':', 1)[1] + try: + ipaddress.ip_address(user) + embed["url"] = create_article_path("Special:Contributions/{user}".format(user=user)) + except ValueError: + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + if "sitewide" not in change["logparams"]: + restriction_description = "" + if "restrictions" in change["logparams"]: + if "pages" in change["logparams"]["restrictions"] and change["logparams"]["restrictions"]["pages"]: + restriction_description = _("Blocked from editing the following pages: ") + restricted_pages = ["*" + i["page_title"] + "*" for i in change["logparams"]["restrictions"]["pages"]] + restriction_description = restriction_description + ", ".join(restricted_pages) + if "namespaces" in change["logparams"]["restrictions"] and change["logparams"]["restrictions"][ + "namespaces"]: + namespaces = [] + if restriction_description: + restriction_description = restriction_description + _(" and namespaces: ") + else: + restriction_description = _("Blocked from editing pages on following namespaces: ") + for namespace in change["logparams"]["restrictions"]["namespaces"]: + if str(namespace) in ctx.client.namespaces: # if we have cached namespace name for given namespace number, add its name to the list + namespaces.append("*{ns}*".format(ns=ctx.client.namespaces[str(namespace)]["*"])) + else: + namespaces.append("*{ns}*".format(ns=namespace)) + restriction_description = restriction_description + ", ".join(namespaces) + restriction_description = restriction_description + "." + if len(restriction_description) > 1020: + logger.debug(restriction_description) + restriction_description = restriction_description[:1020] + "…" + embed.add_field(_("Partial block details"), restriction_description, inline=True) + block_flags = change["logparams"].get("flags") + if block_flags: + embed.add_field(_("Block flags"), ", ".join( + block_flags)) # TODO Translate flags into MW messages, this requires making additional request in init_request since we want to get all messages with prefix (amprefix) block-log-flags- and that parameter is exclusive with ammessages + embed["title"] = _("Blocked {blocked_user} {time}").format(blocked_user=user, time=block_expiry(change)) + embed_helper(ctx, embed, change) + return embed + + +@formatter.compact(event="block/block", mode="compact") +def compact_block_block(ctx, change): + user = change["title"].split(':', 1)[1] + restriction_description = "" + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + try: + ipaddress.ip_address(user) + link = clean_link(create_article_path("Special:Contributions/{user}".format(user=user))) + except ValueError: + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + else: + if "sitewide" not in change["logparams"]: + if "restrictions" in change["logparams"]: + if "pages" in change["logparams"]["restrictions"] and change["logparams"]["restrictions"]["pages"]: + restriction_description = _(" on pages: ") + restricted_pages = ["*{page}*".format(page=i["page_title"]) for i in + change["logparams"]["restrictions"]["pages"]] + restriction_description = restriction_description + ", ".join(restricted_pages) + if "namespaces" in change["logparams"]["restrictions"] and change["logparams"]["restrictions"][ + "namespaces"]: + namespaces = [] + if restriction_description: + restriction_description = restriction_description + _(" and namespaces: ") + else: + restriction_description = _(" on namespaces: ") + for namespace in change["logparams"]["restrictions"]["namespaces"]: + if str(namespace) in ctx.client.namespaces: # if we have cached namespace name for given namespace number, add its name to the list + namespaces.append("*{ns}*".format(ns=ctx.client.namespaces[str(namespace)]["*"])) + else: + namespaces.append("*{ns}*".format(ns=namespace)) + restriction_description = restriction_description + ", ".join(namespaces) + restriction_description = restriction_description + "." + if len(restriction_description) > 1020: + logger.debug(restriction_description) + restriction_description = restriction_description[:1020] + "…" + content = _( + "[{author}]({author_url}) blocked [{user}]({user_url}) {time}{restriction_desc}{comment}").format(author=author, + author_url=author_url, + user=user, + time=block_expiry( + change), + user_url=link, + restriction_desc=restriction_description, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# block/reblock - Changing settings of a block +@formatter.embed(event="block/reblock", mode="embed") +def embed_block_reblock(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + user = change["title"].split(':', 1)[1] + embed["title"] = _("Changed block settings for {blocked_user}").format(blocked_user=sanitize_to_markdown(user)) + return embed + + +@formatter.compact(event="block/reblock") +def compact_block_reblock(ctx, change): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + user = change["title"].split(':', 1)[1] + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) changed block settings for [{blocked_user}]({user_url}){comment}").format( + author=author, author_url=author_url, blocked_user=sanitize_to_markdown(user), user_url=link, comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# block/unblock - Unblocking an user + +@formatter.embed(event="block/unblock", mode="embed") +def embed_block_unblock(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + user = change["title"].split(':', 1)[1] + embed["title"] = _("Unblocked {blocked_user}").format(blocked_user=sanitize_to_markdown(user)) + return embed + + +@formatter.compact(event="block/unblock") +def compact_block_unblock(ctx, change): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + user = change["title"].split(':', 1)[1] + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) unblocked [{blocked_user}]({user_url}){comment}").format(author=author, + author_url=author_url, + blocked_user=sanitize_to_markdown(user), + user_url=link, + comment=parsed_comment) + + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# suppressed - Custom event for whenever there is limited information available about the event due to revdel + + +@formatter.embed(event="suppressed", mode="embed") +def embed_suppressed(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed["url"] = create_article_path("") + embed["title"] = _("Action has been hidden by administration") + embed["author"]["name"] = _("Unknown") + return embed + + +@formatter.compact(event="suppressed", mode="compact") +def compact_suppressed(ctx, change): + content = _("An action has been hidden by administration.") + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# import/upload - Importing pages by uploading exported XML files + +@formatter.embed(event="import/upload", mode="embed") +def embed_import_upload(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = ngettext("Imported {article} with {count} revision", + "Imported {article} with {count} revisions", change["logparams"]["count"]).format( + article=sanitize_to_markdown(change["title"]), count=change["logparams"]["count"]) + return embed + + +@formatter.compact(event="import/upload", mode="compact") +def compact_import_upload(ctx, change): + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + content = ngettext("[{author}]({author_url}) imported [{article}]({article_url}) with {count} revision{comment}", + "[{author}]({author_url}) imported [{article}]({article_url}) with {count} revisions{comment}", + change["logparams"]["count"]).format( + author=author, author_url=author_url, article=sanitize_to_markdown(change["title"]), article_url=link, + count=change["logparams"]["count"], comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# import/interwiki - Importing interwiki entries + + +@formatter.embed(event="import/interwiki", mode="embed") +def embed_import_interwiki(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = ngettext("Imported {article} with {count} revision from \"{source}\"", + "Imported {article} with {count} revisions from \"{source}\"", + change["logparams"]["count"]).format( + article=sanitize_to_markdown(change["title"]), count=change["logparams"]["count"], + source=sanitize_to_markdown(change["logparams"]["interwiki_title"])) + return embed + + +@formatter.compact(event="import/interwiki", mode="compact") +def compact_import_interwiki(ctx, change): + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + author, author_url = compact_author(ctx, change) + source_link = clean_link(create_article_path(change["logparams"]["interwiki_title"])) + parsed_comment = compact_summary(ctx) + content = ngettext( + "[{author}]({author_url}) imported [{article}]({article_url}) with {count} revision from [{source}]({source_url}){comment}", + "[{author}]({author_url}) imported [{article}]({article_url}) with {count} revisions from [{source}]({source_url}){comment}", + change["logparams"]["count"]).format( + author=author, author_url=author_url, article=sanitize_to_markdown(change["title"]), article_url=link, + count=change["logparams"]["count"], source=sanitize_to_markdown(change["logparams"]["interwiki_title"]), + source_url=source_link, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# rights/rights - Assigning rights groups +def get_changed_groups(change: dict) -> [[str], [str]]: + """Creates strings comparing the changes between the user groups for the user""" + def expiry_parse_time(passed_time): + try: + return _(" (until {date_and_time})").format(date_and_time=datetime.datetime.strptime(passed_time, "%Y-%m-%dT%H:%M:%SZ").strftime("%Y-%m-%d %H:%M:%S UTC")) + except ValueError: + return "" + new_group_meta = {_(t["group"]): expiry_parse_time(t.get("expiry", "infinity")) for t in change["logparams"].get("newmetadata", [])} + # translate all groups and pull them into a set + old_groups = {_(x) for x in change["logparams"]["oldgroups"]} + new_groups = {_(x) for x in change["logparams"]["newgroups"]} + added = [x + new_group_meta.get(x, "") for x in new_groups - old_groups] + removed = [x for x in old_groups - new_groups] + return added, removed + + +@formatter.embed(event="rights/rights", aliases=["rights/autopromote"]) +def embed_rights_rights(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed["url"] = create_article_path(sanitize_to_url("User:{}".format(change["title"].split(":")[1]))) + if ctx.event == "rights/rights": + embed["title"] = _("Changed group membership for {target}").format(target=sanitize_to_markdown(change["title"].split(":")[1])) + else: + embed.set_author(_("System"), "") + embed["title"] = _("{target} got autopromoted to a new usergroup").format( + target=sanitize_to_markdown(change["title"].split(":")[1])) + # if len(change["logparams"]["oldgroups"]) < len(change["logparams"]["newgroups"]): + # embed["thumbnail"]["url"] = "https://i.imgur.com/WnGhF5g.gif" + added, removed = get_changed_groups(change) + if added: + embed.add_field(ngettext("Added group", "Added groups", len(added)), "\n".join(added), inline=True) + if removed: + embed.add_field(ngettext("Removed group", "Removed groups", len(removed)), "\n".join(removed), inline=True) + embed_helper(ctx, embed, change) + return embed + + +@formatter.compact(event="rights/rights", aliases=["rights/autopromote"]) +def compact_rights_rights(ctx, change): + link = clean_link(create_article_path(sanitize_to_url("User:{user}".format(user=change["title"].split(":")[1])))) + added, removed = get_changed_groups(change) + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + if ctx.event == "rights/rights": + group_changes = "Unknown group changes." # Because I don't know if it can handle time extensions correctly + if added and removed: + group_changes = _("Added to {added} and removed from {removed}.").format( + added=_(", ").join(added), removed=_(", ").join(removed)) + elif added: + group_changes = _("Added to {added}.").format(added=_(", ").join(added)) + elif removed: + group_changes = _("Removed from {removed}.").format(removed=_(", ").join(removed)) + content = _("[{author}]({author_url}) changed group membership for [{target}]({target_url}): {group_changes}{comment}").format( + author=author, author_url=author_url, target=sanitize_to_markdown(change["title"].split(":")[1]), + target_url=link, group_changes=group_changes, comment=parsed_comment) + else: + content = _("The system autopromoted [{target}]({target_url}) to {added}.{comment}").format( + target=sanitize_to_markdown(change["title"].split(":")[1]), target_url=link, + added=_(", ").join(added), comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# merge/merge - Merging histories of two pages + +@formatter.embed(event="merge/merge", mode="embed") +def embed_merge_merge(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Merged revision histories of {article} into {dest}").format( + article=sanitize_to_markdown(change["title"]), + dest=sanitize_to_markdown(change["logparams"][ + "dest_title"])) + return embed + + +@formatter.compact(event="merge/merge") +def compact_merge_merge(ctx, change): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + link_dest = clean_link(create_article_path(sanitize_to_url(change["logparams"]["dest_title"]))) + content = _( + "[{author}]({author_url}) merged revision histories of [{article}]({article_url}) into [{dest}]({dest_url}){comment}").format( + author=author, author_url=author_url, article=sanitize_to_markdown(change["title"]), article_url=link, dest_url=link_dest, + dest=sanitize_to_markdown(change["logparams"]["dest_title"]), comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# newusers/autocreate - Auto creation of user account + + +@formatter.embed(event="newusers/autocreate", mode="embed") +def embed_newusers_autocreate(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Created account automatically") + return embed + + +@formatter.compact(event="newusers/autocreate") +def compact_newusers_autocreate(ctx, change): + author, author_url = compact_author(ctx, change) + content = _("Account [{author}]({author_url}) was created automatically").format(author=author, + author_url=author_url) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# newusers/create - Auto creation of user account + + +@formatter.embed(event="newusers/create", mode="embed") +def embed_newusers_create(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Created account") + return embed + + +@formatter.compact(event="newusers/create") +def compact_newusers_create(ctx, change): + author, author_url = compact_author(ctx, change) + content = _("Account [{author}]({author_url}) was created").format(author=author, author_url=author_url) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# newusers/autocreate - Auto creation of user account + + +@formatter.embed(event="newusers/create2", mode="embed") +def embed_newusers_create2(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Created account {article}").format(article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="newusers/create2") +def compact_newusers_create2(ctx, change): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _("Account [{article}]({article_url}) was created by [{author}]({author_url}){comment}").format( + article=sanitize_to_markdown(change["title"]), article_url=link, author=author, author_url=author_url, comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# newusers/byemail - Creation of account by email + + +@formatter.embed(event="newusers/byemail", mode="embed") +def embed_newusers_byemail(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Created account {article} and password was sent by email").format( + article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="newusers/byemail") +def compact_newusers_byemail(ctx, change): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _( + "Account [{article}]({article_url}) was created by [{author}]({author_url}) and password was sent by email{comment}").format( + article=sanitize_to_markdown(change["title"]), article_url=link, author=author, author_url=author_url, comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# newusers/newusers - New users + + +@formatter.embed(event="newusers/newusers", mode="embed") +def embed_newusers_newusers(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url("User:{}".format(change["user"]))) + embed["title"] = _("Created account") + return embed + + +@formatter.compact(event="newusers/newusers") +def compact_newusers_newusers(ctx, change): + author, author_url = compact_author(ctx, change) + content = _("Account [{author}]({author_url}) was created").format(author=author, author_url=author_url) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# contentmodel/change - Changing the content model of a page + + +@formatter.embed(event="contentmodel/change", mode="embed") +def embed_contentmodel_change(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change, set_desc=False) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Changed the content model of the page {article}").format( + article=sanitize_to_markdown(change["title"])) + embed["description"] = _("Model changed from {old} to {new}: {reason}").format(old=change["logparams"]["oldmodel"], + new=change["logparams"]["newmodel"], + reason=ctx.parsedcomment) + return embed + + +@formatter.compact(event="contentmodel/change") +def compact_contentmodel_change(ctx, change): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + parsed_comment = compact_summary(ctx) + content = _( + "[{author}]({author_url}) changed the content model of the page [{article}]({article_url}) from {old} to {new}{comment}").format( + author=author, author_url=author_url, article=sanitize_to_markdown(change["title"]), article_url=link, + old=change["logparams"]["oldmodel"], + new=change["logparams"]["newmodel"], comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# contentmodel/new - Creating a page with non-default content model + + +@formatter.embed(event="contentmodel/new", mode="embed") +def embed_contentmodel_new(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change, set_desc=False) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Created the page {article} using a non-default content model").format( + article=sanitize_to_markdown(change["title"])) + embed["description"] = _("Created with model {new}: {reason}").format(new=change["logparams"]["newmodel"], + reason=ctx.parsedcomment) + return embed + + +@formatter.compact(event="contentmodel/new") +def compact_contentmodel_new(ctx, change): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + parsed_comment = compact_summary(ctx) + content = _( + "[{author}]({author_url}) created the page [{article}]({article_url}) using a non-default content model {new}{comment}").format( + author=author, author_url=author_url, article=sanitize_to_markdown(change["title"]), article_url=link, + new=change["logparams"]["newmodel"], comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# managetags/create - Creating log tags + + +@formatter.embed(event="managetags/create", mode="embed") +def embed_managetags_create(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + ctx.client.refresh_internal_data() + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Created the tag \"{tag}\"").format(tag=sanitize_to_markdown(change["logparams"]["tag"])) + return embed + + +@formatter.compact(event="managetags/create") +def compact_managetags_create(ctx, change): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + ctx.client.refresh_internal_data() + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) created the [tag]({tag_url}) \"{tag}\"{comment}").format(author=author, + author_url=author_url, + tag= + sanitize_to_markdown( + change[ + "logparams"][ + "tag"]), + tag_url=link, + comment=parsed_comment) + + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# managetags/delete - Deleting a tag + + +@formatter.embed(event="managetags/delete", mode="embed") +def embed_managetags_delete(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + ctx.client.refresh_internal_data() + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Deleted the tag \"{tag}\"").format(tag=sanitize_to_markdown(change["logparams"]["tag"])) + if change["logparams"]["count"] > 0: + embed.add_field(_('Removed from'), ngettext("{} revision or log entry", "{} revisions and/or log entries", + change["logparams"]["count"]).format(change["logparams"]["count"])) + embed_helper(ctx, embed, change) + return embed + + +@formatter.compact(event="managetags/delete") +def compact_managetags_delete(ctx, change): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + ctx.client.refresh_internal_data() + parsed_comment = compact_summary(ctx) + if change["logparams"]["count"] == 0: + content = _("[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\"{comment}").format(author=author, + author_url=author_url, + tag=sanitize_to_markdown( + change[ + "logparams"][ + "tag"]), + tag_url=link, + comment=parsed_comment) + else: + content = ngettext( + "[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\" and removed it from {count} revision or log entry{comment}", + "[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\" and removed it from {count} revisions and/or log entries{comment}", + change["logparams"]["count"]).format(author=author, author_url=author_url, + tag=sanitize_to_markdown(change["logparams"]["tag"]), + tag_url=link, count=change["logparams"]["count"], + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# managetags/activate - Activating a tag + + +@formatter.embed(event="managetags/activate", mode="embed") +def embed_managetags_activate(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Activated the tag \"{tag}\"").format(tag=sanitize_to_markdown(change["logparams"]["tag"])) + return embed + + +@formatter.compact(event="managetags/activate") +def compact_managetags_activate(ctx, change): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) activated the [tag]({tag_url}) \"{tag}\"{comment}").format(author=author, + author_url=author_url, + tag=sanitize_to_markdown( + change[ + "logparams"][ + "tag"]), + tag_url=link, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# managetags/deactivate - Deactivating a tag + + +@formatter.embed(event="managetags/deactivate", mode="embed") +def embed_managetags_deactivate(ctx, change): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Deactivated the tag \"{tag}\"").format(tag=sanitize_to_markdown(change["logparams"]["tag"])) + return embed + + +@formatter.compact(event="managetags/deactivate") +def compact_managetags_deactivate(ctx, change): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) deactivated the [tag]({tag_url}) \"{tag}\"{comment}").format(author=author, + author_url=author_url, + tag=sanitize_to_markdown( + change[ + "logparams"][ + "tag"]), + tag_url=link, + comment=parsed_comment) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) diff --git a/extensions/base/renameuser.py b/extensions/base/renameuser.py new file mode 100644 index 0000000..bdffbb4 --- /dev/null +++ b/extensions/base/renameuser.py @@ -0,0 +1,70 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + + +import logging +from src.discord.message import DiscordMessage +from src.api import formatter +from src.i18n import formatters_i18n +from src.api.context import Context +from src.api.util import embed_helper, compact_summary, clean_link, compact_author, create_article_path, sanitize_to_markdown, sanitize_to_url + +_ = formatters_i18n.gettext +ngettext = formatters_i18n.ngettext + + +# Renameuser - https://www.mediawiki.org/wiki/Extension:Renameuser +# renameuser/renameuser - Renaming a user + + +@formatter.embed(event="renameuser/renameuser") +def embed_renameuser_renameuser(ctx: Context, change: dict) -> DiscordMessage: + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + edits = change["logparams"]["edits"] + if edits > 0: + embed["title"] = ngettext("Renamed user \"{old_name}\" with {edits} edit to \"{new_name}\"", + "Renamed user \"{old_name}\" with {edits} edits to \"{new_name}\"", edits).format( + old_name=sanitize_to_markdown(change["logparams"]["olduser"]), edits=edits, + new_name=sanitize_to_markdown(change["logparams"]["newuser"])) + else: + embed["title"] = _("Renamed user \"{old_name}\" to \"{new_name}\"").format( + old_name=sanitize_to_markdown(change["logparams"]["olduser"]), + new_name=sanitize_to_markdown(change["logparams"]["newuser"])) + embed["url"] = create_article_path("User:" + sanitize_to_url(change["logparams"]["newuser"])) + return embed + + +@formatter.compact(event="renameuser/renameuser") +def compact_renameuser_renameuser(ctx: Context, change: dict) -> DiscordMessage: + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path("User:" + sanitize_to_url(change["logparams"]["newuser"]))) + edits = change["logparams"]["edits"] + parsed_comment = compact_summary(ctx) + if edits > 0: + content = ngettext( + "[{author}]({author_url}) renamed user *{old_name}* with {edits} edit to [{new_name}]({link}){comment}", + "[{author}]({author_url}) renamed user *{old_name}* with {edits} edits to [{new_name}]({link}){comment}", + edits).format( + author=author, author_url=author_url, old_name=sanitize_to_markdown(change["logparams"]["olduser"]), + edits=edits, + new_name=sanitize_to_markdown(change["logparams"]["newuser"]), link=link, comment=parsed_comment + ) + else: + content = _("[{author}]({author_url}) renamed user *{old_name}* to [{new_name}]({link}){comment}").format( + author=author, author_url=author_url, old_name=sanitize_to_markdown(change["logparams"]["olduser"]), + new_name=sanitize_to_markdown(change["logparams"]["newuser"]), link=link, comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) diff --git a/extensions/base/sprite.py b/extensions/base/sprite.py new file mode 100644 index 0000000..cd3423d --- /dev/null +++ b/extensions/base/sprite.py @@ -0,0 +1,91 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +import logging +from src.discord.message import DiscordMessage +from src.api import formatter +from src.i18n import formatters_i18n +from src.api.context import Context +from src.api.util import embed_helper, compact_author, create_article_path, sanitize_to_markdown, sanitize_to_url, \ + clean_link + +_ = formatters_i18n.gettext +ngettext = formatters_i18n.ngettext + + +# SpriteSheet - https://www.mediawiki.org/wiki/Extension:SpriteSheet +# sprite/sprite - Editing a sprite + + +@formatter.embed(event="sprite/sprite") +def embed_sprite_sprite(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Edited the sprite for {article}").format(article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="sprite/sprite") +def compact_sprite_sprite(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _("[{author}]({author_url}) edited the sprite for [{article}]({article_url})").format(author=author, + author_url=author_url, + article=sanitize_to_markdown(change[ + "title"]), + article_url=link) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# sprite/sheet - Creating a sprite sheet + + +@formatter.embed(event="sprite/sheet") +def embed_sprite_sheet(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Created the sprite sheet for {article}").format(article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="sprite/sheet") +def compact_sprite_sheet(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _("[{author}]({author_url}) created the sprite sheet for [{article}]({article_url})").format(author=author, author_url=author_url, article=sanitize_to_markdown(change["title"]), article_url=link) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# sprite/slice - Editing a slice + + +@formatter.embed(event="sprite/slice") +def embed_sprite_slice(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Edited the slice for {article}").format(article=sanitize_to_markdown(change["title"])) + return embed + +@formatter.compact(event="sprite/slice") +def compact_sprite_slice(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _("[{author}]({author_url}) edited the slice for [{article}]({article_url})").format(author=author, + author_url=author_url, + article=sanitize_to_markdown(change[ + "title"]), + article_url=link) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) diff --git a/extensions/base/translate.py b/extensions/base/translate.py new file mode 100644 index 0000000..68349cc --- /dev/null +++ b/extensions/base/translate.py @@ -0,0 +1,482 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +import logging +from src.discord.message import DiscordMessage +from src.api import formatter +from src.i18n import formatters_i18n +from src.api.context import Context +from src.api.util import embed_helper, compact_author, create_article_path, sanitize_to_markdown, sanitize_to_url, \ + clean_link, compact_summary + +_ = formatters_i18n.gettext +ngettext = formatters_i18n.ngettext + +# I cried when I realized I have to migrate Translate extension logs, but this way I atone for my countless sins +# Translate - https://www.mediawiki.org/wiki/Extension:Translate +# pagetranslation/mark - Marking a page for translation + + +@formatter.embed(event="pagetranslation/mark") +def embed_pagetranslation_mark(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + link = create_article_path(sanitize_to_url(change["title"])) + if "?" in link: + embed["url"] = link + "&oldid={}".format(change["logparams"]["revision"]) + else: + embed["url"] = link + "?oldid={}".format(change["logparams"]["revision"]) + embed["title"] = _("Marked \"{article}\" for translation").format(article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="pagetranslation/mark") +def compact_pagetranslation_mark(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + link = create_article_path(sanitize_to_url(change["title"])) + if "?" in link: + link = link + "&oldid={}".format(change["logparams"]["revision"]) + else: + link = link + "?oldid={}".format(change["logparams"]["revision"]) + link = clean_link(link) + parsed_comment = compact_summary(ctx) + content = _("[{author}]({author_url}) marked [{article}]({article_url}) for translation{comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# pagetranslation/unmark - Removing a page from translation system + + +@formatter.embed(event="pagetranslation/unmark") +def embed_pagetranslation_unmark(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Removed \"{article}\" from the translation system").format(article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="pagetranslation/unmark") +def compact_pagetranslation_unmark(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _( + "[{author}]({author_url}) removed [{article}]({article_url}) from the translation system{comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# pagetranslation/moveok - Completed moving translation page + + +@formatter.embed(event="pagetranslation/moveok") +def embed_pagetranslation_moveok(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["logparams"]["target"])) + embed["title"] = _("Completed moving translation pages from \"{article}\" to \"{target}\"").format( + article=sanitize_to_markdown(change["title"]), target=sanitize_to_markdown(change["logparams"]["target"])) + return embed + + +@formatter.compact(event="pagetranslation/moveok") +def compact_pagetranslation_moveok(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["logparams"]["target"]))) + content = _( + "[{author}]({author_url}) completed moving translation pages from *{article}* to [{target}]({target_url}){comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), target=sanitize_to_markdown(change["logparams"]["target"]), + target_url=link, comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# pagetranslation/movenok - Failed while moving translation page + + +@formatter.embed(event="pagetranslation/movenok") +def embed_pagetranslation_movenok(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Encountered a problem while moving \"{article}\" to \"{target}\"").format( + article=sanitize_to_markdown(change["title"]), target=sanitize_to_markdown(change["logparams"]["target"])) + return embed + + +@formatter.compact(event="pagetranslation/movenok") +def compact_pagetranslation_movenok(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + target_url = clean_link(create_article_path(sanitize_to_url(change["logparams"]["target"]))) + content = _( + "[{author}]({author_url}) encountered a problem while moving [{article}]({article_url}) to [{target}]({target_url}){comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + target=sanitize_to_markdown(change["logparams"]["target"]), target_url=target_url, + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# pagetranslation/deletefnok - Failure in deletion of translatable page + + +@formatter.embed(event="pagetranslation/deletefnok") +def embed_pagetranslation_deletefnok(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Failed to delete \"{article}\" which belongs to translatable page \"{target}\"").format( + article=sanitize_to_markdown(change["title"]), target=sanitize_to_markdown(change["logparams"]["target"])) + return embed + + +@formatter.compact(event="pagetranslation/deletefnok") +def compact_pagetranslation_deletefnok(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + target_url = clean_link(create_article_path(sanitize_to_url(change["logparams"]["target"]))) + content = _( + "[{author}]({author_url}) failed to delete [{article}]({article_url}) which belongs to translatable page [{target}]({target_url}){comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + target=sanitize_to_markdown(change["logparams"]["target"]), target_url=target_url, + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# pagetranslation/deletelok - Completion in deleting a page? + + +@formatter.embed(event="pagetranslation/deletelok") +def embed_pagetranslation_deletelok(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Completed deletion of translation page \"{article}\"").format( + article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="pagetranslation/deletelok") +def compact_pagetranslation_deletelok(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _( + "[{author}]({author_url}) completed deletion of translation page [{article}]({article_url}){comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# pagetranslation/deletelnok - Failure in deletion of article belonging to a translation page + + +@formatter.embed(event="pagetranslation/deletelnok") +def embed_pagetranslation_deletelnok(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Failed to delete \"{article}\" which belongs to translation page \"{target}\"").format( + article=sanitize_to_markdown(change["title"]), target=sanitize_to_markdown(change["logparams"]["target"])) + return embed + + +@formatter.compact(event="pagetranslation/deletelnok") +def compact_pagetranslation_deletelnok(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + target_url = clean_link(create_article_path(sanitize_to_url(change["logparams"]["target"]))) + content = _( + "[{author}]({author_url}) failed to delete [{article}]({article_url}) which belongs to translation page [{target}]({target_url}){comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + target=sanitize_to_markdown(change["logparams"]["target"]), target_url=target_url, + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# pagetranslation/encourage - Encouraging to translate an article + + +@formatter.embed(event="pagetranslation/encourage") +def embed_pagetranslation_encourage(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Encouraged translation of \"{article}\"").format(article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="pagetranslation/encourage") +def compact_pagetranslation_encourage(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _("[{author}]({author_url}) encouraged translation of [{article}]({article_url}){comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# pagetranslation/discourage - Discouraging to translate an article + + +@formatter.embed(event="pagetranslation/discourage") +def embed_pagetranslation_discourage(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Discouraged translation of \"{article}\"").format(article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="pagetranslation/discourage") +def compact_pagetranslation_discourage(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _("[{author}]({author_url}) discouraged translation of [{article}]({article_url}){comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# pagetranslation/prioritylanguages - Changing the priority of translations? + + +@formatter.embed(event="pagetranslation/prioritylanguages") +def embed_pagetranslation_prioritylanguages(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + if "languages" in change["logparams"]: + languages = "`, `".join(change["logparams"]["languages"].split(",")) + if change["logparams"]["force"] == "on": + embed["title"] = _("Limited languages for \"{article}\" to `{languages}`").format(article=sanitize_to_markdown(change["title"]), + languages=languages) + else: + embed["title"] = _("Priority languages for \"{article}\" set to `{languages}`").format( + article=sanitize_to_markdown(change["title"]), languages=languages) + else: + embed["title"] = _("Removed priority languages from \"{article}\"").format(article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="pagetranslation/prioritylanguages") +def compact_pagetranslation_prioritylanguages(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + if "languages" in change["logparams"]: + languages = "`, `".join(change["logparams"]["languages"].split(",")) + if change["logparams"]["force"] == "on": + content = _( + "[{author}]({author_url}) limited languages for [{article}]({article_url}) to `{languages}`{comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + languages=languages, comment=parsed_comment + ) + else: + content = _( + "[{author}]({author_url}) set the priority languages for [{article}]({article_url}) to `{languages}`{comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + languages=languages, comment=parsed_comment + ) + else: + content = _( + "[{author}]({author_url}) removed priority languages from [{article}]({article_url}){comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + + +# pagetranslation/associate - Adding an article to translation group + + +@formatter.embed(event="pagetranslation/associate") +def embed_pagetranslation_associate(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Added translatable page \"{article}\" to aggregate group \"{group}\"").format( + article=sanitize_to_markdown(change["title"]), group=change["logparams"]["aggregategroup"]) + return embed + + +@formatter.compact(event="pagetranslation/associate") +def compact_pagetranslation_associate(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _( + "[{author}]({author_url}) added translatable page [{article}]({article_url}) to aggregate group \"{group}\"{comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + group=change["logparams"]["aggregategroup"], comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# pagetranslation/dissociate - Removing an article from translation group + + +@formatter.embed(event="pagetranslation/dissociate") +def embed_pagetranslation_dissociate(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Removed translatable page \"{article}\" from aggregate group \"{group}\"").format( + article=sanitize_to_markdown(change["title"]), group=change["logparams"]["aggregategroup"]) + return embed + + +@formatter.compact(event="pagetranslation/dissociate") +def compact_pagetranslation_dissociate(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + content = _( + "[{author}]({author_url}) removed translatable page [{article}]({article_url}) from aggregate group \"{group}\"{comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + group=change["logparams"]["aggregategroup"], comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# translationreview/message - Reviewing translation + + +@formatter.embed(event="translationreview/message") +def embed_translationreview_message(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + link = create_article_path(sanitize_to_url(change["title"])) + if "?" in link: + embed["url"] = link + "&oldid={}".format(change["logparams"]["revision"]) + else: + embed["url"] = link + "?oldid={}".format(change["logparams"]["revision"]) + embed["title"] = _("Reviewed translation \"{article}\"").format(article=sanitize_to_markdown(change["title"])) + return embed + + +@formatter.compact(event="translationreview/message") +def compact_translationreview_message(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = create_article_path(sanitize_to_url(change["title"])) + if "?" in link: + link = link + "&oldid={}".format(change["logparams"]["revision"]) + else: + link = link + "?oldid={}".format(change["logparams"]["revision"]) + link = clean_link(link) + content = _("[{author}]({author_url}) reviewed translation [{article}]({article_url}){comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# translationreview/group - Changing of state for group translation? + + +@formatter.embed(event="translationreview/group") +def embed_translationreview_group(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + embed["title"] = _("Changed the state of `{language}` translations of \"{article}\"").format( + language=change["logparams"]["language"], article=sanitize_to_markdown(change["title"])) + if "old-state" in change["logparams"]: + embed.add_field(_("Old state"), change["logparams"]["old-state"], inline=True) + embed.add_field(_("New state"), change["logparams"]["new-state"], inline=True) + return embed + + +@formatter.compact(event="translationreview/group") +def compact_translationreview_group(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + if "old-state" in change["logparams"]: + content = _( + "[{author}]({author_url}) changed the state of `{language}` translations of [{article}]({article_url}) from `{old_state}` to `{new_state}`{comment}").format( + author=author, author_url=author_url, language=change["logparams"]["language"], + article=sanitize_to_markdown(change["logparams"]["group-label"]), article_url=link, + old_state=change["logparams"]["old-state"], new_state=change["logparams"]["new-state"], + comment=parsed_comment + ) + else: + content = _( + "[{author}]({author_url}) changed the state of `{language}` translations of [{article}]({article_url}) to `{new_state}`{comment}").format( + author=author, author_url=author_url, language=change["logparams"]["language"], + article=sanitize_to_markdown(change["logparams"]["group-label"]), article_url=link, + new_state=change["logparams"]["new-state"], comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) + +# pagelang/pagelang - Changing the language of a page + + +def get_languages(change): + old_lang = "`{}`".format(change["logparams"]["oldlanguage"]) + if change["logparams"]["oldlanguage"][-5:] == "[def]": + old_lang = "`{}` {}".format(change["logparams"]["oldlanguage"][:-5], _("(default)")) + new_lang = "`{}`".format(change["logparams"]["newlanguage"]) + if change["logparams"]["newlanguage"][-5:] == "[def]": + new_lang = "`{}` {}".format(change["logparams"]["oldlanguage"][:-5], _("(default)")) + return old_lang, new_lang + +@formatter.embed(event="pagelang/pagelang") +def embed_pagelang_pagelang(ctx: Context, change: dict): + embed = DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url) + embed_helper(ctx, embed, change) + embed["url"] = create_article_path(sanitize_to_url(change["title"])) + old_lang, new_lang = get_languages(change) + embed["title"] = _("Changed the language of \"{article}\"").format(article=sanitize_to_markdown(change["title"])) + embed.add_field(_("Old language"), old_lang, inline=True) + embed.add_field(_("New language"), new_lang, inline=True) + return embed + + +@formatter.compact(event="pagelang/pagelang") +def compact_pagelang_pagelang(ctx: Context, change: dict): + author, author_url = compact_author(ctx, change) + parsed_comment = compact_summary(ctx) + link = clean_link(create_article_path(sanitize_to_url(change["title"]))) + old_lang, new_lang = get_languages(change) + content = _( + "[{author}]({author_url}) changed the language of [{article}]({article_url}) from {old_lang} to {new_lang}{comment}").format( + author=author, author_url=author_url, + article=sanitize_to_markdown(change["title"]), article_url=link, + old_lang=old_lang, new_lang=new_lang, comment=parsed_comment + ) + return DiscordMessage(ctx.message_type, ctx.event, ctx.webhook_url, content=content) diff --git a/extensions/hooks/__init__.py b/extensions/hooks/__init__.py new file mode 100644 index 0000000..669ca03 --- /dev/null +++ b/extensions/hooks/__init__.py @@ -0,0 +1,16 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +import extensions.hooks.example_hook \ No newline at end of file diff --git a/extensions/hooks/edit_alerts.py b/extensions/hooks/edit_alerts.py new file mode 100644 index 0000000..4339aff --- /dev/null +++ b/extensions/hooks/edit_alerts.py @@ -0,0 +1,133 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +from src.api.hook import post_hook +from src.configloader import settings + +# { +# "hooks": { +# "edit_alerts": [ +# { +# "content": "DISCORD MARKDOWN TEXT", +# "allowed_mentions": { +# "users": ["USERID"], +# "roles": ["ROLEID"] +# }, +# "requirements": [ +# { +# "action": [ +# "edit", +# "delete/delete", +# "delete" +# ], +# "user": [ +# "USERNAME", +# "@__anon__", +# "@__user__" +# ], +# "title": [ +# "PAGETITLE" +# ], +# "tags": [ +# ["EDIT TAG", "AND EDIT TAG"], +# ["OR EDIT TAG"] +# ], +# "categories": [ +# { +# "added": [ +# ["CATEGORY", "AND CATEGORY"], +# ["OR CATEGORY"] +# ], +# "removed": [ +# ["CATEGORY", "AND CATEGORY"], +# ["OR CATEGORY"] +# ] +# } +# ] +# } +# ] +# } +# ] +# } +# } +edit_alerts = settings.get("hooks", {}).get("edit_alerts", []) + + +class RequirementNotMet(Exception): + """Exception raised when the requirement is not met and another requirement must be processed""" + pass + + +def check_group_requirements(change_data: list, settings_data: list): + """This function resolves group discussions and raises RequirementNotMet when requirement is not met""" + if settings_data: + for required_group in settings_data: + # test all items in required_group are in change_data (one group fulfills the requirement) return the function + for required_item in required_group: + if required_item not in change_data: + break + else: + break + else: + raise RequirementNotMet + + + +@post_hook +def edit_alerts_hook(message, metadata, context, change): + # For every alert in edit_alerts, they can have different functions and so on + for alert in edit_alerts: + # For every requirement, if one of the requirements passes the alert gets executed + for requirement in alert.get("requirements", []): + try: + req_action = requirement.get("action", []) + # If current action isn't in config for this requirement AND current event type is not in the requirements in settings skip this requirement + if req_action and context.event not in req_action and context.event.split('/', 1)[0] not in req_action: + raise RequirementNotMet + req_user = requirement.get("user", []) + # If current user is not in config AND checkings for anon and user fail + if req_user and change["user"] not in req_user and ("@__anon__" if "anon" in change else "@__user__") not in req_user: + raise RequirementNotMet + req_title = requirement.get("title", []) + if req_title and change["title"] not in req_title: + raise RequirementNotMet + check_group_requirements(change.get("tags", []), requirement.get("tags", [])) + if requirement.get("categories", []): + for req_cats in requirement.get("categories", []): + try: + check_group_requirements(context.categories.new, req_cats.get("added", [])) + check_group_requirements(context.categories.removed, req_cats.get("removed", [])) + except RequirementNotMet: + continue + else: + break + else: + raise RequirementNotMet + except RequirementNotMet: + continue + else: + break + else: + continue + message.webhook_object["content"] = (message.webhook_object.get("content", "") or "") + alert["content"] + allowed_mentions = message.webhook_object["allowed_mentions"] + if alert.get("allowed_mentions", {}).get("users", []): + if not allowed_mentions.get("users", []): + allowed_mentions["users"] = [] + allowed_mentions["users"].extend(alert["allowed_mentions"]["users"]) + if alert.get("allowed_mentions", {}).get("roles", []): + if not allowed_mentions.get("roles", []): + allowed_mentions["roles"] = [] + allowed_mentions["roles"].extend(alert["allowed_mentions"]["roles"]) diff --git a/extensions/hooks/example_hook.py b/extensions/hooks/example_hook.py new file mode 100644 index 0000000..ec7f889 --- /dev/null +++ b/extensions/hooks/example_hook.py @@ -0,0 +1,28 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +from src.api.hook import pre_hook, post_hook + + +@pre_hook +def example_pre_hook(context, change): + if context.event == "edit": + print("I'm an edit with {} bytes changed!".format(change.get("newlen", 0) - change.get("oldlen", 0))) + + +@post_hook +def example_post_hook(message, metadata, context, change): + print("Our Discord message looks as follows: ") + print(message) diff --git a/extensions/hooks/usertalk.py b/extensions/hooks/usertalk.py new file mode 100644 index 0000000..75911aa --- /dev/null +++ b/extensions/hooks/usertalk.py @@ -0,0 +1,38 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +from src.api.hook import post_hook +from src.configloader import settings + +# { +# "hooks": { +# "usertalk": { +# "USERNAME": "USERID" +# } +# } +# } +discord_users = settings.get("hooks", {}).get("usertalk", {}) + +@post_hook +def usertalk_hook(message, metadata, context, change): + if discord_users and change["ns"] in [2, 3, 202] and not "/" in change["title"]: + username = change["title"].split(':', 1)[1] + if discord_users.get(username, "") and username != change["user"]: + message.webhook_object["content"] = (message.webhook_object.get("content", "") or "") + " <@{}>".format(discord_users[username]) + if message.webhook_object["allowed_mentions"].get("users", []): + if discord_users[username] not in message.webhook_object["allowed_mentions"]["users"]: + message.webhook_object["allowed_mentions"]["users"].append(discord_users[username]) + else: + message.webhook_object["allowed_mentions"]["users"] = [discord_users[username]] diff --git a/locale/bn/LC_MESSAGES/discussion_formatters.mo b/locale/bn/LC_MESSAGES/discussion_formatters.mo deleted file mode 100644 index 58a9365..0000000 Binary files a/locale/bn/LC_MESSAGES/discussion_formatters.mo and /dev/null differ diff --git a/locale/bn/LC_MESSAGES/discussion_formatters.po b/locale/bn/LC_MESSAGES/discussion_formatters.po deleted file mode 100644 index a0ce3aa..0000000 --- a/locale/bn/LC_MESSAGES/discussion_formatters.po +++ /dev/null @@ -1,184 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the RcGcDw package. -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: RcGcDw\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-30 11:58+0100\n" -"PO-Revision-Date: 2020-12-30 13:26+0000\n" -"Last-Translator: Creeper \n" -"Language-Team: Bengali \n" -"Language: bn\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.2.1\n" - -#: src/discussion_formatters.py:25 src/discussion_formatters.py:81 -msgid "Unregistered user" -msgstr "রেজিস্টার না করা ব্যাবহারকারি" - -#: src/discussion_formatters.py:34 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created [{title}](<{url}f/p/{threadId}>) in " -"{forumName}" -msgstr "" -"[{author}]({author_url}) {forumName}তে [{title}](<{url}f/p/{threadId}>) " -"বানিয়েছে" - -#: src/discussion_formatters.py:36 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created a poll [{title}](<{url}f/p/{threadId}>) in " -"{forumName}" -msgstr "" -"[{author}]({author_url}) {forumName}এ পোল [{title}](<{url}f/p/{threadId}>) " -"বানিয়েছে" - -#: src/discussion_formatters.py:38 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created a quiz [{title}](<{url}f/p/{threadId}>) in " -"{forumName}" -msgstr "" -"[{author}]({author_url}) {forumName}তে একটি কুইজ [{title}](<{url}f/p/" -"{threadId}>) বানিয়েছে" - -#: src/discussion_formatters.py:43 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created a [reply](<{url}f/p/{threadId}/r/{postId}>) " -"to [{title}](<{url}f/p/{threadId}>) in {forumName}" -msgstr "" -"[{author}]({author_url}) {forumName}এ [{title}](<{url}f/p/{threadId}>)তে একটি" -" [উত্তর](<{url}f/p/{threadId}/r/{postId}>) দিয়েছে" - -#: src/discussion_formatters.py:45 src/discussion_formatters.py:54 -#: src/discussion_formatters.py:137 src/discussion_formatters.py:150 -msgid "unknown" -msgstr "অজানা" - -#: src/discussion_formatters.py:49 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created [{title}](<{url}wiki/Message_Wall:" -"{user_wall}?threadId={threadId}>) on [{user}'s Message Wall](<{url}wiki/" -"Message_Wall:{user_wall}>)" -msgstr "" -"[{author}]({author_url}) [{user}এর মেসেজ ওয়ালে](<{url}wiki/" -"Message_Wall:{user_wall}>)এ [{title}](<{url}wiki/" -"Message_Wall:{user_wall}?threadId={threadId}>) বানিয়েছে" - -#: src/discussion_formatters.py:51 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created a [reply](<{url}wiki/Message_Wall:" -"{user_wall}?threadId={threadId}#{replyId}>) to [{title}](<{url}wiki/" -"Message_Wall:{user_wall}?threadId={threadId}>) on [{user}'s Message Wall]" -"(<{url}wiki/Message_Wall:{user_wall}>)" -msgstr "" -"[{author}]({author_url}) [{user}এর মেসেজ ওয়ালে](<{url}wiki/" -"Message_Wall:{user_wall}>) [{title}](<{url}wiki/" -"Message_Wall:{user_wall}?threadId={threadId}>)তে একটি [উত্তর](<{url}wiki/" -"Message_Wall:{user_wall}?threadId={threadId}#{replyId}>) দিয়েছে" - -#: src/discussion_formatters.py:57 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created a [comment](<{url}?commentId={commentId}>) " -"on [{article}](<{url}>)" -msgstr "" -"[{author}]({author_url}) [{article}](<{url}>)এ একটি " -"[কমেন্ট](<{url}?commentId={commentId}>) লিখেছে" - -#: src/discussion_formatters.py:62 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created a [reply](<{url}?commentId={commentId}" -"&replyId={replyId}>) to a [comment](<{url}?commentId={commentId}>) on " -"[{article}](<{url}>)" -msgstr "" -"[{author}]({author_url}) [{article}](<{url}>)এর একটি " -"[কমেন্ট](<{url}?commentId={commentId}>)এ একটি " -"[উত্তর](<{url}?commentId={commentId}&replyId={replyId}>) দিয়েছে" - -#: src/discussion_formatters.py:70 -#, python-brace-format -msgid "" -"Unknown event `{event}` by [{author}]({author_url}), report it on the " -"[support server](<{support}>)." -msgstr "" -"[{author}]({author_url})দ্বারা অজানা ঘটনা `{event}` , [সাহায্য " -"সার্ভারে](<{support}>) রিপোর্ট করুন।" - -#: src/discussion_formatters.py:98 -#, python-brace-format -msgid "Created \"{title}\"" -msgstr "\"{title}\" বানানো হলো" - -#: src/discussion_formatters.py:102 -#, python-brace-format -msgid "Created a poll \"{title}\"" -msgstr "পোল \"{title}\" বানানো হলো" - -#: src/discussion_formatters.py:109 -msgid "Option {}" -msgstr "বিকল্প {}" - -#: src/discussion_formatters.py:110 -#, python-brace-format -msgid "__[View image]({image_url})__" -msgstr "__[চিত্র দেখুন]({image_url})__" - -#: src/discussion_formatters.py:114 -#, python-brace-format -msgid "Created a quiz \"{title}\"" -msgstr "একটি কুইজ \"{title}\" বানানো হলো" - -#: src/discussion_formatters.py:129 src/discussion_formatters.py:131 -msgid "Tags" -msgstr "ট্যাগ" - -#: src/discussion_formatters.py:129 -msgid "{} tags" -msgstr "{}টি ট্যাগ" - -#: src/discussion_formatters.py:134 -#, python-brace-format -msgid "Replied to \"{title}\"" -msgstr "\"{title}\"এ উত্তর দেওয়া হলো" - -#: src/discussion_formatters.py:143 -#, python-brace-format -msgid "Created \"{title}\" on {user}'s Message Wall" -msgstr "{user}এর মেসেজ ওয়ালে \"{title}\" বানানো হলো" - -#: src/discussion_formatters.py:147 -#, python-brace-format -msgid "Replied to \"{title}\" on {user}'s Message Wall" -msgstr "{user}এর মেসেজ ওয়ালের \"{title}\"তে উত্তর দেওয়া হলো" - -#: src/discussion_formatters.py:154 -#, python-brace-format -msgid "Commented on {article}" -msgstr "{article}এ কমেন্ট করা হলো" - -#: src/discussion_formatters.py:158 -#, python-brace-format -msgid "Replied to a comment on {article}" -msgstr "{article}এর একটি কমেন্টে উত্তর দেওয়া হলো" - -#: src/discussion_formatters.py:162 -#, python-brace-format -msgid "Unknown event `{event}`" -msgstr "অজানা ঘটনা `{event}`" - -#: src/discussion_formatters.py:168 src/discussion_formatters.py:170 -msgid "Report this on the support server" -msgstr "এটিকে সাহায্য সার্ভারে রিপোর্ট করুন" diff --git a/locale/bn/LC_MESSAGES/formatters.mo b/locale/bn/LC_MESSAGES/formatters.mo new file mode 100644 index 0000000..7c7f9ba Binary files /dev/null and b/locale/bn/LC_MESSAGES/formatters.mo differ diff --git a/locale/bn/LC_MESSAGES/rc_formatters.po b/locale/bn/LC_MESSAGES/formatters.po similarity index 52% rename from locale/bn/LC_MESSAGES/rc_formatters.po rename to locale/bn/LC_MESSAGES/formatters.po index 764eaab..7e86532 100644 --- a/locale/bn/LC_MESSAGES/rc_formatters.po +++ b/locale/bn/LC_MESSAGES/formatters.po @@ -7,696 +7,763 @@ msgid "" msgstr "" "Project-Id-Version: RcGcDw\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-30 11:58+0100\n" -"PO-Revision-Date: 2021-04-14 14:22+0000\n" -"Last-Translator: R4356th \n" -"Language-Team: Bengali \n" +"POT-Creation-Date: 2021-05-22 18:48+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" "Language: bn\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.4.2\n" -#: src/rc_formatters.py:28 -msgid "None" -msgstr "কিছুই না" - -#: src/rc_formatters.py:28 -msgid "Warning issued" -msgstr "সতর্কতা জারি করা হয়েছে" - -#: src/rc_formatters.py:28 -msgid "**Blocked user**" -msgstr "**অবরুদ্ধ ব্যবহারকারী**" - -#: src/rc_formatters.py:28 -msgid "Tagged the edit" -msgstr "সম্পাদনা ট্যাগ করা হয়েছিল" - -#: src/rc_formatters.py:28 -msgid "Disallowed the action" +#: src/api/util.py:61 src/api/util.py:66 +msgid "__Only whitespace__" msgstr "" -#: src/rc_formatters.py:28 -msgid "**IP range blocked**" +#: src/api/util.py:71 +msgid "Removed" msgstr "" -#: src/rc_formatters.py:28 -msgid "Throttled actions" +#: src/api/util.py:73 +msgid "Added" msgstr "" -#: src/rc_formatters.py:28 -msgid "Removed autoconfirmed group" -msgstr "" - -#: src/rc_formatters.py:28 -msgid "**Removed from privileged groups**" -msgstr "" - -#: src/rc_formatters.py:29 -msgid "Edit" -msgstr "সম্পাদনা" - -#: src/rc_formatters.py:29 -msgid "Upload" -msgstr "আপলোড" - -#: src/rc_formatters.py:29 -msgid "Move" -msgstr "সরানো" - -#: src/rc_formatters.py:29 -msgid "Stash upload" -msgstr "স্ট্যাশ আপলোড" - -#: src/rc_formatters.py:29 -msgid "Deletion" -msgstr "" - -#: src/rc_formatters.py:29 -msgid "Account creation" -msgstr "" - -#: src/rc_formatters.py:29 -msgid "Auto account creation" -msgstr "" - -#: src/rc_formatters.py:46 src/rc_formatters.py:53 src/rc_formatters.py:60 -#: src/rc_formatters.py:75 src/rc_formatters.py:96 +#: src/api/util.py:94 src/api/util.py:126 src/api/util.py:133 +#: src/api/util.py:141 extensions/base/discussions.py:247 +#: extensions/base/discussions.py:264 extensions/base/abusefilter.py:45 msgid "Unregistered user" msgstr "" -#: src/rc_formatters.py:83 -#, python-brace-format -msgid "" -"[{author}]({author_url}) triggered *{abuse_filter}*, performing the action " -"\"{action}\" on *[{target}]({target_url})* - action taken: {result}." +#: src/api/util.py:160 +msgctxt "recent changes Tags" +msgid "Tags" msgstr "" -#: src/rc_formatters.py:85 src/rc_formatters.py:86 src/rc_formatters.py:87 -#: src/rc_formatters.py:449 src/rc_formatters.py:452 src/rc_formatters.py:455 -#: src/rc_formatters.py:456 src/rc_formatters.py:461 src/rc_formatters.py:462 -#: src/rc_formatters.py:470 src/rc_formatters.py:474 src/rc_formatters.py:650 -#: src/rc_formatters.py:651 src/rc_formatters.py:652 src/rc_formatters.py:1103 -#: src/rc_formatters.py:1106 src/rc_formatters.py:1109 -#: src/rc_formatters.py:1111 src/rc_formatters.py:1114 -#: src/rc_formatters.py:1116 src/rc_formatters.py:1122 -#: src/rc_formatters.py:1125 src/rc_formatters.py:1200 -msgid "Unknown" +#: src/api/util.py:162 +msgid "**Added**: " msgstr "" -#: src/rc_formatters.py:116 -#, python-brace-format -msgid "" -"[{author}]({author_url}) edited [{article}]({edit_link}){comment} {bold}" -"({sign}{edit_size}){bold}" +#: src/api/util.py:163 +msgid " and {} more\n" msgstr "" -#: src/rc_formatters.py:118 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created [{article}]({edit_link}){comment} {bold}" -"({sign}{edit_size}){bold}" +#: src/api/util.py:165 +msgid "**Removed**: " msgstr "" -#: src/rc_formatters.py:121 -#, python-brace-format -msgid "[{author}]({author_url}) uploaded [{file}]({file_link}){comment}" +#: src/api/util.py:166 +msgid " and {} more" msgstr "" -#: src/rc_formatters.py:128 -#, python-brace-format -msgid "" -"[{author}]({author_url}) reverted a version of [{file}]({file_link}){comment}" +#: src/api/util.py:168 +msgid "Changed categories" msgstr "" -#: src/rc_formatters.py:132 +#: extensions/base/cargo.py:37 #, python-brace-format -msgid "" -"[{author}]({author_url}) uploaded a new version of [{file}]({file_link})" -"{comment}" +msgid "Created the Cargo table \"{table}\"" msgstr "" -#: src/rc_formatters.py:135 -#, python-brace-format -msgid "[{author}]({author_url}) deleted [{page}]({page_link}){comment}" -msgstr "" - -#: src/rc_formatters.py:141 -#, python-brace-format -msgid "" -"[{author}]({author_url}) deleted redirect by overwriting [{page}]" -"({page_link}){comment}" -msgstr "" - -#: src/rc_formatters.py:147 src/rc_formatters.py:152 -msgid "without making a redirect" -msgstr "পুনঃনির্দেশ না করে" - -#: src/rc_formatters.py:147 src/rc_formatters.py:153 -msgid "with a redirect" -msgstr "পুনঃনির্দেশ করে" - -#: src/rc_formatters.py:148 -#, python-brace-format -msgid "" -"[{author}]({author_url}) moved {redirect}*{article}* to [{target}]" -"({target_url}) {made_a_redirect}{comment}" -msgstr "" - -#: src/rc_formatters.py:154 -#, python-brace-format -msgid "" -"[{author}]({author_url}) moved {redirect}*{article}* over redirect to " -"[{target}]({target_url}) {made_a_redirect}{comment}" -msgstr "" - -#: src/rc_formatters.py:159 -#, python-brace-format -msgid "" -"[{author}]({author_url}) moved protection settings from {redirect}*{article}" -"* to [{target}]({target_url}){comment}" -msgstr "" - -#: src/rc_formatters.py:170 src/rc_formatters.py:823 -msgid "for infinity and beyond" -msgstr "অনন্ত এবং এর বাইরেও" - -#: src/rc_formatters.py:179 src/rc_formatters.py:831 -#, python-brace-format -msgid "for {num} {translated_length}" -msgstr "{num} {translated_length} -এর জন্য" - -#: src/rc_formatters.py:185 src/rc_formatters.py:835 -msgid "until {}" -msgstr "{} অবধি" - -#: src/rc_formatters.py:189 -msgid " on pages: " -msgstr "" - -#: src/rc_formatters.py:196 src/rc_formatters.py:849 -msgid " and namespaces: " -msgstr "" - -#: src/rc_formatters.py:198 -msgid " on namespaces: " -msgstr "" - -#: src/rc_formatters.py:210 -#, python-brace-format -msgid "" -"[{author}]({author_url}) blocked [{user}]({user_url}) {time}" -"{restriction_desc}{comment}" -msgstr "" - -#: src/rc_formatters.py:214 -#, python-brace-format -msgid "" -"[{author}]({author_url}) changed block settings for [{blocked_user}]" -"({user_url}){comment}" -msgstr "" - -#: src/rc_formatters.py:218 -#, python-brace-format -msgid "" -"[{author}]({author_url}) unblocked [{blocked_user}]({user_url}){comment}" -msgstr "" - -#: src/rc_formatters.py:223 -#, python-brace-format -msgid "" -"[{author}]({author_url}) left a [comment]({comment}) on {target}'s profile" -msgstr "" - -#: src/rc_formatters.py:225 -#, python-brace-format -msgid "" -"[{author}]({author_url}) left a [comment]({comment}) on their own profile" -msgstr "" - -#: src/rc_formatters.py:231 -#, python-brace-format -msgid "" -"[{author}]({author_url}) replied to a [comment]({comment}) on {target}'s " -"profile" -msgstr "" - -#: src/rc_formatters.py:237 -#, python-brace-format -msgid "" -"[{author}]({author_url}) replied to a [comment]({comment}) on their own " -"profile" -msgstr "" - -#: src/rc_formatters.py:245 -#, python-brace-format -msgid "" -"[{author}]({author_url}) edited a [comment]({comment}) on {target}'s profile" -msgstr "" - -#: src/rc_formatters.py:251 -#, python-brace-format -msgid "" -"[{author}]({author_url}) edited a [comment]({comment}) on their own profile" -msgstr "" - -#: src/rc_formatters.py:257 -#, python-brace-format -msgid "[{author}]({author_url}) purged a comment on {target}'s profile" -msgstr "" - -#: src/rc_formatters.py:259 -#, python-brace-format -msgid "[{author}]({author_url}) purged a comment on their own profile" -msgstr "" - -#: src/rc_formatters.py:267 -#, python-brace-format -msgid "" -"[{author}]({author_url}) deleted a [comment]({comment}) on {target}'s profile" -msgstr "" - -#: src/rc_formatters.py:269 -#, python-brace-format -msgid "" -"[{author}]({author_url}) deleted a [comment]({comment}) on their own profile" -msgstr "" - -#: src/rc_formatters.py:274 -#, python-brace-format -msgid "" -"[{author}]({author_url}) edited the {field} on [{target}]({target_url})'s " -"profile. *({desc})*" -msgstr "" - -#: src/rc_formatters.py:281 -#, python-brace-format -msgid "" -"[{author}]({author_url}) edited the {field} on [their own]({target_url}) " -"profile. *({desc})*" -msgstr "" - -#: src/rc_formatters.py:296 src/rc_formatters.py:298 src/rc_formatters.py:945 -#: src/rc_formatters.py:947 -msgid "none" -msgstr "কিছুই না" - -#: src/rc_formatters.py:301 -#, fuzzy, python-brace-format -msgid "" -"[{author}]({author_url}) changed group membership for [{target}]" -"({target_url}) from {old_groups} to {new_groups}{comment}" -msgstr "" -"[{author}]({author_url}) [{target}] ({target_url})-এর দলীয় সদস্যপদ " -"{old_groups} থেকে {new_groups} -এ পরিবর্তন করেছেন {comment}" - -#: src/rc_formatters.py:303 -#, python-brace-format -msgid "" -"{author} autopromoted [{target}]({target_url}) from {old_groups} to " -"{new_groups}{comment}" -msgstr "" - -#: src/rc_formatters.py:304 src/rc_formatters.py:933 -msgid "System" -msgstr "পদ্ধতি" - -#: src/rc_formatters.py:309 -#, python-brace-format -msgid "" -"[{author}]({author_url}) protected [{article}]({article_url}) with the " -"following settings: {settings}{comment}" -msgstr "" - -#: src/rc_formatters.py:311 src/rc_formatters.py:319 src/rc_formatters.py:955 -#: src/rc_formatters.py:961 -msgid " [cascading]" -msgstr "" - -#: src/rc_formatters.py:316 -#, python-brace-format -msgid "" -"[{author}]({author_url}) modified protection settings of [{article}]" -"({article_url}) to: {settings}{comment}" -msgstr "" - -#: src/rc_formatters.py:323 -#, python-brace-format -msgid "" -"[{author}]({author_url}) removed protection from [{article}]({article_url})" -"{comment}" -msgstr "" - -#: src/rc_formatters.py:327 -#, python-brace-format -msgid "" -"[{author}]({author_url}) changed visibility of revision on page [{article}]" -"({article_url}){comment}" -msgid_plural "" -"[{author}]({author_url}) changed visibility of {amount} revisions on page " -"[{article}]({article_url}){comment}" -msgstr[0] "" -msgstr[1] "" - -#: src/rc_formatters.py:340 -#, python-brace-format -msgid "" -"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " -"revision{comment}" -msgid_plural "" -"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " -"revisions{comment}" -msgstr[0] "" -msgstr[1] "" - -#: src/rc_formatters.py:345 -#, python-brace-format -msgid "[{author}]({author_url}) restored [{article}]({article_url}){comment}" -msgstr "" - -#: src/rc_formatters.py:347 -#, python-brace-format -msgid "[{author}]({author_url}) changed visibility of log events{comment}" -msgstr "" - -#: src/rc_formatters.py:359 -#, python-brace-format -msgid "" -"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " -"revision from [{source}]({source_url}){comment}" -msgid_plural "" -"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " -"revisions from [{source}]({source_url}){comment}" -msgstr[0] "" -msgstr[1] "" - -#: src/rc_formatters.py:364 -#, python-brace-format -msgid "" -"[{author}]({author_url}) edited abuse filter [number {number}]({filter_url})" -msgstr "" - -#: src/rc_formatters.py:368 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created abuse filter [number {number}]({filter_url})" -msgstr "" - -#: src/rc_formatters.py:372 -#, python-brace-format -msgid "" -"[{author}]({author_url}) merged revision histories of [{article}]" -"({article_url}) into [{dest}]({dest_url}){comment}" -msgstr "" - -#: src/rc_formatters.py:375 -#, python-brace-format -msgid "Account [{author}]({author_url}) was created automatically" -msgstr "[{author}]({author_url}) অ্যাকাউন্টটি স্বয়ংক্রিয়ভাবে তৈরি হয়েছে" - -#: src/rc_formatters.py:377 src/rc_formatters.py:385 -#, python-brace-format -msgid "Account [{author}]({author_url}) was created" -msgstr "ব্যবহারকারী অ্যাকাউন্ট [{author}]({author_url}) তৈরি করা হয়েছে" - -#: src/rc_formatters.py:380 -#, python-brace-format -msgid "" -"Account [{article}]({article_url}) was created by [{author}]({author_url})" -"{comment}" -msgstr "" - -#: src/rc_formatters.py:383 -#, python-brace-format -msgid "" -"Account [{article}]({article_url}) was created by [{author}]({author_url}) " -"and password was sent by email{comment}" -msgstr "" - -#: src/rc_formatters.py:388 -#, python-brace-format -msgid "" -"[{author}]({author_url}) added an entry to the [interwiki table]" -"({table_url}) pointing to {website} with {prefix} prefix" -msgstr "" - -#: src/rc_formatters.py:394 -#, python-brace-format -msgid "" -"[{author}]({author_url}) edited an entry in [interwiki table]({table_url}) " -"pointing to {website} with {prefix} prefix" -msgstr "" - -#: src/rc_formatters.py:400 -#, python-brace-format -msgid "" -"[{author}]({author_url}) deleted an entry in [interwiki table]({table_url})" -msgstr "" - -#: src/rc_formatters.py:403 -#, python-brace-format -msgid "" -"[{author}]({author_url}) changed the content model of the page [{article}]" -"({article_url}) from {old} to {new}{comment}" -msgstr "" - -#: src/rc_formatters.py:407 -#, python-brace-format -msgid "" -"[{author}]({author_url}) edited the sprite for [{article}]({article_url})" -msgstr "" - -#: src/rc_formatters.py:410 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created the sprite sheet for [{article}]" -"({article_url})" -msgstr "" - -#: src/rc_formatters.py:413 -#, python-brace-format -msgid "" -"[{author}]({author_url}) edited the slice for [{article}]({article_url})" -msgstr "" - -#: src/rc_formatters.py:418 +#: extensions/base/cargo.py:45 #, python-brace-format msgid "[{author}]({author_url}) created the Cargo table \"{table}\"" msgstr "" -#: src/rc_formatters.py:420 +#: extensions/base/cargo.py:60 #, python-brace-format -msgid "[{author}]({author_url}) deleted the Cargo table \"{table}\"" +msgid "Recreated the Cargo table \"{table}\"" msgstr "" -#: src/rc_formatters.py:425 +#: extensions/base/cargo.py:68 #, python-brace-format msgid "[{author}]({author_url}) recreated the Cargo table \"{table}\"" msgstr "" -#: src/rc_formatters.py:430 +#: extensions/base/cargo.py:83 +#, python-brace-format +msgid "Replaced the Cargo table \"{table}\"" +msgstr "" + +#: extensions/base/cargo.py:91 #, python-brace-format msgid "[{author}]({author_url}) replaced the Cargo table \"{table}\"" msgstr "" -#: src/rc_formatters.py:433 +#: extensions/base/cargo.py:105 #, python-brace-format -msgid "[{author}]({author_url}) created a [tag]({tag_url}) \"{tag}\"" +msgid "Deleted the Cargo table \"{table}\"" msgstr "" -#: src/rc_formatters.py:437 +#: extensions/base/cargo.py:112 #, python-brace-format -msgid "[{author}]({author_url}) deleted a [tag]({tag_url}) \"{tag}\"" +msgid "[{author}]({author_url}) deleted the Cargo table \"{table}\"" msgstr "" -#: src/rc_formatters.py:441 +#: extensions/base/translate.py:41 #, python-brace-format -msgid "[{author}]({author_url}) activated a [tag]({tag_url}) \"{tag}\"" +msgid "Marked \"{article}\" for translation" msgstr "" -#: src/rc_formatters.py:444 -#, python-brace-format -msgid "[{author}]({author_url}) deactivated a [tag]({tag_url}) \"{tag}\"" -msgstr "" - -#: src/rc_formatters.py:446 -#, python-brace-format -msgid "[{author}]({author_url}) changed wiki settings{reason}" -msgstr "" - -#: src/rc_formatters.py:448 -#, python-brace-format -msgid "[{author}]({author_url}) deleted a wiki *{wiki_name}*{comment}" -msgstr "" - -#: src/rc_formatters.py:451 -#, python-brace-format -msgid "[{author}]({author_url}) locked a wiki *{wiki_name}*{comment}" -msgstr "" - -#: src/rc_formatters.py:454 -#, python-brace-format -msgid "" -"[{author}]({author_url}) modified a namespace *{namespace_name}* on " -"*{wiki_name}*{comment}" -msgstr "" - -#: src/rc_formatters.py:459 -#, python-brace-format -msgid "" -"[{author}]({author_url}) deleted a namespace *{namespace_name}* on " -"*{wiki_name}*{comment}" -msgstr "" - -#: src/rc_formatters.py:465 -#, python-brace-format -msgid "[{author}]({author_url}) modified user group *{group_name}*{comment}" -msgstr "" - -#: src/rc_formatters.py:469 -#, python-brace-format -msgid "[{author}]({author_url}) restored a wiki *{wiki_name}*{comment}" -msgstr "" - -#: src/rc_formatters.py:473 -#, python-brace-format -msgid "[{author}]({author_url}) unlocked a wiki *{wiki_name}*{comment}" -msgstr "" - -#: src/rc_formatters.py:484 +#: extensions/base/translate.py:55 #, python-brace-format msgid "" "[{author}]({author_url}) marked [{article}]({article_url}) for " "translation{comment}" msgstr "" -"[{author}]({author_url}) [{article}]({article_url}) অনুবাদের জন্য চিহ্নিত " -"করেছেন {comment}" -#: src/rc_formatters.py:491 +#: extensions/base/translate.py:70 +#, python-brace-format +msgid "Removed \"{article}\" from the translation system" +msgstr "" + +#: extensions/base/translate.py:80 #, python-brace-format msgid "" "[{author}]({author_url}) removed [{article}]({article_url}) from the " "translation system{comment}" msgstr "" -"[{author}]({author_url}) অনুবাদের পাতা [{article}]({article_url}) অপসারণ " -"করেছেন {comment}" -#: src/rc_formatters.py:498 +#: extensions/base/translate.py:95 +#, python-brace-format +msgid "Completed moving translation pages from \"{article}\" to \"{target}\"" +msgstr "" + +#: extensions/base/translate.py:106 #, python-brace-format msgid "" "[{author}]({author_url}) completed moving translation pages from *{article}* " "to [{target}]({target_url}){comment}" msgstr "" -#: src/rc_formatters.py:506 +#: extensions/base/translate.py:121 +#, python-brace-format +msgid "Encountered a problem while moving \"{article}\" to \"{target}\"" +msgstr "" + +#: extensions/base/translate.py:133 #, python-brace-format msgid "" "[{author}]({author_url}) encountered a problem while moving [{article}]" "({article_url}) to [{target}]({target_url}){comment}" msgstr "" -#: src/rc_formatters.py:514 +#: extensions/base/translate.py:149 #, python-brace-format msgid "" -"[{author}]({author_url}) completed deletion of translatable page [{article}]" -"({article_url}){comment}" +"Failed to delete \"{article}\" which belongs to translatable page " +"\"{target}\"" msgstr "" -#: src/rc_formatters.py:522 +#: extensions/base/translate.py:161 #, python-brace-format msgid "" "[{author}]({author_url}) failed to delete [{article}]({article_url}) which " "belongs to translatable page [{target}]({target_url}){comment}" msgstr "" -#: src/rc_formatters.py:530 +#: extensions/base/translate.py:177 +#, python-brace-format +msgid "Completed deletion of translation page \"{article}\"" +msgstr "" + +#: extensions/base/translate.py:188 #, python-brace-format msgid "" "[{author}]({author_url}) completed deletion of translation page [{article}]" "({article_url}){comment}" msgstr "" -#: src/rc_formatters.py:538 +#: extensions/base/translate.py:203 +#, python-brace-format +msgid "" +"Failed to delete \"{article}\" which belongs to translation page \"{target}\"" +msgstr "" + +#: extensions/base/translate.py:215 #, python-brace-format msgid "" "[{author}]({author_url}) failed to delete [{article}]({article_url}) which " "belongs to translation page [{target}]({target_url}){comment}" msgstr "" -#: src/rc_formatters.py:546 +#: extensions/base/translate.py:231 +#, python-brace-format +msgid "Encouraged translation of \"{article}\"" +msgstr "" + +#: extensions/base/translate.py:240 #, python-brace-format msgid "" "[{author}]({author_url}) encouraged translation of [{article}]({article_url})" "{comment}" msgstr "" -#: src/rc_formatters.py:553 +#: extensions/base/translate.py:255 +#, python-brace-format +msgid "Discouraged translation of \"{article}\"" +msgstr "" + +#: extensions/base/translate.py:264 #, python-brace-format msgid "" "[{author}]({author_url}) discouraged translation of [{article}]" "({article_url}){comment}" msgstr "" -#: src/rc_formatters.py:563 +#: extensions/base/translate.py:282 +#, python-brace-format +msgid "Limited languages for \"{article}\" to `{languages}`" +msgstr "" + +#: extensions/base/translate.py:285 +#, python-brace-format +msgid "Priority languages for \"{article}\" set to `{languages}`" +msgstr "" + +#: extensions/base/translate.py:288 +#, python-brace-format +msgid "Removed priority languages from \"{article}\"" +msgstr "" + +#: extensions/base/translate.py:301 #, python-brace-format msgid "" "[{author}]({author_url}) limited languages for [{article}]({article_url}) to " "`{languages}`{comment}" msgstr "" -#: src/rc_formatters.py:569 +#: extensions/base/translate.py:308 #, python-brace-format msgid "" "[{author}]({author_url}) set the priority languages for [{article}]" "({article_url}) to `{languages}`{comment}" msgstr "" -#: src/rc_formatters.py:575 +#: extensions/base/translate.py:315 #, python-brace-format msgid "" "[{author}]({author_url}) removed priority languages from [{article}]" "({article_url}){comment}" msgstr "" -#: src/rc_formatters.py:582 +#: extensions/base/translate.py:331 +#, python-brace-format +msgid "Added translatable page \"{article}\" to aggregate group \"{group}\"" +msgstr "" + +#: extensions/base/translate.py:342 #, python-brace-format msgid "" "[{author}]({author_url}) added translatable page [{article}]({article_url}) " "to aggregate group \"{group}\"{comment}" msgstr "" -#: src/rc_formatters.py:589 +#: extensions/base/translate.py:357 +#, python-brace-format +msgid "" +"Removed translatable page \"{article}\" from aggregate group \"{group}\"" +msgstr "" + +#: extensions/base/translate.py:368 #, python-brace-format msgid "" "[{author}]({author_url}) removed translatable page [{article}]" "({article_url}) from aggregate group \"{group}\"{comment}" msgstr "" -#: src/rc_formatters.py:601 +#: extensions/base/translate.py:387 +#, python-brace-format +msgid "Reviewed translation \"{article}\"" +msgstr "" + +#: extensions/base/translate.py:401 #, python-brace-format msgid "" "[{author}]({author_url}) reviewed translation [{article}]({article_url})" "{comment}" msgstr "" -#: src/rc_formatters.py:609 +#: extensions/base/translate.py:416 +#, python-brace-format +msgid "Changed the state of `{language}` translations of \"{article}\"" +msgstr "" + +#: extensions/base/translate.py:419 +msgid "Old state" +msgstr "" + +#: extensions/base/translate.py:420 +msgid "New state" +msgstr "" + +#: extensions/base/translate.py:431 #, python-brace-format msgid "" "[{author}]({author_url}) changed the state of `{language}` translations of " "[{article}]({article_url}) from `{old_state}` to `{new_state}`{comment}" msgstr "" -#: src/rc_formatters.py:616 +#: extensions/base/translate.py:439 #, python-brace-format msgid "" "[{author}]({author_url}) changed the state of `{language}` translations of " "[{article}]({article_url}) to `{new_state}`{comment}" msgstr "" -#: src/rc_formatters.py:625 +#: extensions/base/translate.py:452 extensions/base/translate.py:455 +msgid "(default)" +msgstr "" + +#: extensions/base/translate.py:464 +#, python-brace-format +msgid "Changed the language of \"{article}\"" +msgstr "" + +#: extensions/base/translate.py:465 +msgid "Old language" +msgstr "" + +#: extensions/base/translate.py:466 +msgid "New language" +msgstr "" + +#: extensions/base/translate.py:477 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed the language of [{article}]({article_url}) " +"from {old_lang} to {new_lang}{comment}" +msgstr "" + +#: extensions/base/discussions.py:148 extensions/base/discussions.py:207 +#: extensions/base/discussions.py:245 extensions/base/discussions.py:261 +#: extensions/base/discussions.py:284 extensions/base/discussions.py:306 +#: extensions/base/discussions.py:334 extensions/base/discussions.py:354 +msgid "unknown" +msgstr "" + +#: extensions/base/discussions.py:157 +#, python-brace-format +msgid "Created \"{title}\"" +msgstr "" + +#: extensions/base/discussions.py:161 +#, python-brace-format +msgid "Created a poll \"{title}\"" +msgstr "" + +#: extensions/base/discussions.py:168 +msgid "Option {}" +msgstr "" + +#: extensions/base/discussions.py:170 +#, python-brace-format +msgid "__[View image]({image_url})__" +msgstr "" + +#: extensions/base/discussions.py:174 +#, python-brace-format +msgid "Created a quiz \"{title}\"" +msgstr "" + +#: extensions/base/discussions.py:193 extensions/base/discussions.py:195 +msgctxt "Fandom discussions Tags/Forums" +msgid "Tags" +msgstr "" + +#: extensions/base/discussions.py:193 +msgctxt "Fandom discussions amount of Tags/Forums" +msgid "{} tags" +msgstr "" + +#: extensions/base/discussions.py:198 +#, python-brace-format +msgid "Replied to \"{title}\"" +msgstr "" + +#: extensions/base/discussions.py:214 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created [{title}](<{url}f/p/{threadId}>) in " +"{forumName}" +msgstr "" + +#: extensions/base/discussions.py:217 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a poll [{title}](<{url}f/p/{threadId}>) in " +"{forumName}" +msgstr "" + +#: extensions/base/discussions.py:220 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a quiz [{title}](<{url}f/p/{threadId}>) in " +"{forumName}" +msgstr "" + +#: extensions/base/discussions.py:234 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a [reply](<{url}f/p/{threadId}/r/{postId}>) " +"to [{title}](<{url}f/p/{threadId}>) in {forumName}" +msgstr "" + +#: extensions/base/discussions.py:292 +#, python-brace-format +msgid "Created \"{title}\" on {user}'s Message Wall" +msgstr "" + +#: extensions/base/discussions.py:298 +#, python-brace-format +msgid "Replied to \"{title}\" on {user}'s Message Wall" +msgstr "" + +#: extensions/base/discussions.py:312 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created [{title}](<{url}wiki/Message_Wall:" +"{user_wall}?threadId={threadId}>) on [{user}'s Message Wall](<{url}wiki/" +"Message_Wall:{user_wall}>)" +msgstr "" + +#: extensions/base/discussions.py:318 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a [reply](<{url}wiki/Message_Wall:" +"{user_wall}?threadId={threadId}#{replyId}>) to [{title}](<{url}wiki/" +"Message_Wall:{user_wall}?threadId={threadId}>) on [{user}'s Message Wall]" +"(<{url}wiki/Message_Wall:{user_wall}>)" +msgstr "" + +#: extensions/base/discussions.py:338 +#, python-brace-format +msgid "Commented on {article}" +msgstr "" + +#: extensions/base/discussions.py:344 +#, python-brace-format +msgid "Replied to a comment on {article}" +msgstr "" + +#: extensions/base/discussions.py:359 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a [comment](<{url}?commentId={commentId}>) " +"on [{article}](<{url}>)" +msgstr "" + +#: extensions/base/discussions.py:365 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a [reply](<{url}?commentId={commentId}" +"&replyId={replyId}>) to a [comment](<{url}?commentId={commentId}>) on " +"[{article}](<{url}>)" +msgstr "" + +#: extensions/base/managewiki.py:34 +msgid "Changed wiki settings" +msgstr "" + +#: extensions/base/managewiki.py:44 +#, python-brace-format +msgid "[{author}]({author_url}) changed wiki settings{reason}" +msgstr "" + +#: extensions/base/managewiki.py:55 +#, python-brace-format +msgid "Deleted a \"{wiki}\" wiki" +msgstr "" + +#: extensions/base/managewiki.py:55 extensions/base/managewiki.py:67 +#: extensions/base/managewiki.py:103 extensions/base/managewiki.py:112 +#: extensions/base/managewiki.py:125 extensions/base/managewiki.py:126 +#: extensions/base/managewiki.py:135 extensions/base/managewiki.py:136 +#: extensions/base/managewiki.py:148 extensions/base/managewiki.py:149 +#: extensions/base/managewiki.py:160 extensions/base/managewiki.py:161 +#: extensions/base/managewiki.py:195 extensions/base/managewiki.py:204 +#: extensions/base/managewiki.py:217 extensions/base/managewiki.py:226 +#: extensions/base/abusefilter.py:55 extensions/base/abusefilter.py:56 +#: extensions/base/abusefilter.py:57 extensions/base/abusefilter.py:68 +#: extensions/base/abusefilter.py:69 extensions/base/abusefilter.py:70 +#: extensions/base/mediawiki.py:744 +msgid "Unknown" +msgstr "" + +#: extensions/base/managewiki.py:63 +#, python-brace-format +msgid "[{author}]({author_url}) deleted a wiki *{wiki_name}*{comment}" +msgstr "" + +#: extensions/base/managewiki.py:80 +#, python-brace-format +msgid "Deleted a \"{group}\" user group" +msgstr "" + +#: extensions/base/managewiki.py:89 +#, python-brace-format +msgid "[{author}]({author_url}) deleted a usergroup *{group}*{comment}" +msgstr "" + +#: extensions/base/managewiki.py:103 +#, python-brace-format +msgid "Locked a \"{wiki}\" wiki" +msgstr "" + +#: extensions/base/managewiki.py:111 +#, python-brace-format +msgid "[{author}]({author_url}) locked a wiki *{wiki_name}*{comment}" +msgstr "" + +#: extensions/base/managewiki.py:124 +#, python-brace-format +msgid "Modified \"{namespace_name}\" namespace" +msgstr "" + +#: extensions/base/managewiki.py:126 extensions/base/managewiki.py:149 +msgid "Wiki" +msgstr "" + +#: extensions/base/managewiki.py:134 +#, python-brace-format +msgid "" +"[{author}]({author_url}) modified namespace *{namespace_name}* on " +"*{wiki_name}*{comment}" +msgstr "" + +#: extensions/base/managewiki.py:147 +#, python-brace-format +msgid "Deleted a \"{namespace_name}\" namespace" +msgstr "" + +#: extensions/base/managewiki.py:158 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted a namespace *{namespace_name}* on " +"*{wiki_name}*{comment}" +msgstr "" + +#: extensions/base/managewiki.py:173 +#, python-brace-format +msgid "Modified \"{usergroup_name}\" usergroup" +msgstr "" + +#: extensions/base/managewiki.py:182 +#, python-brace-format +msgid "[{author}]({author_url}) modified user group *{group_name}*{comment}" +msgstr "" + +#: extensions/base/managewiki.py:195 +#, python-brace-format +msgid "Undeleted a \"{wiki}\" wiki" +msgstr "" + +#: extensions/base/managewiki.py:203 +#, python-brace-format +msgid "[{author}]({author_url}) undeleted a wiki *{wiki_name}*{comment}" +msgstr "" + +#: extensions/base/managewiki.py:217 +#, python-brace-format +msgid "Unlocked a \"{wiki}\" wiki" +msgstr "" + +#: extensions/base/managewiki.py:225 +#, python-brace-format +msgid "[{author}]({author_url}) unlocked a wiki *{wiki_name}*{comment}" +msgstr "" + +#: extensions/base/datadump.py:36 +#, python-brace-format +msgid "Generated {file} dump" +msgstr "" + +#: extensions/base/datadump.py:45 +#, python-brace-format +msgid "[{author}]({author_url}) generated *{file}* dump{comment}" +msgstr "" + +#: extensions/base/datadump.py:58 +#, python-brace-format +msgid "Deleted {file} dump" +msgstr "" + +#: extensions/base/datadump.py:67 +#, python-brace-format +msgid "[{author}]({author_url}) deleted *{file}* dump{comment}" +msgstr "" + +#: extensions/base/curseprofile.py:40 +#, python-brace-format +msgid "Edited {target}'s profile" +msgstr "" + +#: extensions/base/curseprofile.py:42 +msgid "Edited their own profile" +msgstr "" + +#: extensions/base/curseprofile.py:44 +#, python-brace-format +msgid "Cleared the {field} field" +msgstr "" + +#: extensions/base/curseprofile.py:46 +#, python-brace-format +msgid "{field} field changed to: {desc}" +msgstr "" + +#: extensions/base/curseprofile.py:58 +#, python-brace-format +msgid "" +"[{author}]({author_url}) cleared the {field} on [{target}]({target_url})'s " +"profile." +msgstr "" + +#: extensions/base/curseprofile.py:60 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited the {field} on [{target}]({target_url})'s " +"profile. *({desc})*" +msgstr "" + +#: extensions/base/curseprofile.py:65 +#, python-brace-format +msgid "" +"[{author}]({author_url}) cleared the {field} on [their own]({target_url}) " +"profile." +msgstr "" + +#: extensions/base/curseprofile.py:67 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited the {field} on [their own]({target_url}) " +"profile. *({desc})*" +msgstr "" + +#: extensions/base/curseprofile.py:82 +#, python-brace-format +msgid "Left a comment on {target}'s profile" +msgstr "" + +#: extensions/base/curseprofile.py:84 +msgid "Left a comment on their own profile" +msgstr "" + +#: extensions/base/curseprofile.py:97 +#, python-brace-format +msgid "" +"[{author}]({author_url}) left a [comment]({comment}) on {target}'s profile." +msgstr "" + +#: extensions/base/curseprofile.py:100 +#, python-brace-format +msgid "" +"[{author}]({author_url}) left a [comment]({comment}) on their own profile." +msgstr "" + +#: extensions/base/curseprofile.py:113 +#, python-brace-format +msgid "Edited a comment on {target}'s profile" +msgstr "" + +#: extensions/base/curseprofile.py:115 +msgid "Edited a comment on their own profile" +msgstr "" + +#: extensions/base/curseprofile.py:128 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited a [comment]({comment}) on {target}'s profile." +msgstr "" + +#: extensions/base/curseprofile.py:131 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited a [comment]({comment}) on their own profile." +msgstr "" + +#: extensions/base/curseprofile.py:144 +#, python-brace-format +msgid "Replied to a comment on {target}'s profile" +msgstr "" + +#: extensions/base/curseprofile.py:146 +msgid "Replied to a comment on their own profile" +msgstr "" + +#: extensions/base/curseprofile.py:159 +#, python-brace-format +msgid "" +"[{author}]({author_url}) replied to a [comment]({comment}) on {target}'s " +"profile." +msgstr "" + +#: extensions/base/curseprofile.py:162 +#, python-brace-format +msgid "" +"[{author}]({author_url}) replied to a [comment]({comment}) on their own " +"profile." +msgstr "" + +#: extensions/base/curseprofile.py:175 +#, python-brace-format +msgid "Deleted a comment on {target}'s profile" +msgstr "" + +#: extensions/base/curseprofile.py:177 +msgid "Deleted a comment on their own profile" +msgstr "" + +#: extensions/base/curseprofile.py:197 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted a [comment]({comment}) on {target}'s " +"profile.{reason}" +msgstr "" + +#: extensions/base/curseprofile.py:200 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted a [comment]({comment}) on their own profile." +"{reason}" +msgstr "" + +#: extensions/base/curseprofile.py:214 +#, python-brace-format +msgid "Purged a comment on {target}'s profile" +msgstr "" + +#: extensions/base/curseprofile.py:216 +msgid "Purged a comment on their own profile" +msgstr "" + +#: extensions/base/curseprofile.py:230 +#, python-brace-format +msgid "" +"[{author}]({author_url}) purged a comment on [{target}]({link})'s profile." +"{reason}" +msgstr "" + +#: extensions/base/curseprofile.py:233 +#, python-brace-format +msgid "" +"[{author}]({author_url}) purged a comment on [their own]({link}) profile." +"{reason}" +msgstr "" + +#: extensions/base/renameuser.py:38 +#, python-brace-format +msgid "Renamed user \"{old_name}\" with {edits} edit to \"{new_name}\"" +msgid_plural "Renamed user \"{old_name}\" with {edits} edits to \"{new_name}\"" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/renameuser.py:43 +#, python-brace-format +msgid "Renamed user \"{old_name}\" to \"{new_name}\"" +msgstr "" + +#: extensions/base/renameuser.py:58 #, python-brace-format msgid "" "[{author}]({author_url}) renamed user *{old_name}* with {edits} edit to " @@ -707,601 +774,831 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: src/rc_formatters.py:630 +#: extensions/base/renameuser.py:66 #, python-brace-format msgid "" "[{author}]({author_url}) renamed user *{old_name}* to [{new_name}]({link})" "{comment}" msgstr "" -#: src/rc_formatters.py:634 -msgid "An action has been hidden by administration." +#: extensions/base/interwiki.py:37 +msgid "Added an entry to the interwiki table" msgstr "" -#: src/rc_formatters.py:641 +#: extensions/base/interwiki.py:38 extensions/base/interwiki.py:65 +#, python-brace-format +msgid "Prefix: {prefix}, website: {website} | {desc}" +msgstr "" + +#: extensions/base/interwiki.py:50 #, python-brace-format msgid "" -"Unknown event `{event}` by [{author}]({author_url}), report it on the " -"[support server](<{support}>)." +"[{author}]({author_url}) added an entry to the [interwiki table]" +"({table_url}) pointing to {website} with {prefix} prefix" msgstr "" -#: src/rc_formatters.py:649 +#: extensions/base/interwiki.py:64 +msgid "Edited an entry in interwiki table" +msgstr "" + +#: extensions/base/interwiki.py:77 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited an entry in [interwiki table]({table_url}) " +"pointing to {website} with {prefix} prefix" +msgstr "" + +#: extensions/base/interwiki.py:91 +msgid "Deleted an entry in interwiki table" +msgstr "" + +#: extensions/base/interwiki.py:92 +#, python-brace-format +msgid "Prefix: {prefix} | {desc}" +msgstr "" + +#: extensions/base/interwiki.py:102 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted an entry in [interwiki table]({table_url})" +"{desc}" +msgstr "" + +#: extensions/base/abusefilter.py:29 +msgid "None" +msgstr "" + +#: extensions/base/abusefilter.py:29 +msgid "Warning issued" +msgstr "" + +#: extensions/base/abusefilter.py:29 +msgid "**Blocked user**" +msgstr "" + +#: extensions/base/abusefilter.py:29 +msgid "Tagged the edit" +msgstr "" + +#: extensions/base/abusefilter.py:29 +msgid "Disallowed the action" +msgstr "" + +#: extensions/base/abusefilter.py:29 +msgid "**IP range blocked**" +msgstr "" + +#: extensions/base/abusefilter.py:29 +msgid "Throttled actions" +msgstr "" + +#: extensions/base/abusefilter.py:29 +msgid "Removed autoconfirmed group" +msgstr "" + +#: extensions/base/abusefilter.py:29 +msgid "**Removed from privileged groups**" +msgstr "" + +#: extensions/base/abusefilter.py:30 +msgid "Edit" +msgstr "" + +#: extensions/base/abusefilter.py:30 +msgid "Upload" +msgstr "" + +#: extensions/base/abusefilter.py:30 +msgid "Move" +msgstr "" + +#: extensions/base/abusefilter.py:30 +msgid "Stash upload" +msgstr "" + +#: extensions/base/abusefilter.py:30 +msgid "Deletion" +msgstr "" + +#: extensions/base/abusefilter.py:30 +msgid "Account creation" +msgstr "" + +#: extensions/base/abusefilter.py:30 +msgid "Auto account creation" +msgstr "" + +#: extensions/base/abusefilter.py:54 #, python-brace-format msgid "{user} triggered \"{abuse_filter}\"" msgstr "" -#: src/rc_formatters.py:650 +#: extensions/base/abusefilter.py:55 msgid "Performed" -msgstr "সম্পাদিত" +msgstr "" -#: src/rc_formatters.py:651 +#: extensions/base/abusefilter.py:56 msgid "Action taken" -msgstr "ব্যবস্থা নেওয়া হয়েছে" +msgstr "" -#: src/rc_formatters.py:652 +#: extensions/base/abusefilter.py:57 msgid "Title" -msgstr "শিরোনাম" +msgstr "" -#: src/rc_formatters.py:661 src/rc_formatters.py:948 -msgid "No description provided" -msgstr "কোনও বিবরণ সরবরাহ করা হয়নি" +#: extensions/base/abusefilter.py:66 +#, python-brace-format +msgid "" +"[{author}]({author_url}) triggered *{abuse_filter}*, performing the action " +"\"{action}\" on *[{target}]({target_url})* - action taken: {result}." +msgstr "" -#: src/rc_formatters.py:685 +#: extensions/base/abusefilter.py:83 +#, python-brace-format +msgid "Edited abuse filter number {number}" +msgstr "" + +#: extensions/base/abusefilter.py:95 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited abuse filter [number {number}]({filter_url})" +msgstr "" + +#: extensions/base/abusefilter.py:111 +#, python-brace-format +msgid "Created abuse filter number {number}" +msgstr "" + +#: extensions/base/abusefilter.py:119 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created abuse filter [number {number}]({filter_url})" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "director" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "bot" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "editor" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "directors" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "sysop" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "bureaucrat" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "reviewer" +msgstr "" + +#: extensions/base/mediawiki.py:38 +msgid "autoreview" +msgstr "" + +#: extensions/base/mediawiki.py:38 +msgid "autopatrol" +msgstr "" + +#: extensions/base/mediawiki.py:38 +msgid "wiki_guardian" +msgstr "" + +#: extensions/base/mediawiki.py:71 msgid "(N!) " -msgstr "(N!) " +msgstr "" -#: src/rc_formatters.py:686 +#: extensions/base/mediawiki.py:72 msgid "m" -msgstr "m" +msgstr "" -#: src/rc_formatters.py:686 +#: extensions/base/mediawiki.py:73 msgid "b" -msgstr "b" +msgstr "" -#: src/rc_formatters.py:703 src/rc_formatters.py:708 -msgid "__Only whitespace__" -msgstr "__Only whitespace__" +#: extensions/base/mediawiki.py:112 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited [{article}]({edit_link}){comment} {bold}" +"({sign}{edit_size}){bold}" +msgstr "" -#: src/rc_formatters.py:713 -msgid "Removed" -msgstr "সরানো হয়েছে" +#: extensions/base/mediawiki.py:117 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created [{article}]({edit_link}){comment} {bold}" +"({sign}{edit_size}){bold}" +msgstr "" -#: src/rc_formatters.py:715 -msgid "Added" -msgstr "যুক্ত হয়েছে" - -#: src/rc_formatters.py:749 src/rc_formatters.py:788 +#: extensions/base/mediawiki.py:190 extensions/base/mediawiki.py:223 msgid "Options" -msgstr "বিকল্পগুলি" +msgstr "" -#: src/rc_formatters.py:749 +#: extensions/base/mediawiki.py:190 #, python-brace-format msgid "([preview]({link}) | [undo]({undolink}))" msgstr "" -#: src/rc_formatters.py:754 +#: extensions/base/mediawiki.py:195 #, python-brace-format msgid "Uploaded a new version of {name}" -msgstr "{name} -এর একটি নতুন সংস্করণ আপলোড হয়েছে" +msgstr "" -#: src/rc_formatters.py:756 +#: extensions/base/mediawiki.py:197 #, python-brace-format msgid "Reverted a version of {name}" msgstr "" -#: src/rc_formatters.py:758 +#: extensions/base/mediawiki.py:199 #, python-brace-format msgid "Uploaded {name}" msgstr "" -#: src/rc_formatters.py:774 +#: extensions/base/mediawiki.py:208 msgid "**No license!**" msgstr "" -#: src/rc_formatters.py:786 +#: extensions/base/mediawiki.py:223 +#, python-brace-format +msgid "([preview]({link}))" +msgstr "" + +#: extensions/base/mediawiki.py:228 msgid "" "\n" "License: {}" msgstr "" -#: src/rc_formatters.py:788 +#: extensions/base/mediawiki.py:237 #, python-brace-format -msgid "([preview]({link}))" +msgid "" +"[{author}]({author_url}) reverted a version of [{file}]({file_link}){comment}" msgstr "" -#: src/rc_formatters.py:793 +#: extensions/base/mediawiki.py:248 +#, python-brace-format +msgid "" +"[{author}]({author_url}) uploaded a new version of [{file}]({file_link})" +"{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:259 +#, python-brace-format +msgid "[{author}]({author_url}) uploaded [{file}]({file_link}){comment}" +msgstr "" + +#: extensions/base/mediawiki.py:274 #, python-brace-format msgid "Deleted page {article}" msgstr "" -#: src/rc_formatters.py:798 +#: extensions/base/mediawiki.py:283 +#, python-brace-format +msgid "[{author}]({author_url}) deleted [{page}]({page_link}){comment}" +msgstr "" + +#: extensions/base/mediawiki.py:298 #, python-brace-format msgid "Deleted redirect {article} by overwriting" msgstr "" -#: src/rc_formatters.py:804 -msgid "No redirect has been made" -msgstr "" - -#: src/rc_formatters.py:805 -msgid "A redirect has been made" -msgstr "" - -#: src/rc_formatters.py:806 +#: extensions/base/mediawiki.py:308 #, python-brace-format -msgid "Moved {redirect}{article} to {target}" +msgid "" +"[{author}]({author_url}) deleted redirect by overwriting [{page}]" +"({page_link}){comment}" msgstr "" -#: src/rc_formatters.py:809 +#: extensions/base/mediawiki.py:322 #, python-brace-format -msgid "Moved {redirect}{article} to {title} over redirect" +msgid "Restored {article}" msgstr "" -#: src/rc_formatters.py:813 +#: extensions/base/mediawiki.py:331 #, python-brace-format -msgid "Moved protection settings from {redirect}{article} to {title}" +msgid "[{author}]({author_url}) restored [{article}]({article_url}){comment}" msgstr "" -#: src/rc_formatters.py:837 -msgid "unknown expiry time" +#: extensions/base/mediawiki.py:348 +msgid "Changed visibility of log events" msgstr "" -#: src/rc_formatters.py:842 -msgid "Blocked from editing the following pages: " -msgstr "" - -#: src/rc_formatters.py:851 -msgid "Blocked from editing pages on following namespaces: " -msgstr "" - -#: src/rc_formatters.py:862 -msgid "Partial block details" -msgstr "" - -#: src/rc_formatters.py:863 +#: extensions/base/mediawiki.py:356 #, python-brace-format -msgid "Blocked {blocked_user} {time}" +msgid "[{author}]({author_url}) changed visibility of log events{comment}" msgstr "" -#: src/rc_formatters.py:867 -#, python-brace-format -msgid "Changed block settings for {blocked_user}" -msgstr "" - -#: src/rc_formatters.py:871 -#, python-brace-format -msgid "Unblocked {blocked_user}" -msgstr "" - -#: src/rc_formatters.py:878 -#, python-brace-format -msgid "Left a comment on {target}'s profile" -msgstr "" - -#: src/rc_formatters.py:880 -msgid "Left a comment on their own profile" -msgstr "" - -#: src/rc_formatters.py:887 -#, python-brace-format -msgid "Replied to a comment on {target}'s profile" -msgstr "" - -#: src/rc_formatters.py:889 -msgid "Replied to a comment on their own profile" -msgstr "" - -#: src/rc_formatters.py:896 -#, python-brace-format -msgid "Edited a comment on {target}'s profile" -msgstr "" - -#: src/rc_formatters.py:898 -msgid "Edited a comment on their own profile" -msgstr "" - -#: src/rc_formatters.py:903 -#, python-brace-format -msgid "Edited {target}'s profile" -msgstr "" - -#: src/rc_formatters.py:905 -msgid "Edited their own profile" -msgstr "" - -#: src/rc_formatters.py:907 -#, python-brace-format -msgid "Cleared the {field} field" -msgstr "" - -#: src/rc_formatters.py:909 -#, python-brace-format -msgid "{field} field changed to: {desc}" -msgstr "" - -#: src/rc_formatters.py:914 -#, python-brace-format -msgid "Purged a comment on {target}'s profile" -msgstr "" - -#: src/rc_formatters.py:916 -msgid "Purged a comment on their own profile" -msgstr "" - -#: src/rc_formatters.py:924 -#, python-brace-format -msgid "Deleted a comment on {target}'s profile" -msgstr "" - -#: src/rc_formatters.py:926 -msgid "Deleted a comment on their own profile" -msgstr "" - -#: src/rc_formatters.py:930 -#, python-brace-format -msgid "Changed group membership for {target}" -msgstr "" - -#: src/rc_formatters.py:934 -#, python-brace-format -msgid "{target} got autopromoted to a new usergroup" -msgstr "" - -#: src/rc_formatters.py:949 -#, python-brace-format -msgid "Groups changed from {old_groups} to {new_groups}{reason}" -msgstr "" - -#: src/rc_formatters.py:953 -#, python-brace-format -msgid "Protected {target}" -msgstr "" - -#: src/rc_formatters.py:959 -#, python-brace-format -msgid "Changed protection level for {article}" -msgstr "" - -#: src/rc_formatters.py:965 -#, python-brace-format -msgid "Removed protection from {article}" -msgstr "" - -#: src/rc_formatters.py:969 +#: extensions/base/mediawiki.py:370 #, python-brace-format msgid "Changed visibility of revision on page {article} " msgid_plural "Changed visibility of {amount} revisions on page {article} " msgstr[0] "" msgstr[1] "" -#: src/rc_formatters.py:981 +#: extensions/base/mediawiki.py:383 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed visibility of revision on page [{article}]" +"({article_url}){comment}" +msgid_plural "" +"[{author}]({author_url}) changed visibility of {amount} revisions on page " +"[{article}]({article_url}){comment}" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:399 extensions/base/mediawiki.py:432 +msgid "No redirect has been made" +msgstr "" + +#: extensions/base/mediawiki.py:400 extensions/base/mediawiki.py:433 +msgid "A redirect has been made" +msgstr "" + +#: extensions/base/mediawiki.py:401 +#, python-brace-format +msgid "Moved {redirect}{article} to {target}" +msgstr "" + +#: extensions/base/mediawiki.py:412 extensions/base/mediawiki.py:444 +msgid "without making a redirect" +msgstr "" + +#: extensions/base/mediawiki.py:413 extensions/base/mediawiki.py:445 +msgid "with a redirect" +msgstr "" + +#: extensions/base/mediawiki.py:416 +#, python-brace-format +msgid "" +"[{author}]({author_url}) moved {redirect}*{article}* to [{target}]" +"({target_url}) {made_a_redirect}{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:434 +#, python-brace-format +msgid "Moved {redirect}{article} to {title} over redirect" +msgstr "" + +#: extensions/base/mediawiki.py:448 +#, python-brace-format +msgid "" +"[{author}]({author_url}) moved {redirect}*{article}* over redirect to " +"[{target}]({target_url}) {made_a_redirect}{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:464 +#, python-brace-format +msgid "Moved protection settings from {redirect}{article} to {title}" +msgstr "" + +#: extensions/base/mediawiki.py:477 +#, python-brace-format +msgid "" +"[{author}]({author_url}) moved protection settings from {redirect}*{article}" +"* to [{target}]({target_url}){comment}" +msgstr "" + +#: extensions/base/mediawiki.py:492 +#, python-brace-format +msgid "Protected {target}" +msgstr "" + +#: extensions/base/mediawiki.py:495 extensions/base/mediawiki.py:510 +#: extensions/base/mediawiki.py:526 extensions/base/mediawiki.py:541 +msgid " [cascading]" +msgstr "" + +#: extensions/base/mediawiki.py:506 +#, python-brace-format +msgid "" +"[{author}]({author_url}) protected [{article}]({article_url}) with the " +"following settings: {settings}{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:523 +#, python-brace-format +msgid "Changed protection level for {article}" +msgstr "" + +#: extensions/base/mediawiki.py:537 +#, python-brace-format +msgid "" +"[{author}]({author_url}) modified protection settings of [{article}]" +"({article_url}) to: {settings}{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:554 +#, python-brace-format +msgid "Removed protection from {article}" +msgstr "" + +#: extensions/base/mediawiki.py:563 +#, python-brace-format +msgid "" +"[{author}]({author_url}) removed protection from [{article}]({article_url})" +"{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:572 +msgid "for infinity and beyond" +msgstr "" + +#: extensions/base/mediawiki.py:582 +msgid "for less than a minute" +msgstr "" + +#: extensions/base/mediawiki.py:584 +msgid "year" +msgid_plural "years" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:584 +msgid "day" +msgid_plural "days" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:584 +msgid "hour" +msgid_plural "hours" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:585 +msgid "minute" +msgid_plural "minutes" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:590 +#, python-brace-format +msgid "for {time_number} {time_unit}" +msgstr "" + +#: extensions/base/mediawiki.py:609 +msgid "Blocked from editing the following pages: " +msgstr "" + +#: extensions/base/mediawiki.py:616 extensions/base/mediawiki.py:662 +msgid " and namespaces: " +msgstr "" + +#: extensions/base/mediawiki.py:618 +msgid "Blocked from editing pages on following namespaces: " +msgstr "" + +#: extensions/base/mediawiki.py:629 +msgid "Partial block details" +msgstr "" + +#: extensions/base/mediawiki.py:632 +msgid "Block flags" +msgstr "" + +#: extensions/base/mediawiki.py:634 +#, python-brace-format +msgid "Blocked {blocked_user} {time}" +msgstr "" + +#: extensions/base/mediawiki.py:654 +msgid " on pages: " +msgstr "" + +#: extensions/base/mediawiki.py:664 +msgid " on namespaces: " +msgstr "" + +#: extensions/base/mediawiki.py:676 +#, python-brace-format +msgid "" +"[{author}]({author_url}) blocked [{user}]({user_url}) {time}" +"{restriction_desc}{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:694 +#, python-brace-format +msgid "Changed block settings for {blocked_user}" +msgstr "" + +#: extensions/base/mediawiki.py:704 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed block settings for [{blocked_user}]" +"({user_url}){comment}" +msgstr "" + +#: extensions/base/mediawiki.py:717 +#, python-brace-format +msgid "Unblocked {blocked_user}" +msgstr "" + +#: extensions/base/mediawiki.py:727 +#, python-brace-format +msgid "" +"[{author}]({author_url}) unblocked [{blocked_user}]({user_url}){comment}" +msgstr "" + +#: extensions/base/mediawiki.py:743 +msgid "Action has been hidden by administration" +msgstr "" + +#: extensions/base/mediawiki.py:750 +msgid "An action has been hidden by administration." +msgstr "" + +#: extensions/base/mediawiki.py:761 #, python-brace-format msgid "Imported {article} with {count} revision" msgid_plural "Imported {article} with {count} revisions" msgstr[0] "" msgstr[1] "" -#: src/rc_formatters.py:986 +#: extensions/base/mediawiki.py:772 #, python-brace-format -msgid "Restored {article}" -msgstr "" +msgid "" +"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " +"revision{comment}" +msgid_plural "" +"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " +"revisions{comment}" +msgstr[0] "" +msgstr[1] "" -#: src/rc_formatters.py:989 -msgid "Changed visibility of log events" -msgstr "" - -#: src/rc_formatters.py:999 +#: extensions/base/mediawiki.py:788 #, python-brace-format msgid "Imported {article} with {count} revision from \"{source}\"" msgid_plural "Imported {article} with {count} revisions from \"{source}\"" msgstr[0] "" msgstr[1] "" -#: src/rc_formatters.py:1004 +#: extensions/base/mediawiki.py:803 #, python-brace-format -msgid "Edited abuse filter number {number}" +msgid "" +"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " +"revision from [{source}]({source_url}){comment}" +msgid_plural "" +"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " +"revisions from [{source}]({source_url}){comment}" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:818 +#, python-brace-format +msgid " (until {date_and_time})" msgstr "" -#: src/rc_formatters.py:1007 +#: extensions/base/mediawiki.py:835 #, python-brace-format -msgid "Created abuse filter number {number}" +msgid "Changed group membership for {target}" msgstr "" -#: src/rc_formatters.py:1010 +#: extensions/base/mediawiki.py:837 +msgid "System" +msgstr "" + +#: extensions/base/mediawiki.py:838 +#, python-brace-format +msgid "{target} got autopromoted to a new usergroup" +msgstr "" + +#: extensions/base/mediawiki.py:844 +msgid "Added group" +msgid_plural "Added groups" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:846 +msgid "Removed group" +msgid_plural "Removed groups" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:860 +#, python-brace-format +msgid "Added to {added} and removed from {removed}." +msgstr "" + +#: extensions/base/mediawiki.py:861 extensions/base/mediawiki.py:863 +#: extensions/base/mediawiki.py:865 extensions/base/mediawiki.py:872 +msgid ", " +msgstr "" + +#: extensions/base/mediawiki.py:863 +#, python-brace-format +msgid "Added to {added}." +msgstr "" + +#: extensions/base/mediawiki.py:865 +#, python-brace-format +msgid "Removed from {removed}." +msgstr "" + +#: extensions/base/mediawiki.py:866 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed group membership for [{target}]" +"({target_url}): {group_changes}{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:870 +#, python-brace-format +msgid "The system autopromoted [{target}]({target_url}) to {added}.{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:883 #, python-brace-format msgid "Merged revision histories of {article} into {dest}" msgstr "" -#: src/rc_formatters.py:1014 +#: extensions/base/mediawiki.py:897 +#, python-brace-format +msgid "" +"[{author}]({author_url}) merged revision histories of [{article}]" +"({article_url}) into [{dest}]({dest_url}){comment}" +msgstr "" + +#: extensions/base/mediawiki.py:911 msgid "Created account automatically" msgstr "" -#: src/rc_formatters.py:1017 src/rc_formatters.py:1026 +#: extensions/base/mediawiki.py:918 +#, python-brace-format +msgid "Account [{author}]({author_url}) was created automatically" +msgstr "" + +#: extensions/base/mediawiki.py:931 extensions/base/mediawiki.py:996 msgid "Created account" msgstr "" -#: src/rc_formatters.py:1020 +#: extensions/base/mediawiki.py:938 extensions/base/mediawiki.py:1003 +#, python-brace-format +msgid "Account [{author}]({author_url}) was created" +msgstr "" + +#: extensions/base/mediawiki.py:950 #, python-brace-format msgid "Created account {article}" msgstr "" -#: src/rc_formatters.py:1023 +#: extensions/base/mediawiki.py:959 +#, python-brace-format +msgid "" +"Account [{article}]({article_url}) was created by [{author}]({author_url})" +"{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:972 #, python-brace-format msgid "Created account {article} and password was sent by email" msgstr "" -#: src/rc_formatters.py:1029 -msgid "Added an entry to the interwiki table" -msgstr "" - -#: src/rc_formatters.py:1030 src/rc_formatters.py:1036 +#: extensions/base/mediawiki.py:983 #, python-brace-format -msgid "Prefix: {prefix}, website: {website} | {desc}" +msgid "" +"Account [{article}]({article_url}) was created by [{author}]({author_url}) " +"and password was sent by email{comment}" msgstr "" -#: src/rc_formatters.py:1035 -msgid "Edited an entry in interwiki table" -msgstr "" - -#: src/rc_formatters.py:1041 -msgid "Deleted an entry in interwiki table" -msgstr "" - -#: src/rc_formatters.py:1042 -#, python-brace-format -msgid "Prefix: {prefix} | {desc}" -msgstr "" - -#: src/rc_formatters.py:1045 +#: extensions/base/mediawiki.py:1015 #, python-brace-format msgid "Changed the content model of the page {article}" msgstr "" -#: src/rc_formatters.py:1046 +#: extensions/base/mediawiki.py:1017 #, python-brace-format msgid "Model changed from {old} to {new}: {reason}" msgstr "" -#: src/rc_formatters.py:1051 +#: extensions/base/mediawiki.py:1029 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed the content model of the page [{article}]" +"({article_url}) from {old} to {new}{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:1044 +#, python-brace-format +msgid "Created the page {article} using a non-default content model" +msgstr "" + +#: extensions/base/mediawiki.py:1046 +#, python-brace-format +msgid "Created with model {new}: {reason}" +msgstr "" + +#: extensions/base/mediawiki.py:1057 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created the page [{article}]({article_url}) using a " +"non-default content model {new}{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:1072 +#, python-brace-format +msgid "Created the tag \"{tag}\"" +msgstr "" + +#: extensions/base/mediawiki.py:1082 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created the [tag]({tag_url}) \"{tag}\"{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:1103 +#, python-brace-format +msgid "Deleted the tag \"{tag}\"" +msgstr "" + +#: extensions/base/mediawiki.py:1105 +msgid "Removed from" +msgstr "" + +#: extensions/base/mediawiki.py:1105 +msgid "{} revision or log entry" +msgid_plural "{} revisions and/or log entries" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:1118 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\"{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:1128 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\" and removed " +"it from {count} revision or log entry{comment}" +msgid_plural "" +"[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\" and removed " +"it from {count} revisions and/or log entries{comment}" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:1145 +#, python-brace-format +msgid "Activated the tag \"{tag}\"" +msgstr "" + +#: extensions/base/mediawiki.py:1154 +#, python-brace-format +msgid "" +"[{author}]({author_url}) activated the [tag]({tag_url}) \"{tag}\"{comment}" +msgstr "" + +#: extensions/base/mediawiki.py:1173 +#, python-brace-format +msgid "Deactivated the tag \"{tag}\"" +msgstr "" + +#: extensions/base/mediawiki.py:1182 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deactivated the [tag]({tag_url}) \"{tag}\"{comment}" +msgstr "" + +#: extensions/base/sprite.py:37 #, python-brace-format msgid "Edited the sprite for {article}" msgstr "" -#: src/rc_formatters.py:1054 +#: extensions/base/sprite.py:45 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited the sprite for [{article}]({article_url})" +msgstr "" + +#: extensions/base/sprite.py:60 #, python-brace-format msgid "Created the sprite sheet for {article}" msgstr "" -#: src/rc_formatters.py:1057 +#: extensions/base/sprite.py:68 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created the sprite sheet for [{article}]" +"({article_url})" +msgstr "" + +#: extensions/base/sprite.py:79 #, python-brace-format msgid "Edited the slice for {article}" msgstr "" -#: src/rc_formatters.py:1063 -#, python-brace-format -msgid "Created the Cargo table \"{table}\"" -msgstr "" - -#: src/rc_formatters.py:1067 -#, python-brace-format -msgid "Deleted the Cargo table \"{table}\"" -msgstr "" - -#: src/rc_formatters.py:1074 -#, python-brace-format -msgid "Recreated the Cargo table \"{table}\"" -msgstr "" - -#: src/rc_formatters.py:1081 -#, python-brace-format -msgid "Replaced the Cargo table \"{table}\"" -msgstr "" - -#: src/rc_formatters.py:1085 -#, python-brace-format -msgid "Created a tag \"{tag}\"" -msgstr "" - -#: src/rc_formatters.py:1089 -#, python-brace-format -msgid "Deleted a tag \"{tag}\"" -msgstr "" - -#: src/rc_formatters.py:1093 -#, python-brace-format -msgid "Activated a tag \"{tag}\"" -msgstr "" - -#: src/rc_formatters.py:1096 -#, python-brace-format -msgid "Deactivated a tag \"{tag}\"" -msgstr "" - -#: src/rc_formatters.py:1099 -msgid "Changed wiki settings" -msgstr "" - -#: src/rc_formatters.py:1103 -#, python-brace-format -msgid "Deleted a \"{wiki}\" wiki" -msgstr "" - -#: src/rc_formatters.py:1106 -#, python-brace-format -msgid "Locked a \"{wiki}\" wiki" -msgstr "" - -#: src/rc_formatters.py:1109 -#, python-brace-format -msgid "Modified a \"{namespace_name}\" namespace" -msgstr "" - -#: src/rc_formatters.py:1111 src/rc_formatters.py:1116 -msgid "Wiki" -msgstr "" - -#: src/rc_formatters.py:1113 -#, python-brace-format -msgid "Deleted a \"{namespace_name}\" namespace" -msgstr "" - -#: src/rc_formatters.py:1119 -#, python-brace-format -msgid "Modified \"{usergroup_name}\" usergroup" -msgstr "" - -#: src/rc_formatters.py:1122 -#, python-brace-format -msgid "Restored a \"{wiki}\" wiki" -msgstr "" - -#: src/rc_formatters.py:1125 -#, python-brace-format -msgid "Unlocked a \"{wiki}\" wiki" -msgstr "" - -#: src/rc_formatters.py:1133 -#, python-brace-format -msgid "Marked \"{article}\" for translation" -msgstr "" - -#: src/rc_formatters.py:1136 -#, python-brace-format -msgid "Removed \"{article}\" from the translation system" -msgstr "" - -#: src/rc_formatters.py:1139 -#, python-brace-format -msgid "Completed moving translation pages from \"{article}\" to \"{target}\"" -msgstr "" - -#: src/rc_formatters.py:1142 -#, python-brace-format -msgid "Encountered a problem while moving \"{article}\" to \"{target}\"" -msgstr "" - -#: src/rc_formatters.py:1145 -#, python-brace-format -msgid "Completed deletion of translatable page \"{article}\"" -msgstr "" - -#: src/rc_formatters.py:1148 +#: extensions/base/sprite.py:86 #, python-brace-format msgid "" -"Failed to delete \"{article}\" which belongs to translatable page " -"\"{target}\"" -msgstr "" - -#: src/rc_formatters.py:1151 -#, python-brace-format -msgid "Completed deletion of translation page \"{article}\"" -msgstr "" - -#: src/rc_formatters.py:1154 -#, python-brace-format -msgid "" -"Failed to delete \"{article}\" which belongs to translation page \"{target}\"" -msgstr "" - -#: src/rc_formatters.py:1157 -#, python-brace-format -msgid "Encouraged translation of \"{article}\"" -msgstr "" - -#: src/rc_formatters.py:1160 -#, python-brace-format -msgid "Discouraged translation of \"{article}\"" -msgstr "" - -#: src/rc_formatters.py:1166 -#, python-brace-format -msgid "Limited languages for \"{article}\" to `{languages}`" -msgstr "" - -#: src/rc_formatters.py:1168 -#, python-brace-format -msgid "Priority languages for \"{article}\" set to `{languages}`" -msgstr "" - -#: src/rc_formatters.py:1170 -#, python-brace-format -msgid "Removed priority languages from \"{article}\"" -msgstr "" - -#: src/rc_formatters.py:1173 -#, python-brace-format -msgid "Added translatable page \"{article}\" to aggregate group \"{group}\"" -msgstr "" - -#: src/rc_formatters.py:1176 -#, python-brace-format -msgid "" -"Removed translatable page \"{article}\" from aggregate group \"{group}\"" -msgstr "" - -#: src/rc_formatters.py:1183 -#, python-brace-format -msgid "Reviewed translation \"{article}\"" -msgstr "" - -#: src/rc_formatters.py:1186 -#, python-brace-format -msgid "Changed the state of `{language}` translations of \"{article}\"" -msgstr "" - -#: src/rc_formatters.py:1188 -msgid "Old state" -msgstr "" - -#: src/rc_formatters.py:1189 -msgid "New state" -msgstr "" - -#: src/rc_formatters.py:1193 -#, python-brace-format -msgid "Renamed user \"{old_name}\" with {edits} edit to \"{new_name}\"" -msgid_plural "Renamed user \"{old_name}\" with {edits} edits to \"{new_name}\"" -msgstr[0] "" -msgstr[1] "" - -#: src/rc_formatters.py:1195 -#, python-brace-format -msgid "Renamed user \"{old_name}\" to \"{new_name}\"" -msgstr "" - -#: src/rc_formatters.py:1199 -msgid "Action has been hidden by administration" -msgstr "" - -#: src/rc_formatters.py:1204 -#, python-brace-format -msgid "Unknown event `{event}`" -msgstr "" - -#: src/rc_formatters.py:1210 src/rc_formatters.py:1212 -msgid "Report this on the support server" -msgstr "" - -#: src/rc_formatters.py:1229 -msgid "Tags" -msgstr "" - -#: src/rc_formatters.py:1234 -msgid "**Added**: " -msgstr "" - -#: src/rc_formatters.py:1234 -msgid " and {} more\n" -msgstr "" - -#: src/rc_formatters.py:1235 -msgid "**Removed**: " -msgstr "" - -#: src/rc_formatters.py:1235 -msgid " and {} more" -msgstr "" - -#: src/rc_formatters.py:1236 -msgid "Changed categories" +"[{author}]({author_url}) edited the slice for [{article}]({article_url})" msgstr "" diff --git a/locale/bn/LC_MESSAGES/rc_formatters.mo b/locale/bn/LC_MESSAGES/rc_formatters.mo deleted file mode 100644 index 55f93c7..0000000 Binary files a/locale/bn/LC_MESSAGES/rc_formatters.mo and /dev/null differ diff --git a/locale/de/LC_MESSAGES/discussion_formatters.mo b/locale/de/LC_MESSAGES/discussion_formatters.mo deleted file mode 100644 index e393df6..0000000 Binary files a/locale/de/LC_MESSAGES/discussion_formatters.mo and /dev/null differ diff --git a/locale/de/LC_MESSAGES/discussion_formatters.po b/locale/de/LC_MESSAGES/discussion_formatters.po deleted file mode 100644 index ab647c4..0000000 --- a/locale/de/LC_MESSAGES/discussion_formatters.po +++ /dev/null @@ -1,185 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-12-23 00:28+0100\n" -"PO-Revision-Date: 2020-12-13 14:30+0000\n" -"Last-Translator: Frisk The Evil Goat Overlord \n" -"Language-Team: German \n" -"Language: de\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.2.1\n" - -#: src/discussion_formatters.py:21 src/discussion_formatters.py:56 -#: src/discussion_formatters.py:67 src/discussion_formatters.py:95 -#: src/discussion_formatters.py:163 src/discussion_formatters.py:176 -msgid "unknown" -msgstr "Unbekannt" - -#: src/discussion_formatters.py:27 src/discussion_formatters.py:102 -msgid "Unregistered user" -msgstr "Nicht angemeldeter Benutzer" - -#: src/discussion_formatters.py:39 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created [{title}](<{url}f/p/{threadId}>) in " -"{forumName}" -msgstr "" -"[{author}]({author_url}) erstellte [{title}](<{url}f/p/{threadId}>) in " -"{forumName}" - -#: src/discussion_formatters.py:42 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created a poll [{title}](<{url}f/p/{threadId}>) in " -"{forumName}" -msgstr "" -"[{author}]({author_url}) erstellte eine Umfrage [{title}](<{url}f/p/" -"{threadId}>) in {forumName}" - -#: src/discussion_formatters.py:45 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created a quiz [{title}](<{url}f/p/{threadId}>) in " -"{forumName}" -msgstr "" -"[{author}]({author_url}) erstellte ein Quiz [{title}](<{url}f/p/{threadId}>) " -"in {forumName}" - -#: src/discussion_formatters.py:54 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created a [reply](<{url}f/p/{threadId}/r/{postId}>) " -"to [{title}](<{url}f/p/{threadId}>) in {forumName}" -msgstr "" -"[{author}]({author_url}) erstellte eine [Antwort](<{url}f/p/{threadId}/r/" -"{postId}>) zu [{title}](<{url}f/p/{threadId}>) in {forumName}" - -#: src/discussion_formatters.py:61 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created [{title}](<{url}wiki/Message_Wall:" -"{user_wall}?threadId={threadId}>) on [{user}'s Message Wall](<{url}wiki/" -"Message_Wall:{user_wall}>)" -msgstr "" -"[{author}]({author_url}) erstellte [{title}](<{url}wiki/Message_Wall:" -"{user_wall}?threadId={threadId}>) auf der [Nachrichtenseite von {user}]" -"(<{url}wiki/Message_Wall:{user_wall}>)" - -#: src/discussion_formatters.py:64 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created a [reply](<{url}wiki/Message_Wall:" -"{user_wall}?threadId={threadId}#{replyId}>) to [{title}](<{url}wiki/" -"Message_Wall:{user_wall}?threadId={threadId}>) on [{user}'s Message Wall]" -"(<{url}wiki/Message_Wall:{user_wall}>)" -msgstr "" -"[{author}]({author_url}) erstellte eine [Antwort](<{url}wiki/Message_Wall:" -"{user_wall}?threadId={threadId}#{replyId}>) auf [{title}](<{url}wiki/" -"Message_Wall:{user_wall}?threadId={threadId}>) auf der [Nachrichtenseite von " -"{user}](<{url}wiki/Message_Wall:{user_wall}>)" - -#: src/discussion_formatters.py:72 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created a [comment](<{url}?commentId={commentId}>) " -"on [{article}](<{url}>)" -msgstr "" -"[{author}]({author_url}) erstellte ein [Kommentar](<{url}?" -"commentId={commentId}>) zu [{article}](<{url}>)" - -#: src/discussion_formatters.py:78 -#, python-brace-format -msgid "" -"[{author}]({author_url}) created a [reply](<{url}?commentId={commentId}" -"&replyId={replyId}>) to a [comment](<{url}?commentId={commentId}>) on " -"[{article}](<{url}>)" -msgstr "" -"[{author}]({author_url}) erstellte eine [Antwort](<{url}?" -"commentId={commentId}&replyId={replyId}>) auf ein [Kommentar](<{url}?" -"commentId={commentId}>) zu [{article}](<{url}>)" - -#: src/discussion_formatters.py:86 -#, python-brace-format -msgid "" -"Unknown event `{event}` by [{author}]({author_url}), report it on the " -"[support server](<{support}>)." -msgstr "" -"Unbekanntes Event `{event}` von [{author}]({author_url}), melde es auf dem " -"[Support-Server](<{support}>)." - -#: src/discussion_formatters.py:123 -#, python-brace-format -msgid "Created \"{title}\"" -msgstr "Erstellte „{title}“" - -#: src/discussion_formatters.py:127 -#, python-brace-format -msgid "Created a poll \"{title}\"" -msgstr "Erstellte eine Umfrage „{title}“" - -#: src/discussion_formatters.py:134 -msgid "Option {}" -msgstr "Option {}" - -#: src/discussion_formatters.py:135 -#, python-brace-format -msgid "__[View image]({image_url})__" -msgstr "__[Bild öffnen]({image_url})__" - -#: src/discussion_formatters.py:139 -#, python-brace-format -msgid "Created a quiz \"{title}\"" -msgstr "Erstellte ein Quiz „{title}“" - -#: src/discussion_formatters.py:155 src/discussion_formatters.py:157 -msgid "Tags" -msgstr "Tags" - -#: src/discussion_formatters.py:155 -msgid "{} tags" -msgstr "{} Tags" - -#: src/discussion_formatters.py:160 -#, python-brace-format -msgid "Replied to \"{title}\"" -msgstr "Antwortete auf „{title}“" - -#: src/discussion_formatters.py:169 -#, python-brace-format -msgid "Created \"{title}\" on {user}'s Message Wall" -msgstr "Erstellte „{title}“ auf der Nachrichtenseite von {user}" - -#: src/discussion_formatters.py:173 -#, python-brace-format -msgid "Replied to \"{title}\" on {user}'s Message Wall" -msgstr "Antwortete auf „{title}“ auf der Nachrichtenseite von {user}" - -#: src/discussion_formatters.py:180 -#, python-brace-format -msgid "Commented on {article}" -msgstr "Kommentierte zu „{article}“" - -#: src/discussion_formatters.py:184 -#, python-brace-format -msgid "Replied to a comment on {article}" -msgstr "Antwortete auf ein Kommentar zu „{article}“" - -#: src/discussion_formatters.py:188 -#, python-brace-format -msgid "Unknown event `{event}`" -msgstr "Unbekanntes Event `{event}`" - -#: src/discussion_formatters.py:194 src/discussion_formatters.py:196 -msgid "Report this on the support server" -msgstr "Melde es auf dem Support-Server" diff --git a/locale/de/LC_MESSAGES/formatters.mo b/locale/de/LC_MESSAGES/formatters.mo new file mode 100644 index 0000000..5b622a6 Binary files /dev/null and b/locale/de/LC_MESSAGES/formatters.mo differ diff --git a/locale/de/LC_MESSAGES/formatters.po b/locale/de/LC_MESSAGES/formatters.po new file mode 100644 index 0000000..82a6f74 --- /dev/null +++ b/locale/de/LC_MESSAGES/formatters.po @@ -0,0 +1,1999 @@ +# #-#-#-#-# formatters.po #-#-#-#-# +# #-#-#-#-# discussion_formatters.po #-#-#-#-# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-07-11 14:32+0200\n" +"PO-Revision-Date: 2021-07-30 10:44+0000\n" +"Last-Translator: MarkusRost \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.6.2\n" +"X-Loco-Source-Locale: de_DE\n" +"Generated-By: pygettext.py 1.5\n" +"X-Loco-Parser: loco_parse_po\n" + +#: src/api/util.py:61 src/api/util.py:66 +msgid "__Only whitespace__" +msgstr "__Nur Leerraum__" + +#: src/api/util.py:71 +msgid "Removed" +msgstr "Entfernt" + +#: src/api/util.py:73 +msgid "Added" +msgstr "Hinzugefügt" + +#: src/api/util.py:94 src/api/util.py:126 src/api/util.py:133 +#: src/api/util.py:141 extensions/base/discussions.py:247 +#: extensions/base/discussions.py:264 extensions/base/abusefilter.py:45 +msgid "Unregistered user" +msgstr "Nicht angemeldeter Benutzer" + +#: src/api/util.py:160 +msgctxt "recent changes Tags" +msgid "Tags" +msgstr "Markierungen" + +#: src/api/util.py:162 +msgid "**Added**: " +msgstr "**Hinzugefügt:** " + +#: src/api/util.py:163 +msgid " and {} more\n" +msgstr " und {} mehr\n" + +#: src/api/util.py:165 +msgid "**Removed**: " +msgstr "**Entfernt:** " + +#: src/api/util.py:166 +msgid " and {} more" +msgstr " und {} mehr" + +#: src/api/util.py:168 +msgid "Changed categories" +msgstr "Geänderte Kategorien" + +#: extensions/base/cargo.py:37 +#, python-brace-format +msgid "Created the Cargo table \"{table}\"" +msgstr "Erstellte die Cargo-Tabelle „{table}“" + +#: extensions/base/cargo.py:45 +#, python-brace-format +msgid "[{author}]({author_url}) created the Cargo table \"{table}\"" +msgstr "[{author}]({author_url}) erstellte die Cargo-Tabelle „{table}“" + +#: extensions/base/cargo.py:60 +#, python-brace-format +msgid "Recreated the Cargo table \"{table}\"" +msgstr "Erstellte die Cargo-Tabelle „{table}“ neu" + +#: extensions/base/cargo.py:68 +#, python-brace-format +msgid "[{author}]({author_url}) recreated the Cargo table \"{table}\"" +msgstr "[{author}]({author_url}) erstellte die Cargo-Tabelle „{table}“ neu" + +#: extensions/base/cargo.py:83 +#, python-brace-format +msgid "Replaced the Cargo table \"{table}\"" +msgstr "Ersetzte die Cargo-Tabelle „{table}“" + +#: extensions/base/cargo.py:91 +#, python-brace-format +msgid "[{author}]({author_url}) replaced the Cargo table \"{table}\"" +msgstr "[{author}]({author_url}) ersetzte die Cargo-Tabelle „{table}“" + +#: extensions/base/cargo.py:105 +#, python-brace-format +msgid "Deleted the Cargo table \"{table}\"" +msgstr "Löschte die Cargo-Tabelle „{table}“" + +#: extensions/base/cargo.py:112 +#, python-brace-format +msgid "[{author}]({author_url}) deleted the Cargo table \"{table}\"" +msgstr "[{author}]({author_url}) löschte die Cargo-Tabelle „{table}“" + +#: extensions/base/translate.py:41 +#, python-brace-format +msgid "Marked \"{article}\" for translation" +msgstr "Markierte „{article}“ zum Übersetzen" + +#: extensions/base/translate.py:55 +#, python-brace-format +msgid "" +"[{author}]({author_url}) marked [{article}]({article_url}) for " +"translation{comment}" +msgstr "" +"[{author}]({author_url}) markierte [{article}]({article_url}) zur " +"Übersetzung{comment}" + +#: extensions/base/translate.py:70 +#, python-brace-format +msgid "Removed \"{article}\" from the translation system" +msgstr "Entfernte „{article}“ aus dem Übersetzungssystem" + +#: extensions/base/translate.py:80 +#, python-brace-format +msgid "" +"[{author}]({author_url}) removed [{article}]({article_url}) from the " +"translation system{comment}" +msgstr "" +"[{author}]({author_url}) entfernte [{article}]({article_url}) aus dem " +"Übersetzungssystem{comment}" + +#: extensions/base/translate.py:95 +#, python-brace-format +msgid "Completed moving translation pages from \"{article}\" to \"{target}\"" +msgstr "" +"Schloss die Verschiebung der Übersetzungsseiten von „{article}“ nach " +"„{target}“ ab" + +#: extensions/base/translate.py:106 +#, python-brace-format +msgid "" +"[{author}]({author_url}) completed moving translation pages from *{article}* " +"to [{target}]({target_url}){comment}" +msgstr "" +"[{author}]({author_url}) schloss die Umbenennung der übersetzbaren Seite von " +"*{article}* nach [{target}]({target_url}) ab{comment}" + +#: extensions/base/translate.py:121 +#, python-brace-format +msgid "Encountered a problem while moving \"{article}\" to \"{target}\"" +msgstr "Hatte ein Problem beim Verschieben von „{article}“ nach „{target}“" + +#: extensions/base/translate.py:133 +#, python-brace-format +msgid "" +"[{author}]({author_url}) encountered a problem while moving [{article}]" +"({article_url}) to [{target}]({target_url}){comment}" +msgstr "" +"[{author}]({author_url}) hatte ein Problem beim Verschieben der Seite von " +"[{article}]({article_url}) nach [{target}]({target_url}){comment}" + +#: extensions/base/translate.py:149 +#, python-brace-format +msgid "" +"Failed to delete \"{article}\" which belongs to translatable page " +"\"{target}\"" +msgstr "" +"Konnte „{article}“ nicht löschen, die zur übersetzbaren Seite „{target}“ " +"gehört" + +#: extensions/base/translate.py:161 +#, python-brace-format +msgid "" +"[{author}]({author_url}) failed to delete [{article}]({article_url}) which " +"belongs to translatable page [{target}]({target_url}){comment}" +msgstr "" +"[{author}]({author_url}) konnte die Seite [{article}]({article_url}) nicht " +"löschen, die zur übersetzbaren Seite [{target}]({target_url}) gehört{comment}" + +#: extensions/base/translate.py:177 +#, python-brace-format +msgid "Completed deletion of translation page \"{article}\"" +msgstr "Schloss die Löschung der Übersetzungsseite „{article}“ ab" + +#: extensions/base/translate.py:188 +#, python-brace-format +msgid "" +"[{author}]({author_url}) completed deletion of translation page [{article}]" +"({article_url}){comment}" +msgstr "" +"[{author}]({author_url}) schloss die Löschung der Übersetzungsseite " +"[{article}]({article_url}) ab{comment}" + +#: extensions/base/translate.py:203 +#, python-brace-format +msgid "" +"Failed to delete \"{article}\" which belongs to translation page \"{target}\"" +msgstr "" +"Konnte „{article}“ nicht löschen, die zur Übersetzungsseite „{target}“ gehört" + +#: extensions/base/translate.py:215 +#, python-brace-format +msgid "" +"[{author}]({author_url}) failed to delete [{article}]({article_url}) which " +"belongs to translation page [{target}]({target_url}){comment}" +msgstr "" +"[{author}]({author_url}) konnte die Seite [{article}]({article_url}) nicht " +"löschen, die zur Übersetzungsseite [{target}]({target_url}) gehört{comment}" + +#: extensions/base/translate.py:231 +#, python-brace-format +msgid "Encouraged translation of \"{article}\"" +msgstr "Empfahl die Übersetzung von „{article}“" + +#: extensions/base/translate.py:240 +#, python-brace-format +msgid "" +"[{author}]({author_url}) encouraged translation of [{article}]({article_url})" +"{comment}" +msgstr "" +"[{author}]({author_url}) empfahl die Übersetzung der Seite [{article}]" +"({article_url}){comment}" + +#: extensions/base/translate.py:255 +#, python-brace-format +msgid "Discouraged translation of \"{article}\"" +msgstr "Riet von der Übersetzung von „{article}“ ab" + +#: extensions/base/translate.py:264 +#, python-brace-format +msgid "" +"[{author}]({author_url}) discouraged translation of [{article}]" +"({article_url}){comment}" +msgstr "" +"[{author}]({author_url}) riet von der Übersetzung der Seite [{article}]" +"({article_url}) ab{comment}" + +#: extensions/base/translate.py:282 +#, python-brace-format +msgid "Limited languages for \"{article}\" to `{languages}`" +msgstr "Begrenzte die Sprachen für „{article}“ auf `{languages}`" + +#: extensions/base/translate.py:285 +#, python-brace-format +msgid "Priority languages for \"{article}\" set to `{languages}`" +msgstr "" +"Legte die priorisierten Sprachen für „{article}“ auf `{languages}` fest" + +#: extensions/base/translate.py:288 +#, python-brace-format +msgid "Removed priority languages from \"{article}\"" +msgstr "Entfernte die priorisierten Sprachen von „{article}“" + +#: extensions/base/translate.py:301 +#, python-brace-format +msgid "" +"[{author}]({author_url}) limited languages for [{article}]({article_url}) to " +"`{languages}`{comment}" +msgstr "" +"[{author}]({author_url}) begrenzte die Sprachen für [{article}]" +"({article_url}) auf `{languages}`{comment}" + +#: extensions/base/translate.py:308 +#, python-brace-format +msgid "" +"[{author}]({author_url}) set the priority languages for [{article}]" +"({article_url}) to `{languages}`{comment}" +msgstr "" +"[{author}]({author_url}) legte die priorisierten Sprachen für [{article}]" +"({article_url}) auf `{languages}` fest{comment}" + +#: extensions/base/translate.py:315 +#, python-brace-format +msgid "" +"[{author}]({author_url}) removed priority languages from [{article}]" +"({article_url}){comment}" +msgstr "" +"[{author}]({author_url}) entfernte die priorisierten Sprachen von [{article}]" +"({article_url}){comment}" + +#: extensions/base/translate.py:331 +#, python-brace-format +msgid "Added translatable page \"{article}\" to aggregate group \"{group}\"" +msgstr "" +"Fügte die übersetzbare Seite „{article}“ zur zusammenfassenden Gruppe " +"„{group}“ hinzu" + +#: extensions/base/translate.py:342 +#, python-brace-format +msgid "" +"[{author}]({author_url}) added translatable page [{article}]({article_url}) " +"to aggregate group \"{group}\"{comment}" +msgstr "" +"[{author}]({author_url}) fügte die übersetzbare Seite [{article}]" +"({article_url}) zur zusammenfassenden Gruppe „{group}“ hinzu{comment}" + +#: extensions/base/translate.py:357 +#, python-brace-format +msgid "" +"Removed translatable page \"{article}\" from aggregate group \"{group}\"" +msgstr "" +"Entfernte die übersetzbare Seite „{article}“ von der zusammenfassenden " +"Gruppe „{group}“" + +#: extensions/base/translate.py:368 +#, python-brace-format +msgid "" +"[{author}]({author_url}) removed translatable page [{article}]" +"({article_url}) from aggregate group \"{group}\"{comment}" +msgstr "" +"[{author}]({author_url}) entfernte die übersetzbare Seite [{article}]" +"({article_url}) von der zusammenfassenden Gruppe „{group}“{comment}" + +#: extensions/base/translate.py:387 +#, python-brace-format +msgid "Reviewed translation \"{article}\"" +msgstr "Überprüfte die Übersetzung „{article}“" + +#: extensions/base/translate.py:401 +#, python-brace-format +msgid "" +"[{author}]({author_url}) reviewed translation [{article}]({article_url})" +"{comment}" +msgstr "" +"[{author}]({author_url}) überprüfte die Übersetzung [{article}]" +"({article_url}){comment}" + +#: extensions/base/translate.py:416 +#, python-brace-format +msgid "Changed the state of `{language}` translations of \"{article}\"" +msgstr "Änderte den Status der Übersetzungen in `{language}` für „{article}“" + +#: extensions/base/translate.py:419 +msgid "Old state" +msgstr "Alter Status" + +#: extensions/base/translate.py:420 +msgid "New state" +msgstr "Neuer Status" + +#: extensions/base/translate.py:431 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed the state of `{language}` translations of " +"[{article}]({article_url}) from `{old_state}` to `{new_state}`{comment}" +msgstr "" +"[{author}]({author_url}) änderte den Status der Übersetzungen in der Sprache " +"`{language}` der Seite [{article}]({article_url}) von `{old_state}` in " +"`{new_state}`{comment}" + +#: extensions/base/translate.py:439 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed the state of `{language}` translations of " +"[{article}]({article_url}) to `{new_state}`{comment}" +msgstr "" +"[{author}]({author_url}) änderte den Status der Übersetzungen in der Sprache " +"`{language}` der Seite [{article}]({article_url}) in `{new_state}`{comment}" + +#: extensions/base/translate.py:452 extensions/base/translate.py:455 +msgid "(default)" +msgstr "(Standard)" + +#: extensions/base/translate.py:464 +#, python-brace-format +msgid "Changed the language of \"{article}\"" +msgstr "Änderte die Sprache für „{article}“" + +#: extensions/base/translate.py:465 +msgid "Old language" +msgstr "Alte Sprache" + +#: extensions/base/translate.py:466 +msgid "New language" +msgstr "Neue Sprache" + +#: extensions/base/translate.py:477 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed the language of [{article}]({article_url}) " +"from {old_lang} to {new_lang}{comment}" +msgstr "" +"[{author}]({author_url}) änderte die Sprache für [{article}]({article_url}) " +"von {old_lang} zu {new_lang}{comment}" + +#: extensions/base/discussions.py:148 extensions/base/discussions.py:207 +#: extensions/base/discussions.py:245 extensions/base/discussions.py:261 +#: extensions/base/discussions.py:284 extensions/base/discussions.py:306 +#: extensions/base/discussions.py:334 extensions/base/discussions.py:354 +msgid "unknown" +msgstr "Unbekannt" + +#: extensions/base/discussions.py:157 +#, python-brace-format +msgid "Created \"{title}\"" +msgstr "Erstellte „{title}“" + +#: extensions/base/discussions.py:161 +#, python-brace-format +msgid "Created a poll \"{title}\"" +msgstr "Erstellte eine Umfrage „{title}“" + +#: extensions/base/discussions.py:168 +msgid "Option {}" +msgstr "Option {}" + +#: extensions/base/discussions.py:170 +#, python-brace-format +msgid "__[View image]({image_url})__" +msgstr "__[Bild öffnen]({image_url})__" + +#: extensions/base/discussions.py:174 +#, python-brace-format +msgid "Created a quiz \"{title}\"" +msgstr "Erstellte ein Quiz „{title}“" + +#: extensions/base/discussions.py:193 extensions/base/discussions.py:195 +msgctxt "Fandom discussions Tags/Forums" +msgid "Tags" +msgstr "Tags" + +#: extensions/base/discussions.py:193 +msgctxt "Fandom discussions amount of Tags/Forums" +msgid "{} tags" +msgstr "{} Tags" + +#: extensions/base/discussions.py:198 +#, python-brace-format +msgid "Replied to \"{title}\"" +msgstr "Antwortete auf „{title}“" + +#: extensions/base/discussions.py:214 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created [{title}](<{url}f/p/{threadId}>) in " +"{forumName}" +msgstr "" +"[{author}]({author_url}) erstellte [{title}](<{url}f/p/{threadId}>) in " +"{forumName}" + +#: extensions/base/discussions.py:217 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a poll [{title}](<{url}f/p/{threadId}>) in " +"{forumName}" +msgstr "" +"[{author}]({author_url}) erstellte eine Umfrage [{title}](<{url}f/p/" +"{threadId}>) in {forumName}" + +#: extensions/base/discussions.py:220 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a quiz [{title}](<{url}f/p/{threadId}>) in " +"{forumName}" +msgstr "" +"[{author}]({author_url}) erstellte ein Quiz [{title}](<{url}f/p/{threadId}>) " +"in {forumName}" + +#: extensions/base/discussions.py:234 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a [reply](<{url}f/p/{threadId}/r/{postId}>) " +"to [{title}](<{url}f/p/{threadId}>) in {forumName}" +msgstr "" +"[{author}]({author_url}) erstellte eine [Antwort](<{url}f/p/{threadId}/r/" +"{postId}>) zu [{title}](<{url}f/p/{threadId}>) in {forumName}" + +#: extensions/base/discussions.py:292 +#, python-brace-format +msgid "Created \"{title}\" on {user}'s Message Wall" +msgstr "Erstellte „{title}“ auf der Nachrichtenseite von {user}" + +#: extensions/base/discussions.py:298 +#, python-brace-format +msgid "Replied to \"{title}\" on {user}'s Message Wall" +msgstr "Antwortete auf „{title}“ auf der Nachrichtenseite von {user}" + +#: extensions/base/discussions.py:312 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created [{title}](<{url}wiki/Message_Wall:" +"{user_wall}?threadId={threadId}>) on [{user}'s Message Wall](<{url}wiki/" +"Message_Wall:{user_wall}>)" +msgstr "" +"[{author}]({author_url}) erstellte [{title}](<{url}wiki/Message_Wall:" +"{user_wall}?threadId={threadId}>) auf der [Nachrichtenseite von {user}]" +"(<{url}wiki/Message_Wall:{user_wall}>)" + +#: extensions/base/discussions.py:318 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a [reply](<{url}wiki/Message_Wall:" +"{user_wall}?threadId={threadId}#{replyId}>) to [{title}](<{url}wiki/" +"Message_Wall:{user_wall}?threadId={threadId}>) on [{user}'s Message Wall]" +"(<{url}wiki/Message_Wall:{user_wall}>)" +msgstr "" +"[{author}]({author_url}) erstellte eine [Antwort](<{url}wiki/Message_Wall:" +"{user_wall}?threadId={threadId}#{replyId}>) auf [{title}](<{url}wiki/" +"Message_Wall:{user_wall}?threadId={threadId}>) auf der [Nachrichtenseite von " +"{user}](<{url}wiki/Message_Wall:{user_wall}>)" + +#: extensions/base/discussions.py:338 +#, python-brace-format +msgid "Commented on {article}" +msgstr "Kommentierte zu „{article}“" + +#: extensions/base/discussions.py:344 +#, python-brace-format +msgid "Replied to a comment on {article}" +msgstr "Antwortete auf ein Kommentar zu „{article}“" + +#: extensions/base/discussions.py:359 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a [comment](<{url}?commentId={commentId}>) " +"on [{article}](<{url}>)" +msgstr "" +"[{author}]({author_url}) erstellte ein [Kommentar](<{url}?" +"commentId={commentId}>) zu [{article}](<{url}>)" + +#: extensions/base/discussions.py:365 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a [reply](<{url}?commentId={commentId}" +"&replyId={replyId}>) to a [comment](<{url}?commentId={commentId}>) on " +"[{article}](<{url}>)" +msgstr "" +"[{author}]({author_url}) erstellte eine [Antwort](<{url}?" +"commentId={commentId}&replyId={replyId}>) auf ein [Kommentar](<{url}?" +"commentId={commentId}>) zu [{article}](<{url}>)" + +#: extensions/base/managewiki.py:34 +msgid "Changed wiki settings" +msgstr "Änderte Wiki-Einstellungen" + +#: extensions/base/managewiki.py:44 +#, python-brace-format +msgid "[{author}]({author_url}) changed wiki settings{reason}" +msgstr "[{author}]({author_url}) änderte Wiki-Einstellungen{reason}" + +#: extensions/base/managewiki.py:55 +#, python-brace-format +msgid "Deleted a \"{wiki}\" wiki" +msgstr "Löschte das Wiki „{wiki}“" + +#: extensions/base/managewiki.py:55 extensions/base/managewiki.py:67 +#: extensions/base/managewiki.py:103 extensions/base/managewiki.py:112 +#: extensions/base/managewiki.py:125 extensions/base/managewiki.py:126 +#: extensions/base/managewiki.py:135 extensions/base/managewiki.py:136 +#: extensions/base/managewiki.py:148 extensions/base/managewiki.py:149 +#: extensions/base/managewiki.py:160 extensions/base/managewiki.py:161 +#: extensions/base/managewiki.py:195 extensions/base/managewiki.py:204 +#: extensions/base/managewiki.py:217 extensions/base/managewiki.py:226 +#: extensions/base/abusefilter.py:55 extensions/base/abusefilter.py:56 +#: extensions/base/abusefilter.py:57 extensions/base/abusefilter.py:68 +#: extensions/base/abusefilter.py:69 extensions/base/abusefilter.py:70 +#: extensions/base/mediawiki.py:743 +msgid "Unknown" +msgstr "Unbekannt" + +#: extensions/base/managewiki.py:63 +#, python-brace-format +msgid "[{author}]({author_url}) deleted a wiki *{wiki_name}*{comment}" +msgstr "[{author}]({author_url}) löschte das Wiki *{wiki_name}*{comment}" + +#: extensions/base/managewiki.py:80 +#, python-brace-format +msgid "Deleted a \"{group}\" user group" +msgstr "Löschte die Benutzergruppe „{group}“" + +#: extensions/base/managewiki.py:89 +#, python-brace-format +msgid "[{author}]({author_url}) deleted a usergroup *{group}*{comment}" +msgstr "[{author}]({author_url}) löschte die Benutzergruppe *{group}*{comment}" + +#: extensions/base/managewiki.py:103 +#, python-brace-format +msgid "Locked a \"{wiki}\" wiki" +msgstr "Sperrte das Wiki „{wiki}“" + +#: extensions/base/managewiki.py:111 +#, python-brace-format +msgid "[{author}]({author_url}) locked a wiki *{wiki_name}*{comment}" +msgstr "[{author}]({author_url}) sperrte das Wiki *{wiki_name}*{comment}" + +#: extensions/base/managewiki.py:124 +#, python-brace-format +msgid "Modified \"{namespace_name}\" namespace" +msgstr "Bearbeitete den Namensraum „{namespace_name}“" + +#: extensions/base/managewiki.py:126 extensions/base/managewiki.py:149 +msgid "Wiki" +msgstr "Wiki" + +#: extensions/base/managewiki.py:134 +#, python-brace-format +msgid "" +"[{author}]({author_url}) modified namespace *{namespace_name}* on " +"*{wiki_name}*{comment}" +msgstr "" +"[{author}]({author_url}) bearbeitete den Namensraum *{namespace_name}* für " +"*{wiki_name}*{comment}" + +#: extensions/base/managewiki.py:147 +#, python-brace-format +msgid "Deleted a \"{namespace_name}\" namespace" +msgstr "Löschte den Namensraum „{namespace_name}“" + +#: extensions/base/managewiki.py:158 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted a namespace *{namespace_name}* on " +"*{wiki_name}*{comment}" +msgstr "" +"[{author}]({author_url}) löschte den Namesraum *{namespace_name}* für " +"*{wiki_name}*{comment}" + +#: extensions/base/managewiki.py:173 +#, python-brace-format +msgid "Modified \"{usergroup_name}\" usergroup" +msgstr "Bearbeitete die Benutzergruppe „{usergroup_name}“" + +#: extensions/base/managewiki.py:182 +#, python-brace-format +msgid "[{author}]({author_url}) modified user group *{group_name}*{comment}" +msgstr "" +"[{author}]({author_url}) bearbeitete die Benutzergruppe *{group_name}" +"*{comment}" + +#: extensions/base/managewiki.py:195 +#, python-brace-format +msgid "Undeleted a \"{wiki}\" wiki" +msgstr "Stellte das Wiki „{wiki}“ wieder her" + +#: extensions/base/managewiki.py:203 +#, python-brace-format +msgid "[{author}]({author_url}) undeleted a wiki *{wiki_name}*{comment}" +msgstr "" +"[{author}]({author_url}) stellte das Wiki *{wiki_name}* wieder her{comment}" + +#: extensions/base/managewiki.py:217 +#, python-brace-format +msgid "Unlocked a \"{wiki}\" wiki" +msgstr "Entsperrte das Wiki „{wiki}“" + +#: extensions/base/managewiki.py:225 +#, python-brace-format +msgid "[{author}]({author_url}) unlocked a wiki *{wiki_name}*{comment}" +msgstr "[{author}]({author_url}) entsperrte das Wiki *{wiki_name}*{comment}" + +#: extensions/base/datadump.py:36 +#, python-brace-format +msgid "Generated {file} dump" +msgstr "Generierte {file} Dump" + +#: extensions/base/datadump.py:45 +#, python-brace-format +msgid "[{author}]({author_url}) generated *{file}* dump{comment}" +msgstr "[{author}]({author_url}) generierte *{file}* Dump{comment}" + +#: extensions/base/datadump.py:58 +#, python-brace-format +msgid "Deleted {file} dump" +msgstr "Löschte {file} Dump" + +#: extensions/base/datadump.py:67 +#, python-brace-format +msgid "[{author}]({author_url}) deleted *{file}* dump{comment}" +msgstr "[{author}]({author_url}) löschte *{file}* Dump{comment}" + +#: extensions/base/curseprofile.py:40 +#, python-brace-format +msgid "Edited {target}'s profile" +msgstr "Bearbeitete das Profil von {target}" + +#: extensions/base/curseprofile.py:42 +msgid "Edited their own profile" +msgstr "Bearbeitete das eigene Profil" + +#: extensions/base/curseprofile.py:44 +#, python-brace-format +msgid "Cleared the {field} field" +msgstr "Entfernte den {field}" + +#: extensions/base/curseprofile.py:46 +#, python-brace-format +msgid "{field} field changed to: {desc}" +msgstr "{field} geändert zu: {desc}" + +#: extensions/base/curseprofile.py:58 +#, python-brace-format +msgid "" +"[{author}]({author_url}) cleared the {field} on [{target}]({target_url})'s " +"profile." +msgstr "" +"[{author}]({author_url}) leerte den {field} auf dem Profil von [{target}]" +"({target_url})." + +#: extensions/base/curseprofile.py:60 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited the {field} on [{target}]({target_url})'s " +"profile. *({desc})*" +msgstr "" +"[{author}]({author_url}) bearbeitete den {field} auf dem Profil von " +"[{target}]({target_url}). *({desc})*" + +#: extensions/base/curseprofile.py:65 +#, python-brace-format +msgid "" +"[{author}]({author_url}) cleared the {field} on [their own]({target_url}) " +"profile." +msgstr "" +"[{author}]({author_url}) leerte den {field} auf dem [eigenen Profil]" +"({target_url})." + +#: extensions/base/curseprofile.py:67 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited the {field} on [their own]({target_url}) " +"profile. *({desc})*" +msgstr "" +"[{author}]({author_url}) bearbeitete den {field} auf dem [eigenen Profil]" +"({target_url}). *({desc})*" + +#: extensions/base/curseprofile.py:82 +#, python-brace-format +msgid "Left a comment on {target}'s profile" +msgstr "Hinterließ ein Kommentar auf dem Profil von {target}" + +#: extensions/base/curseprofile.py:84 +msgid "Left a comment on their own profile" +msgstr "Hinterließ ein Kommentar auf dem eigenen Profil" + +#: extensions/base/curseprofile.py:97 +#, python-brace-format +msgid "" +"[{author}]({author_url}) left a [comment]({comment}) on {target}'s profile." +msgstr "" +"[{author}]({author_url}) hinterließ einen [Kommentar]({comment}) auf dem " +"Profil von {target}." + +#: extensions/base/curseprofile.py:100 +#, python-brace-format +msgid "" +"[{author}]({author_url}) left a [comment]({comment}) on their own profile." +msgstr "" +"[{author}]({author_url}) hinterließ einen [Kommentar]({comment}) auf dem " +"eigenen Profil." + +#: extensions/base/curseprofile.py:113 +#, python-brace-format +msgid "Edited a comment on {target}'s profile" +msgstr "Bearbeitete ein Kommentar auf dem Profil von {target}" + +#: extensions/base/curseprofile.py:115 +msgid "Edited a comment on their own profile" +msgstr "Bearbeitete ein Kommentar auf dem eigenen Profil" + +#: extensions/base/curseprofile.py:128 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited a [comment]({comment}) on {target}'s profile." +msgstr "" +"[{author}]({author_url}) bearbeitete einen [Kommentar]({comment}) auf dem " +"Profil von {target}." + +#: extensions/base/curseprofile.py:131 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited a [comment]({comment}) on their own profile." +msgstr "" +"[{author}]({author_url}) bearbeitete einen [Kommentar]({comment}) auf dem " +"eigenen Profil." + +#: extensions/base/curseprofile.py:144 +#, python-brace-format +msgid "Replied to a comment on {target}'s profile" +msgstr "Antwortete auf ein Kommentar auf dem Profil von {target}" + +#: extensions/base/curseprofile.py:146 +msgid "Replied to a comment on their own profile" +msgstr "Antwortete auf ein Kommentar auf dem eigenen Profil" + +#: extensions/base/curseprofile.py:159 +#, python-brace-format +msgid "" +"[{author}]({author_url}) replied to a [comment]({comment}) on {target}'s " +"profile." +msgstr "" +"[{author}]({author_url}) antwortete auf einen [Kommentar]({comment}) auf dem " +"Profil von {target}." + +#: extensions/base/curseprofile.py:162 +#, python-brace-format +msgid "" +"[{author}]({author_url}) replied to a [comment]({comment}) on their own " +"profile." +msgstr "" +"[{author}]({author_url}) antwortete auf einen [Kommentar]({comment}) auf dem " +"eigenen Profil." + +#: extensions/base/curseprofile.py:175 +#, python-brace-format +msgid "Deleted a comment on {target}'s profile" +msgstr "Löschte ein Kommentar auf dem Profil von {target}" + +#: extensions/base/curseprofile.py:177 +msgid "Deleted a comment on their own profile" +msgstr "Löschte ein Kommentar auf dem eigenen Profil" + +#: extensions/base/curseprofile.py:197 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted a [comment]({comment}) on {target}'s " +"profile.{reason}" +msgstr "" +"[{author}]({author_url}) löschte einen [Kommentar]({comment}) auf dem Profil " +"von {target}.{reason}" + +#: extensions/base/curseprofile.py:200 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted a [comment]({comment}) on their own profile." +"{reason}" +msgstr "" +"[{author}]({author_url}) löschte einen [Kommentar]({comment}) auf dem " +"eigenen Profil.{reason}" + +#: extensions/base/curseprofile.py:214 +#, python-brace-format +msgid "Purged a comment on {target}'s profile" +msgstr "Löschte ein Kommentar auf dem Profil von {target} dauerhaft" + +#: extensions/base/curseprofile.py:216 +msgid "Purged a comment on their own profile" +msgstr "Löschte ein Kommentar auf dem eigenen Profil dauerhaft" + +#: extensions/base/curseprofile.py:230 +#, python-brace-format +msgid "" +"[{author}]({author_url}) purged a comment on [{target}]({link})'s profile." +"{reason}" +msgstr "" +"[{author}]({author_url}) löschte einen Kommentar auf dem Profil von " +"[{target}]({link}) dauerhaft.{reason}" + +#: extensions/base/curseprofile.py:233 +#, python-brace-format +msgid "" +"[{author}]({author_url}) purged a comment on [their own]({link}) profile." +"{reason}" +msgstr "" +"[{author}]({author_url}) löschte einen Kommentar auf dem [eigenen]({link}) " +"Profil dauerhaft.{reason}" + +#: extensions/base/renameuser.py:38 +#, python-brace-format +msgid "Renamed user \"{old_name}\" with {edits} edit to \"{new_name}\"" +msgid_plural "Renamed user \"{old_name}\" with {edits} edits to \"{new_name}\"" +msgstr[0] "" +"Nannte den Benutzer „{old_name}“ mit einer Bearbeitung zu „{new_name}“ um" +msgstr[1] "" +"Nannte den Benutzer „{old_name}“ mit {edits} Bearbeitungen zu „{new_name}“ um" + +#: extensions/base/renameuser.py:43 +#, python-brace-format +msgid "Renamed user \"{old_name}\" to \"{new_name}\"" +msgstr "Nannte den Benutzer „{old_name}“ zu „{new_name}“ um" + +#: extensions/base/renameuser.py:58 +#, python-brace-format +msgid "" +"[{author}]({author_url}) renamed user *{old_name}* with {edits} edit to " +"[{new_name}]({link}){comment}" +msgid_plural "" +"[{author}]({author_url}) renamed user *{old_name}* with {edits} edits to " +"[{new_name}]({link}){comment}" +msgstr[0] "" +"[{author}]({author_url}) hat den Benutzer *{old_name}* mit einer Bearbeitung " +"zu [{new_name}]({link}) umbenannt{comment}" +msgstr[1] "" +"[{author}]({author_url}) hat den Benutzer *{old_name}* mit {edits} " +"Bearbeitungen zu [{new_name}]({link}) umbenannt{comment}" + +#: extensions/base/renameuser.py:66 +#, python-brace-format +msgid "" +"[{author}]({author_url}) renamed user *{old_name}* to [{new_name}]({link})" +"{comment}" +msgstr "" +"[{author}]({author_url}) hat den Benutzer *{old_name}* zu [{new_name}]" +"({link}) umbenannt{comment}" + +#: extensions/base/interwiki.py:37 +msgid "Added an entry to the interwiki table" +msgstr "Fügte ein Interwiki-Präfix hinzu" + +#: extensions/base/interwiki.py:38 extensions/base/interwiki.py:65 +#, python-brace-format +msgid "Prefix: {prefix}, website: {website} | {desc}" +msgstr "Präfix: {prefix}, URL: {website} | {desc}" + +#: extensions/base/interwiki.py:50 +#, python-brace-format +msgid "" +"[{author}]({author_url}) added an entry to the [interwiki table]" +"({table_url}) pointing to {website} with {prefix} prefix" +msgstr "" +"[{author}]({author_url}) erstellte den [Interwiki-Präfix]({table_url}) " +"{prefix} nach {website}" + +#: extensions/base/interwiki.py:64 +msgid "Edited an entry in interwiki table" +msgstr "Änderte ein Interwiki-Präfix" + +#: extensions/base/interwiki.py:77 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited an entry in [interwiki table]({table_url}) " +"pointing to {website} with {prefix} prefix" +msgstr "" +"[{author}]({author_url}) bearbeitete den [Interwiki-Präfix]({table_url}) " +"{prefix} nach {website}" + +#: extensions/base/interwiki.py:91 +msgid "Deleted an entry in interwiki table" +msgstr "Entfernte ein Interwiki-Präfix" + +#: extensions/base/interwiki.py:92 +#, python-brace-format +msgid "Prefix: {prefix} | {desc}" +msgstr "Präfix: {prefix} | {desc}" + +#: extensions/base/interwiki.py:102 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted an entry in [interwiki table]({table_url})" +"{desc}" +msgstr "" +"[{author}]({author_url}) entfernte ein [Interwiki-Präfix]({table_url}){desc}" + +#: extensions/base/abusefilter.py:29 +msgid "None" +msgstr "Keine" + +#: extensions/base/abusefilter.py:29 +msgid "Warning issued" +msgstr "Gewarnt" + +#: extensions/base/abusefilter.py:29 +msgid "**Blocked user**" +msgstr "**Benutzer gesperrt**" + +#: extensions/base/abusefilter.py:29 +msgid "Tagged the edit" +msgstr "Änderung markiert" + +#: extensions/base/abusefilter.py:29 +msgid "Disallowed the action" +msgstr "Aktion verhindert" + +#: extensions/base/abusefilter.py:29 +msgid "**IP range blocked**" +msgstr "**IP-Adressbereich gesperrt**" + +#: extensions/base/abusefilter.py:29 +msgid "Throttled actions" +msgstr "Aktionen gedrosselt" + +#: extensions/base/abusefilter.py:29 +msgid "Removed autoconfirmed group" +msgstr "„Automatisch bestätigter Benutzer“-Status entzogen" + +#: extensions/base/abusefilter.py:29 +msgid "**Removed from privileged groups**" +msgstr "**Gruppen mit Sonderrechten entfernt**" + +#: extensions/base/abusefilter.py:30 +msgid "Edit" +msgstr "Bearbeitung" + +#: extensions/base/abusefilter.py:30 +msgid "Upload" +msgstr "Hochladen" + +#: extensions/base/abusefilter.py:30 +msgid "Move" +msgstr "Verschieben" + +#: extensions/base/abusefilter.py:30 +msgid "Stash upload" +msgstr "Hochladen vom Zwischenspeicher" + +#: extensions/base/abusefilter.py:30 +msgid "Deletion" +msgstr "Löschung" + +#: extensions/base/abusefilter.py:30 +msgid "Account creation" +msgstr "Benutzerkontenerstellung" + +#: extensions/base/abusefilter.py:30 +msgid "Auto account creation" +msgstr "Automatische Benutzerkontenerstellung" + +#: extensions/base/abusefilter.py:54 +#, python-brace-format +msgid "{user} triggered \"{abuse_filter}\"" +msgstr "{user} löste „{abuse_filter}“ aus" + +#: extensions/base/abusefilter.py:55 +msgid "Performed" +msgstr "Aktion" + +#: extensions/base/abusefilter.py:56 +msgid "Action taken" +msgstr "Maßnahmen" + +#: extensions/base/abusefilter.py:57 +msgid "Title" +msgstr "Seite" + +#: extensions/base/abusefilter.py:66 +#, python-brace-format +msgid "" +"[{author}]({author_url}) triggered *{abuse_filter}*, performing the action " +"\"{action}\" on *[{target}]({target_url})* - action taken: {result}." +msgstr "" +"[{author}]({author_url}) löste durch die Aktion „{action}“ auf der Seite " +"*[{target}]({target_url})* den Filter *{abuse_filter}* aus. Ergriffene " +"Maßnahmen: {result}." + +#: extensions/base/abusefilter.py:83 +#, python-brace-format +msgid "Edited abuse filter number {number}" +msgstr "Änderte Missbrauchsfilter {number}" + +#: extensions/base/abusefilter.py:95 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited abuse filter [number {number}]({filter_url})" +msgstr "" +"[{author}]({author_url}) änderte [Missbrauchsfilter {number}]({filter_url})" + +#: extensions/base/abusefilter.py:111 +#, python-brace-format +msgid "Created abuse filter number {number}" +msgstr "Erstellte Missbrauchsfilter {number}" + +#: extensions/base/abusefilter.py:119 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created abuse filter [number {number}]({filter_url})" +msgstr "" +"[{author}]({author_url}) erstellte [Missbrauchsfilter {number}]({filter_url})" + +#: extensions/base/mediawiki.py:37 +msgid "director" +msgstr "Direktor" + +#: extensions/base/mediawiki.py:37 +msgid "bot" +msgstr "Bot" + +#: extensions/base/mediawiki.py:37 +msgid "editor" +msgstr "editor" + +#: extensions/base/mediawiki.py:37 +msgid "directors" +msgstr "Direktor" + +#: extensions/base/mediawiki.py:37 +msgid "sysop" +msgstr "Administrator" + +#: extensions/base/mediawiki.py:37 +msgid "bureaucrat" +msgstr "Bürokrat" + +#: extensions/base/mediawiki.py:37 +msgid "reviewer" +msgstr "Prüfer" + +#: extensions/base/mediawiki.py:38 +msgid "autoreview" +msgstr "Passive Sichter" + +#: extensions/base/mediawiki.py:38 +msgid "autopatrol" +msgstr "Automatisch kontrolliert" + +#: extensions/base/mediawiki.py:38 +msgid "wiki_guardian" +msgstr "Wiki Guardian" + +#: extensions/base/mediawiki.py:70 +msgid "(N!) " +msgstr "(N!) " + +#: extensions/base/mediawiki.py:71 +msgid "m" +msgstr "K" + +#: extensions/base/mediawiki.py:72 +msgid "b" +msgstr "B" + +#: extensions/base/mediawiki.py:112 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited [{article}]({edit_link}){comment} {bold}" +"({sign}{edit_size}){bold}" +msgstr "" +"[{author}]({author_url}) bearbeitete [{article}]({edit_link}){comment} {bold}" +"({sign}{edit_size}){bold}" + +#: extensions/base/mediawiki.py:117 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created [{article}]({edit_link}){comment} {bold}" +"({sign}{edit_size}){bold}" +msgstr "" +"[{author}]({author_url}) erstellte [{article}]({edit_link}){comment} {bold}" +"({sign}{edit_size}){bold}" + +#: extensions/base/mediawiki.py:190 extensions/base/mediawiki.py:223 +msgid "Options" +msgstr "Optionen" + +#: extensions/base/mediawiki.py:190 +#, python-brace-format +msgid "([preview]({link}) | [undo]({undolink}))" +msgstr "([Vorschau]({link}) | [zurücksetzen]({undolink}))" + +#: extensions/base/mediawiki.py:195 +#, python-brace-format +msgid "Uploaded a new version of {name}" +msgstr "Neue Dateiversion {name}" + +#: extensions/base/mediawiki.py:197 +#, python-brace-format +msgid "Reverted a version of {name}" +msgstr "Setzte {name} auf eine alte Version zurück" + +#: extensions/base/mediawiki.py:199 +#, python-brace-format +msgid "Uploaded {name}" +msgstr "Neue Datei {name}" + +#: extensions/base/mediawiki.py:208 +msgid "**No license!**" +msgstr "**Keine Lizenz!**" + +#: extensions/base/mediawiki.py:223 +#, python-brace-format +msgid "([preview]({link}))" +msgstr "([Vorschau]({link}))" + +#: extensions/base/mediawiki.py:228 +msgid "" +"\n" +"License: {}" +msgstr "" +"\n" +"Lizenz: {}" + +#: extensions/base/mediawiki.py:237 +#, python-brace-format +msgid "" +"[{author}]({author_url}) reverted a version of [{file}]({file_link}){comment}" +msgstr "" +"[{author}]({author_url}) setzte [{file}]({file_link}) auf eine alte Version " +"zurück{comment}" + +#: extensions/base/mediawiki.py:248 +#, python-brace-format +msgid "" +"[{author}]({author_url}) uploaded a new version of [{file}]({file_link})" +"{comment}" +msgstr "" +"[{author}]({author_url}) lud eine neue Version von [{file}]({file_link}) " +"hoch{comment}" + +#: extensions/base/mediawiki.py:259 +#, python-brace-format +msgid "[{author}]({author_url}) uploaded [{file}]({file_link}){comment}" +msgstr "[{author}]({author_url}) lud [{file}]({file_link}) hoch{comment}" + +#: extensions/base/mediawiki.py:274 +#, python-brace-format +msgid "Deleted page {article}" +msgstr "Löschte {article}" + +#: extensions/base/mediawiki.py:283 +#, python-brace-format +msgid "[{author}]({author_url}) deleted [{page}]({page_link}){comment}" +msgstr "[{author}]({author_url}) löschte [{page}]({page_link}){comment}" + +#: extensions/base/mediawiki.py:298 +#, python-brace-format +msgid "Deleted redirect {article} by overwriting" +msgstr "Löschte die Weiterleitung {article} um Platz zu machen" + +#: extensions/base/mediawiki.py:308 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted redirect by overwriting [{page}]" +"({page_link}){comment}" +msgstr "" +"[{author}]({author_url}) löschte die Weiterleitung [{page}]({page_link}) " +"durch Überschreiben{comment}" + +#: extensions/base/mediawiki.py:322 +#, python-brace-format +msgid "Restored {article}" +msgstr "Stellte {article} wieder her" + +#: extensions/base/mediawiki.py:331 +#, python-brace-format +msgid "[{author}]({author_url}) restored [{article}]({article_url}){comment}" +msgstr "" +"[{author}]({author_url}) stellte [{article}]({article_url}) wieder " +"her{comment}" + +#: extensions/base/mediawiki.py:348 +msgid "Changed visibility of log events" +msgstr "Änderte die Sichtbarkeit eines Logbucheintrags" + +#: extensions/base/mediawiki.py:356 +#, python-brace-format +msgid "[{author}]({author_url}) changed visibility of log events{comment}" +msgstr "" +"[{author}]({author_url}) änderte die Sichtbarkeit eines " +"Logbucheintrags{comment}" + +#: extensions/base/mediawiki.py:370 +#, python-brace-format +msgid "Changed visibility of revision on page {article} " +msgid_plural "Changed visibility of {amount} revisions on page {article} " +msgstr[0] "Änderte die Sichtbarkeit einer Versionen von {article} " +msgstr[1] "Änderte die Sichtbarkeit von {amount} Versionen von {article} " + +#: extensions/base/mediawiki.py:383 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed visibility of revision on page [{article}]" +"({article_url}){comment}" +msgid_plural "" +"[{author}]({author_url}) changed visibility of {amount} revisions on page " +"[{article}]({article_url}){comment}" +msgstr[0] "" +"[{author}]({author_url}) änderte die Sichtbarkeit einer Version von " +"[{article}]({article_url}){comment}" +msgstr[1] "" +"[{author}]({author_url}) änderte die Sichtbarkeit von {amount} Versionen von " +"[{article}]({article_url}){comment}" + +#: extensions/base/mediawiki.py:399 extensions/base/mediawiki.py:432 +msgid "No redirect has been made" +msgstr "Die Erstellung einer Weiterleitung wurde unterdrückt" + +#: extensions/base/mediawiki.py:400 extensions/base/mediawiki.py:433 +msgid "A redirect has been made" +msgstr "Eine Weiterleitung wurde erstellt" + +#: extensions/base/mediawiki.py:401 +#, python-brace-format +msgid "Moved {redirect}{article} to {target}" +msgstr "Verschob {redirect}{article} nach {target}" + +#: extensions/base/mediawiki.py:412 extensions/base/mediawiki.py:444 +msgid "without making a redirect" +msgstr "ohne eine Weiterleitung zu erstellen" + +#: extensions/base/mediawiki.py:413 extensions/base/mediawiki.py:445 +msgid "with a redirect" +msgstr "und erstellte eine Weiterleitung" + +#: extensions/base/mediawiki.py:416 +#, python-brace-format +msgid "" +"[{author}]({author_url}) moved {redirect}*{article}* to [{target}]" +"({target_url}) {made_a_redirect}{comment}" +msgstr "" +"[{author}]({author_url}) verschob {redirect}*{article}* nach [{target}]" +"({target_url}) {made_a_redirect}{comment}" + +#: extensions/base/mediawiki.py:434 +#, python-brace-format +msgid "Moved {redirect}{article} to {title} over redirect" +msgstr "" +"Verschob {redirect}{article} nach {title} und überschrieb eine Weiterleitung" + +#: extensions/base/mediawiki.py:448 +#, python-brace-format +msgid "" +"[{author}]({author_url}) moved {redirect}*{article}* over redirect to " +"[{target}]({target_url}) {made_a_redirect}{comment}" +msgstr "" +"[{author}]({author_url}) verschob {redirect}*{article}* nach [{target}]" +"({target_url}) und überschrieb eine Weiterleitung {made_a_redirect}{comment}" + +#: extensions/base/mediawiki.py:464 +#, python-brace-format +msgid "Moved protection settings from {redirect}{article} to {title}" +msgstr "Verschob die Schutzeinstellungen von {redirect}{article} nach {title}" + +#: extensions/base/mediawiki.py:477 +#, python-brace-format +msgid "" +"[{author}]({author_url}) moved protection settings from {redirect}*{article}" +"* to [{target}]({target_url}){comment}" +msgstr "" +"[{author}]({author_url}) verschob die Schutzeinstellungen von {redirect}" +"*{article}* nach [{target}]({target_url}){comment}" + +#: extensions/base/mediawiki.py:492 +#, python-brace-format +msgid "Protected {target}" +msgstr "Schützte {target}" + +#: extensions/base/mediawiki.py:495 extensions/base/mediawiki.py:510 +#: extensions/base/mediawiki.py:526 extensions/base/mediawiki.py:541 +msgid " [cascading]" +msgstr " [kaskadierend]" + +#: extensions/base/mediawiki.py:506 +#, python-brace-format +msgid "" +"[{author}]({author_url}) protected [{article}]({article_url}) with the " +"following settings: {settings}{comment}" +msgstr "" +"[{author}]({author_url}) schützte [{article}]({article_url}) {settings}" +"{comment}" + +#: extensions/base/mediawiki.py:523 +#, python-brace-format +msgid "Changed protection level for {article}" +msgstr "Änderte den Schutzstatus von {article}" + +#: extensions/base/mediawiki.py:537 +#, python-brace-format +msgid "" +"[{author}]({author_url}) modified protection settings of [{article}]" +"({article_url}) to: {settings}{comment}" +msgstr "" +"[{author}]({author_url}) änderte den Schutzstatus von [{article}]" +"({article_url}) {settings}{comment}" + +#: extensions/base/mediawiki.py:554 +#, python-brace-format +msgid "Removed protection from {article}" +msgstr "Entfernte den Schutz von {article}" + +#: extensions/base/mediawiki.py:563 +#, python-brace-format +msgid "" +"[{author}]({author_url}) removed protection from [{article}]({article_url})" +"{comment}" +msgstr "" +"[{author}]({author_url}) entfernte den Schutz von [{article}]({article_url})" +"{comment}" + +#: extensions/base/mediawiki.py:572 +msgid "for infinity and beyond" +msgstr "für alle Ewigkeit" + +#: extensions/base/mediawiki.py:581 +msgid "for less than a minute" +msgstr "für weniger als eine Minute" + +#: extensions/base/mediawiki.py:583 +msgid "year" +msgid_plural "years" +msgstr[0] "Jahr" +msgstr[1] "Jahre" + +#: extensions/base/mediawiki.py:583 +msgid "day" +msgid_plural "days" +msgstr[0] "Tag" +msgstr[1] "Tage" + +#: extensions/base/mediawiki.py:583 +msgid "hour" +msgid_plural "hours" +msgstr[0] "Stunde" +msgstr[1] "Stunden" + +#: extensions/base/mediawiki.py:584 +msgid "minute" +msgid_plural "minutes" +msgstr[0] "Minute" +msgstr[1] "Minuten" + +#: extensions/base/mediawiki.py:589 +#, python-brace-format +msgid "for {time_number} {time_unit}" +msgstr "für {time_number} {time_unit}" + +#: extensions/base/mediawiki.py:608 +msgid "Blocked from editing the following pages: " +msgstr "Bearbeiten von folgenden Seiten gesperrt: " + +#: extensions/base/mediawiki.py:615 extensions/base/mediawiki.py:661 +msgid " and namespaces: " +msgstr " und Namensräumen: " + +#: extensions/base/mediawiki.py:617 +msgid "Blocked from editing pages on following namespaces: " +msgstr "Bearbeiten von Seiten in folgenden Namensräumen gesperrt: " + +#: extensions/base/mediawiki.py:628 +msgid "Partial block details" +msgstr "Teilweise Sperre" + +#: extensions/base/mediawiki.py:631 +msgid "Block flags" +msgstr "Sperroptionen" + +#: extensions/base/mediawiki.py:633 +#, python-brace-format +msgid "Blocked {blocked_user} {time}" +msgstr "Sperrte {blocked_user} {time}" + +#: extensions/base/mediawiki.py:653 +msgid " on pages: " +msgstr " auf Seiten: " + +#: extensions/base/mediawiki.py:663 +msgid " on namespaces: " +msgstr " in Namensräumen: " + +#: extensions/base/mediawiki.py:675 +#, python-brace-format +msgid "" +"[{author}]({author_url}) blocked [{user}]({user_url}) {time}" +"{restriction_desc}{comment}" +msgstr "" +"[{author}]({author_url}) sperrte [{user}]({user_url}) {time}" +"{restriction_desc}{comment}" + +#: extensions/base/mediawiki.py:693 +#, python-brace-format +msgid "Changed block settings for {blocked_user}" +msgstr "Änderte die Sperreinstellungen für {blocked_user}" + +#: extensions/base/mediawiki.py:703 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed block settings for [{blocked_user}]" +"({user_url}){comment}" +msgstr "" +"[{author}]({author_url}) änderte die Sperreinstellungen für [{blocked_user}]" +"({user_url}){comment}" + +#: extensions/base/mediawiki.py:716 +#, python-brace-format +msgid "Unblocked {blocked_user}" +msgstr "Hob die Sperre von {blocked_user} auf" + +#: extensions/base/mediawiki.py:726 +#, python-brace-format +msgid "" +"[{author}]({author_url}) unblocked [{blocked_user}]({user_url}){comment}" +msgstr "" +"[{author}]({author_url}) hob die Sperre von [{blocked_user}]({user_url}) " +"auf{comment}" + +#: extensions/base/mediawiki.py:742 +msgid "Action has been hidden by administration" +msgstr "Aktion wurde versteckt" + +#: extensions/base/mediawiki.py:749 +msgid "An action has been hidden by administration." +msgstr "Eine Aktion wurde versteckt." + +#: extensions/base/mediawiki.py:760 +#, python-brace-format +msgid "Imported {article} with {count} revision" +msgid_plural "Imported {article} with {count} revisions" +msgstr[0] "Importierte {article} mit einer Version" +msgstr[1] "Importierte {article} mit {count} Versionen" + +#: extensions/base/mediawiki.py:771 +#, python-brace-format +msgid "" +"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " +"revision{comment}" +msgid_plural "" +"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " +"revisions{comment}" +msgstr[0] "" +"[{author}]({author_url}) importierte [{article}]({article_url}) mit einer " +"Version{comment}" +msgstr[1] "" +"[{author}]({author_url}) importierte [{article}]({article_url}) mit {count} " +"Versionen{comment}" + +#: extensions/base/mediawiki.py:787 +#, python-brace-format +msgid "Imported {article} with {count} revision from \"{source}\"" +msgid_plural "Imported {article} with {count} revisions from \"{source}\"" +msgstr[0] "Importierte {article} mit einer Version von „{source}“" +msgstr[1] "Importierte {article} mit {count} Versionen von „{source}“" + +#: extensions/base/mediawiki.py:802 +#, python-brace-format +msgid "" +"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " +"revision from [{source}]({source_url}){comment}" +msgid_plural "" +"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " +"revisions from [{source}]({source_url}){comment}" +msgstr[0] "" +"[{author}]({author_url}) importierte [{article}]({article_url}) mit einer " +"Version von [{source}]({source_url}){comment}" +msgstr[1] "" +"[{author}]({author_url}) importierte [{article}]({article_url}) mit {count} " +"Versionen von [{source}]({source_url}){comment}" + +#: extensions/base/mediawiki.py:817 +#, python-brace-format +msgid " (until {date_and_time})" +msgstr " (bis {date_and_time})" + +#: extensions/base/mediawiki.py:834 +#, python-brace-format +msgid "Changed group membership for {target}" +msgstr "Änderte die Gruppenzugehörigkeit von {target}" + +#: extensions/base/mediawiki.py:836 +msgid "System" +msgstr "System" + +#: extensions/base/mediawiki.py:837 +#, python-brace-format +msgid "{target} got autopromoted to a new usergroup" +msgstr "{target} wurde automatisch einer neuen Benutzergruppe zugeordnet" + +#: extensions/base/mediawiki.py:843 +msgid "Added group" +msgid_plural "Added groups" +msgstr[0] "Hinzugefügte Gruppe" +msgstr[1] "Hinzugefügte Gruppen" + +#: extensions/base/mediawiki.py:845 +msgid "Removed group" +msgid_plural "Removed groups" +msgstr[0] "Entfernte Gruppe" +msgstr[1] "Entfernte Gruppen" + +#: extensions/base/mediawiki.py:859 +#, python-brace-format +msgid "Added to {added} and removed from {removed}." +msgstr "Hinzugefügt zu {added} und entfernt von {removed}." + +#: extensions/base/mediawiki.py:860 extensions/base/mediawiki.py:862 +#: extensions/base/mediawiki.py:864 extensions/base/mediawiki.py:871 +msgid ", " +msgstr ", " + +#: extensions/base/mediawiki.py:862 +#, python-brace-format +msgid "Added to {added}." +msgstr "Hinzugefügt zu {added}." + +#: extensions/base/mediawiki.py:864 +#, python-brace-format +msgid "Removed from {removed}." +msgstr "Entfernt von {removed}." + +#: extensions/base/mediawiki.py:865 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed group membership for [{target}]" +"({target_url}): {group_changes}{comment}" +msgstr "" +"[{author}]({author_url}) änderte die Benutzergruppen für [{target}]" +"({target_url}): {group_changes}{comment}" + +#: extensions/base/mediawiki.py:869 +#, python-brace-format +msgid "The system autopromoted [{target}]({target_url}) to {added}.{comment}" +msgstr "" +"[{target}]({target_url}) wurde automatisch zu {added} hinzugefügt.{comment}" + +#: extensions/base/mediawiki.py:882 +#, python-brace-format +msgid "Merged revision histories of {article} into {dest}" +msgstr "Vereinigte Versionen von {article} in {dest}" + +#: extensions/base/mediawiki.py:896 +#, python-brace-format +msgid "" +"[{author}]({author_url}) merged revision histories of [{article}]" +"({article_url}) into [{dest}]({dest_url}){comment}" +msgstr "" +"[{author}]({author_url}) vereinigte Versionen von [{article}]({article_url}) " +"in [{dest}]({dest_url}){comment}" + +#: extensions/base/mediawiki.py:910 +msgid "Created account automatically" +msgstr "Erstellte Konto automatisch" + +#: extensions/base/mediawiki.py:917 +#, python-brace-format +msgid "Account [{author}]({author_url}) was created automatically" +msgstr "Konto [{author}]({author_url}) wurde automtisch erstellt" + +#: extensions/base/mediawiki.py:930 extensions/base/mediawiki.py:995 +msgid "Created account" +msgstr "Erstellte Konto" + +#: extensions/base/mediawiki.py:937 extensions/base/mediawiki.py:1002 +#, python-brace-format +msgid "Account [{author}]({author_url}) was created" +msgstr "Konto [{author}]({author_url}) wurde erstellt" + +#: extensions/base/mediawiki.py:949 +#, python-brace-format +msgid "Created account {article}" +msgstr "Erstellte Konto {article}" + +#: extensions/base/mediawiki.py:958 +#, python-brace-format +msgid "" +"Account [{article}]({article_url}) was created by [{author}]({author_url})" +"{comment}" +msgstr "" +"Konto [{article}]({article_url}) wurde von [{author}]({author_url}) " +"erstellt{comment}" + +#: extensions/base/mediawiki.py:971 +#, python-brace-format +msgid "Created account {article} and password was sent by email" +msgstr "Erstellte Konto {article} und das Passwort wurde per E-Mail zugesandt" + +#: extensions/base/mediawiki.py:982 +#, python-brace-format +msgid "" +"Account [{article}]({article_url}) was created by [{author}]({author_url}) " +"and password was sent by email{comment}" +msgstr "" +"Konto [{article}]({article_url}) wurde von [{author}]({author_url}) erstellt " +"und das Passwort wurde per E-Mail zugesandt{comment}" + +#: extensions/base/mediawiki.py:1014 +#, python-brace-format +msgid "Changed the content model of the page {article}" +msgstr "Änderte das Inhaltsmodell von {article}" + +#: extensions/base/mediawiki.py:1016 +#, python-brace-format +msgid "Model changed from {old} to {new}: {reason}" +msgstr "Modell geändert von {old} zu {new}: {reason}" + +#: extensions/base/mediawiki.py:1028 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed the content model of the page [{article}]" +"({article_url}) from {old} to {new}{comment}" +msgstr "" +"[{author}]({author_url}) änderte das Inhaltsmodell der Seite [{article}]" +"({article_url}) von {old} zu {new}{comment}" + +#: extensions/base/mediawiki.py:1043 +#, python-brace-format +msgid "Created the page {article} using a non-default content model" +msgstr "Erstellte die Seite {article}mit einem nicht-standard Inhaltsmodell" + +#: extensions/base/mediawiki.py:1045 +#, python-brace-format +msgid "Created with model {new}: {reason}" +msgstr "Erstellt mit Modell {new}: {reason}" + +#: extensions/base/mediawiki.py:1056 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created the page [{article}]({article_url}) using a " +"non-default content model {new}{comment}" +msgstr "" +"[{author}]({author_url}) erstellte die Seite [{article}]({article_url}) mit " +"dem Inhaltsmodell {new}{comment}" + +#: extensions/base/mediawiki.py:1071 +#, python-brace-format +msgid "Created the tag \"{tag}\"" +msgstr "Erstellte die Markierung „{tag}“" + +#: extensions/base/mediawiki.py:1081 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created the [tag]({tag_url}) \"{tag}\"{comment}" +msgstr "" +"[{author}]({author_url}) erstellte eine [Markierung]({tag_url}) " +"„{tag}“{comment}" + +#: extensions/base/mediawiki.py:1102 +#, python-brace-format +msgid "Deleted the tag \"{tag}\"" +msgstr "Löschte die Markierung „{tag}“" + +#: extensions/base/mediawiki.py:1104 +msgid "Removed from" +msgstr "Entfernt von" + +#: extensions/base/mediawiki.py:1104 +msgid "{} revision or log entry" +msgid_plural "{} revisions and/or log entries" +msgstr[0] "{} Version oder Logbucheintrag" +msgstr[1] "{} Versionen und/oder Logbucheinträgen" + +#: extensions/base/mediawiki.py:1117 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\"{comment}" +msgstr "" +"[{author}]({author_url}) löschte eine [Markierung]({tag_url}) " +"„{tag}“{comment}" + +#: extensions/base/mediawiki.py:1127 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\" and removed " +"it from {count} revision or log entry{comment}" +msgid_plural "" +"[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\" and removed " +"it from {count} revisions and/or log entries{comment}" +msgstr[0] "" +"[{author}]({author_url}) löschte die [Markierung]({tag_url}) „{tag}“ und " +"entfernte diese von {count} Version oder Logbucheintrag{comment}" +msgstr[1] "" +"[{author}]({author_url}) löschte die [Markierung]({tag_url}) „{tag}“ und " +"entfernte diese von {count} Versionen und/oder Logbucheinträgen{comment}" + +#: extensions/base/mediawiki.py:1144 +#, python-brace-format +msgid "Activated the tag \"{tag}\"" +msgstr "Aktivierte die Markierung „{tag}“" + +#: extensions/base/mediawiki.py:1153 +#, python-brace-format +msgid "" +"[{author}]({author_url}) activated the [tag]({tag_url}) \"{tag}\"{comment}" +msgstr "" +"[{author}]({author_url}) aktivierte die [Markierung]({tag_url}) " +"„{tag}“{comment}" + +#: extensions/base/mediawiki.py:1172 +#, python-brace-format +msgid "Deactivated the tag \"{tag}\"" +msgstr "Deaktivierte die Markierung „{tag}“" + +#: extensions/base/mediawiki.py:1181 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deactivated the [tag]({tag_url}) \"{tag}\"{comment}" +msgstr "" +"[{author}]({author_url}) deaktivierte die [Markierung]({tag_url}) " +"„{tag}“{comment}" + +#: extensions/base/sprite.py:37 +#, python-brace-format +msgid "Edited the sprite for {article}" +msgstr "Änderte das Sprite für {article}" + +#: extensions/base/sprite.py:45 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited the sprite for [{article}]({article_url})" +msgstr "" +"[{author}]({author_url}) änderte das Sprite für [{article}]({article_url})" + +#: extensions/base/sprite.py:60 +#, python-brace-format +msgid "Created the sprite sheet for {article}" +msgstr "Erstellte das Sprite-sheet für {article}" + +#: extensions/base/sprite.py:68 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created the sprite sheet for [{article}]" +"({article_url})" +msgstr "" +"[{author}]({author_url}) erstellte das Sprite-sheet für [{article}]" +"({article_url})" + +#: extensions/base/sprite.py:79 +#, python-brace-format +msgid "Edited the slice for {article}" +msgstr "Änderte das Stück für {article}" + +#: extensions/base/sprite.py:86 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited the slice for [{article}]({article_url})" +msgstr "" +"[{author}]({author_url}) änderte das Stück für [{article}]({article_url})" + +#, python-brace-format +#~ msgid "" +#~ "{reason}\n" +#~ "{added}{linebreak}{removed}" +#~ msgstr "" +#~ "{reason}\n" +#~ "{added}{linebreak}{removed}" + +#, python-brace-format +#~ msgid "{value} (avg. {avg})" +#~ msgstr "{value} (vgl. {avg})" + +#~ msgid "Daily overview" +#~ msgstr "Tägliche Übersicht" + +#~ msgid "No activity" +#~ msgstr "Keine Aktivität" + +#~ msgid " ({} action)" +#~ msgid_plural " ({} actions)" +#~ msgstr[0] " (eine Aktion)" +#~ msgstr[1] " ({} Aktionen)" + +#~ msgid " ({} edit)" +#~ msgid_plural " ({} edits)" +#~ msgstr[0] " (eine Änderung)" +#~ msgstr[1] " ({} Änderungen)" + +#~ msgid " UTC ({} action)" +#~ msgid_plural " UTC ({} actions)" +#~ msgstr[0] " UTC (eine Aktion)" +#~ msgstr[1] " UTC ({} Aktionen)" + +#~ msgid "But nobody came" +#~ msgstr "Keine Aktivität" + +#~ msgid "Most active user" +#~ msgid_plural "Most active users" +#~ msgstr[0] "Aktivster Benutzer" +#~ msgstr[1] "Aktivste Benutzer" + +#~ msgid "Most edited article" +#~ msgid_plural "Most edited articles" +#~ msgstr[0] "Meist bearbeiteter Artikel" +#~ msgstr[1] "Meist bearbeitete Artikel" + +#~ msgid "Edits made" +#~ msgstr "Bearbeitungen" + +#~ msgid "New files" +#~ msgstr "Neue Dateien" + +#~ msgid "Admin actions" +#~ msgstr "Admin-Aktionen" + +#~ msgid "Bytes changed" +#~ msgstr "Bytes geändert" + +#~ msgid "New articles" +#~ msgstr "Neue Artikel" + +#~ msgid "Unique contributors" +#~ msgstr "Einzelne Autoren" + +#~ msgid "Most active hour" +#~ msgid_plural "Most active hours" +#~ msgstr[0] "Aktivste Stunde" +#~ msgstr[1] "Aktivste Stunden" + +#~ msgid "Day score" +#~ msgstr "Tageswert" + +#~ msgid "No description provided" +#~ msgstr "Keine Zusammenfassung angegeben" + +#~ msgid "second" +#~ msgid_plural "seconds" +#~ msgstr[0] "Sekunde" +#~ msgstr[1] "Sekunden" + +#~ msgid "week" +#~ msgid_plural "weeks" +#~ msgstr[0] "Woche" +#~ msgstr[1] "Wochen" + +#~ msgid "month" +#~ msgid_plural "months" +#~ msgstr[0] "Monat" +#~ msgstr[1] "Monate" + +#~ msgid "millennium" +#~ msgid_plural "millennia" +#~ msgstr[0] "Jahrtausend" +#~ msgstr[1] "Jahrtausende" + +#~ msgid "decade" +#~ msgid_plural "decades" +#~ msgstr[0] "Jahrzehnt" +#~ msgstr[1] "Jahrzehnte" + +#~ msgid "century" +#~ msgid_plural "centuries" +#~ msgstr[0] "Jahrhundert" +#~ msgstr[1] "Jahrhunderte" + +#, python-brace-format +#~ msgid "" +#~ "Unknown event `{event}` by [{author}]({author_url}), report it on the " +#~ "[support server](<{support}>)." +#~ msgstr "" +#~ "Unbekanntes Event `{event}` von [{author}]({author_url}), melde es auf " +#~ "dem [Support-Server](<{support}>)." + +#, python-brace-format +#~ msgid "Unknown event `{event}`" +#~ msgstr "Unbekanntes Event `{event}`" + +#~ msgid "Report this on the support server" +#~ msgstr "Melde es auf dem Support-Server" + +#, python-brace-format +#~ msgid "for {num} {translated_length}" +#~ msgstr "für {num} {translated_length}" + +#~ msgid "until {}" +#~ msgstr "bis {}" + +#~ msgid "none" +#~ msgstr "keine" + +#, python-brace-format +#~ msgid "" +#~ "[{author}]({author_url}) completed deletion of translatable page " +#~ "[{article}]({article_url}){comment}" +#~ msgstr "" +#~ "[{author}]({author_url}) schloss die Löschung der übersetzbaren Seite " +#~ "[{article}]({article_url}) ab{comment}" + +#~ msgid "unknown expiry time" +#~ msgstr "unbekannte Ablaufdauer" + +#, python-brace-format +#~ msgid "Groups changed from {old_groups} to {new_groups}{reason}" +#~ msgstr "" +#~ "Änderte die Gruppenzugehörigkeit von {old_groups} auf {new_groups}{reason}" + +#, python-brace-format +#~ msgid "Completed deletion of translatable page \"{article}\"" +#~ msgstr "Schloss die Löschung der übersetzbaren Seite „{article}“ ab" + +#, python-brace-format +#~ msgid "[{author}]({author_url}) restored a wiki *{wiki_name}*{comment}" +#~ msgstr "" +#~ "[{author}]({author_url}) stellte das Wiki *{wiki_name}* wieder " +#~ "her{comment}" + +#, python-brace-format +#~ msgid "Restored a \"{wiki}\" wiki" +#~ msgstr "Stellte das Wiki „{wiki}“ wieder her" + +#, python-brace-format +#~ msgid "[{author}]({author_url}) deleted a comment on {target}'s profile" +#~ msgstr "" +#~ "[{author}]({author_url}) löschte einen Kommentar auf dem Profil von " +#~ "{target}" + +#, python-brace-format +#~ msgid "[{author}]({author_url}) deleted a comment on their own profile" +#~ msgstr "" +#~ "[{author}]({author_url}) löschte einen Kommentar auf dem eigenen Profil" + +#, python-brace-format +#~ msgid "[{author}]({author_url}) imported interwiki{comment}" +#~ msgstr "[{author}]({author_url}) importierte Interwiki{comment}" + +#~ msgid "Imported interwiki" +#~ msgstr "Importierte Interwiki" + +#~ msgid "their own profile" +#~ msgstr "das eigene Profil" + +#~ msgid "their own" +#~ msgstr "sich selbst" + +#, python-brace-format +#~ msgid "[{target}]({target_url})'s" +#~ msgstr "dem Profil von [{target}]({target_url})" + +#, python-brace-format +#~ msgid "[their own]({target_url})" +#~ msgstr "dem [eigenen Profil]({target_url})" diff --git a/locale/de/LC_MESSAGES/misc.po b/locale/de/LC_MESSAGES/misc.po index c4349dd..75e47be 100644 --- a/locale/de/LC_MESSAGES/misc.po +++ b/locale/de/LC_MESSAGES/misc.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-28 23:45+0100\n" +"POT-Creation-Date: 2021-07-11 14:32+0200\n" "PO-Revision-Date: 2020-08-03 13:44+0000\n" "Last-Translator: MarkusRost <>\n" "Language-Team: German \n" +"PO-Revision-Date: 2021-05-06 14:10+0000\n" +"Last-Translator: magiczocker \n" "Language-Team: German \n" "Language: de\n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.2.1\n" +"X-Generator: Weblate 4.6\n" "X-Loco-Source-Locale: de_DE\n" "Generated-By: pygettext.py 1.5\n" "X-Loco-Parser: loco_parse_po\n" @@ -601,20 +601,23 @@ msgid "[{author}]({author_url}) replaced the Cargo table \"{table}\"" msgstr "[{author}]({author_url}) ersetzte die Cargo-Tabelle „{table}“" #: src/rc_formatters.py:436 -#, fuzzy, python-brace-format +#, python-brace-format msgid "" "[{author}]({author_url}) created the [tag]({tag_url}) \"{tag}\"{comment}" msgstr "" -"[{author}]({author_url}) erstellte eine [Markierung]({tag_url}) „{tag}“" +"[{author}]({author_url}) erstellte eine [Markierung]({tag_url}) " +"„{tag}“{comment}" #: src/rc_formatters.py:441 -#, fuzzy, python-brace-format +#, python-brace-format msgid "" "[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\"{comment}" -msgstr "[{author}]({author_url}) löschte eine [Markierung]({tag_url}) „{tag}“" +msgstr "" +"[{author}]({author_url}) löschte eine [Markierung]({tag_url}) " +"„{tag}“{comment}" #: src/rc_formatters.py:443 -#, fuzzy, python-brace-format +#, python-brace-format msgid "" "[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\" and removed " "it from {count} revision or log entry{comment}" @@ -622,25 +625,27 @@ msgid_plural "" "[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\" and removed " "it from {count} revisions and/or log entries{comment}" msgstr[0] "" -"[{author}]({author_url}) importierte [{article}]({article_url}) mit einer " -"Version{comment}" +"[{author}]({author_url}) löschte die [Markierung]({tag_url}) „{tag}“ und " +"entfernte diese von {count} Version oder Logeintrag{comment}" msgstr[1] "" -"[{author}]({author_url}) importierte [{article}]({article_url}) mit {count} " -"Versionen{comment}" +"[{author}]({author_url}) löschte die [Markierung]({tag_url}) „{tag}“ und " +"entfernte diese von {count} Versionen und/oder Logeinträgen{comment}" #: src/rc_formatters.py:449 -#, fuzzy, python-brace-format +#, python-brace-format msgid "" "[{author}]({author_url}) activated the [tag]({tag_url}) \"{tag}\"{comment}" msgstr "" -"[{author}]({author_url}) aktivierte eine [Markierung]({tag_url}) „{tag}“" +"[{author}]({author_url}) aktivierte eine [Markierung]({tag_url}) " +"„{tag}“{comment}" #: src/rc_formatters.py:452 -#, fuzzy, python-brace-format +#, python-brace-format msgid "" "[{author}]({author_url}) deactivated the [tag]({tag_url}) \"{tag}\"{comment}" msgstr "" -"[{author}]({author_url}) deaktivierte eine [Markierung]({tag_url}) „{tag}“" +"[{author}]({author_url}) deaktivierte eine [Markierung]({tag_url}) " +"„{tag}“{comment}" #: src/rc_formatters.py:454 #, python-brace-format @@ -658,7 +663,7 @@ msgid "[{author}]({author_url}) locked a wiki *{wiki_name}*{comment}" msgstr "[{author}]({author_url}) sperrte das Wiki *{wiki_name}*{comment}" #: src/rc_formatters.py:462 -#, fuzzy, python-brace-format +#, python-brace-format msgid "" "[{author}]({author_url}) modified namespace *{namespace_name}* on " "*{wiki_name}*{comment}" @@ -683,9 +688,11 @@ msgstr "" "*{comment}" #: src/rc_formatters.py:477 -#, fuzzy, python-brace-format +#, python-brace-format msgid "[{author}]({author_url}) undeleted a wiki *{wiki_name}*{comment}" -msgstr "[{author}]({author_url}) löschte das Wiki *{wiki_name}*{comment}" +msgstr "" +"[{author}]({author_url}) hat das Wiki *{wiki_name}* wiederhergestellt " +"{comment}" #: src/rc_formatters.py:481 #, python-brace-format @@ -1303,33 +1310,32 @@ msgid "Replaced the Cargo table \"{table}\"" msgstr "Ersetzte die Cargo-Tabelle „{table}“" #: src/rc_formatters.py:1121 -#, fuzzy, python-brace-format +#, python-brace-format msgid "Created the tag \"{tag}\"" msgstr "Erstellte die Markierung „{tag}“" #: src/rc_formatters.py:1125 -#, fuzzy, python-brace-format +#, python-brace-format msgid "Deleted the tag \"{tag}\"" msgstr "Löschte die Markierung „{tag}“" #: src/rc_formatters.py:1127 -#, fuzzy msgid "Removed from" -msgstr "Entfernt" +msgstr "Entfernt von" #: src/rc_formatters.py:1127 msgid "{} revision or log entry" msgid_plural "{} revisions and/or log entries" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "{} Version oder Logeintrag" +msgstr[1] "{} Versionen und/oder Logeinträge" #: src/rc_formatters.py:1131 -#, fuzzy, python-brace-format +#, python-brace-format msgid "Activated the tag \"{tag}\"" msgstr "Aktivierte die Markierung „{tag}“" #: src/rc_formatters.py:1134 -#, fuzzy, python-brace-format +#, python-brace-format msgid "Deactivated the tag \"{tag}\"" msgstr "Deaktivierte die Markierung „{tag}“" @@ -1348,7 +1354,7 @@ msgid "Locked a \"{wiki}\" wiki" msgstr "Sperrte das Wiki „{wiki}“" #: src/rc_formatters.py:1147 -#, fuzzy, python-brace-format +#, python-brace-format msgid "Modified \"{namespace_name}\" namespace" msgstr "Bearbeitete den Namensraum „{namespace_name}“" @@ -1367,9 +1373,9 @@ msgid "Modified \"{usergroup_name}\" usergroup" msgstr "Bearbeitete die Benutzergruppe „{usergroup_name}“" #: src/rc_formatters.py:1160 -#, fuzzy, python-brace-format +#, python-brace-format msgid "Undeleted a \"{wiki}\" wiki" -msgstr "Löschte das Wiki „{wiki}“" +msgstr "Das „{wiki}“ Wiki wiederhergestellt" #: src/rc_formatters.py:1163 #, python-brace-format diff --git a/locale/de/LC_MESSAGES/rcgcdw.mo b/locale/de/LC_MESSAGES/rcgcdw.mo index c8e8b5b..3befaa2 100644 Binary files a/locale/de/LC_MESSAGES/rcgcdw.mo and b/locale/de/LC_MESSAGES/rcgcdw.mo differ diff --git a/locale/de/LC_MESSAGES/rcgcdw.po b/locale/de/LC_MESSAGES/rcgcdw.po index 7eb52d8..40ecbf8 100644 --- a/locale/de/LC_MESSAGES/rcgcdw.po +++ b/locale/de/LC_MESSAGES/rcgcdw.po @@ -2,199 +2,190 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-12-23 00:28+0100\n" -"PO-Revision-Date: 2020-09-03 13:14+0200\n" -"Last-Translator: MarkusRost <>\n" -"Language-Team: German \n" +"Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Poedit 2.4.1\n" +"X-Generator: Weblate 4.6\n" "X-Loco-Source-Locale: de_DE\n" "Generated-By: pygettext.py 1.5\n" "X-Loco-Parser: loco_parse_po\n" -#: src/rcgcdw.py:115 src/rcgcdw.py:117 src/rcgcdw.py:119 src/rcgcdw.py:121 -#: src/rcgcdw.py:123 src/rcgcdw.py:125 src/rcgcdw.py:127 +#: src/rcgcdw.py:117 #, python-brace-format msgid "{value} (avg. {avg})" msgstr "{value} (vgl. {avg})" -#: src/rcgcdw.py:147 +#: src/rcgcdw.py:136 msgid "Daily overview" msgstr "Tägliche Übersicht" -#: src/rcgcdw.py:154 +#: src/rcgcdw.py:143 msgid "No activity" msgstr "Keine Aktivität" -#: src/rcgcdw.py:178 +#: src/rcgcdw.py:167 msgid " ({} action)" msgid_plural " ({} actions)" msgstr[0] " (eine Aktion)" msgstr[1] " ({} Aktionen)" -#: src/rcgcdw.py:180 +#: src/rcgcdw.py:169 msgid " ({} edit)" msgid_plural " ({} edits)" msgstr[0] " (eine Änderung)" msgstr[1] " ({} Änderungen)" -#: src/rcgcdw.py:185 +#: src/rcgcdw.py:174 msgid " UTC ({} action)" msgid_plural " UTC ({} actions)" msgstr[0] " UTC (eine Aktion)" msgstr[1] " UTC ({} Aktionen)" -#: src/rcgcdw.py:187 src/rcgcdw.py:188 src/rcgcdw.py:192 +#: src/rcgcdw.py:176 src/rcgcdw.py:179 msgid "But nobody came" msgstr "Keine Aktivität" -#: src/rcgcdw.py:195 +#: src/rcgcdw.py:183 msgid "Most active user" msgid_plural "Most active users" msgstr[0] "Aktivster Benutzer" msgstr[1] "Aktivste Benutzer" -#: src/rcgcdw.py:196 +#: src/rcgcdw.py:184 msgid "Most edited article" msgid_plural "Most edited articles" msgstr[0] "Meist bearbeiteter Artikel" msgstr[1] "Meist bearbeitete Artikel" -#: src/rcgcdw.py:197 +#: src/rcgcdw.py:185 msgid "Edits made" msgstr "Bearbeitungen" -#: src/rcgcdw.py:197 +#: src/rcgcdw.py:185 msgid "New files" msgstr "Neue Dateien" -#: src/rcgcdw.py:197 +#: src/rcgcdw.py:186 msgid "Admin actions" msgstr "Admin-Aktionen" -#: src/rcgcdw.py:198 +#: src/rcgcdw.py:186 msgid "Bytes changed" msgstr "Bytes geändert" -#: src/rcgcdw.py:198 +#: src/rcgcdw.py:187 msgid "New articles" msgstr "Neue Artikel" -#: src/rcgcdw.py:199 +#: src/rcgcdw.py:187 msgid "Unique contributors" msgstr "Einzelne Autoren" -#: src/rcgcdw.py:200 +#: src/rcgcdw.py:188 msgid "Most active hour" msgid_plural "Most active hours" msgstr[0] "Aktivste Stunde" msgstr[1] "Aktivste Stunden" -#: src/rcgcdw.py:201 +#: src/rcgcdw.py:189 msgid "Day score" msgstr "Tageswert" -#: src/rcgcdw.py:243 -msgid "director" -msgstr "Direktor" +#: src/rcgcdw.py:223 +msgid "~~hidden~~" +msgstr "~~versteckt~~" -#: src/rcgcdw.py:243 -msgid "bot" -msgstr "Bot" +#: src/rcgcdw.py:225 +msgid "No description provided" +msgstr "Keine Zusammenfassung angegeben" -#: src/rcgcdw.py:243 -msgid "editor" -msgstr "editor" +#: src/rcgcdw.py:228 +msgid "hidden" +msgstr "versteckt" -#: src/rcgcdw.py:243 -msgid "directors" -msgstr "Direktor" +#~ msgid "director" +#~ msgstr "Direktor" -#: src/rcgcdw.py:243 -msgid "sysop" -msgstr "Administrator" +#~ msgid "bot" +#~ msgstr "Bot" -#: src/rcgcdw.py:243 -msgid "bureaucrat" -msgstr "Bürokrat" +#~ msgid "editor" +#~ msgstr "editor" -#: src/rcgcdw.py:243 -msgid "reviewer" -msgstr "Prüfer" +#~ msgid "directors" +#~ msgstr "Direktor" -#: src/rcgcdw.py:244 -msgid "autoreview" -msgstr "Passive Sichter" +#~ msgid "sysop" +#~ msgstr "Administrator" -#: src/rcgcdw.py:244 -msgid "autopatrol" -msgstr "autopatrol" +#~ msgid "bureaucrat" +#~ msgstr "Bürokrat" -#: src/rcgcdw.py:244 -msgid "wiki_guardian" -msgstr "Wiki Guardian" +#~ msgid "reviewer" +#~ msgstr "Prüfer" -#: src/rcgcdw.py:244 -msgid "second" -msgid_plural "seconds" -msgstr[0] "Sekunde" -msgstr[1] "Sekunden" +#~ msgid "autoreview" +#~ msgstr "Passive Sichter" -#: src/rcgcdw.py:244 -msgid "minute" -msgid_plural "minutes" -msgstr[0] "Minute" -msgstr[1] "Minuten" +#~ msgid "autopatrol" +#~ msgstr "autopatrol" -#: src/rcgcdw.py:244 -msgid "hour" -msgid_plural "hours" -msgstr[0] "Stunde" -msgstr[1] "Stunden" +#~ msgid "wiki_guardian" +#~ msgstr "Wiki Guardian" -#: src/rcgcdw.py:244 -msgid "day" -msgid_plural "days" -msgstr[0] "Tag" -msgstr[1] "Tage" +#~ msgid "second" +#~ msgid_plural "seconds" +#~ msgstr[0] "Sekunde" +#~ msgstr[1] "Sekunden" -#: src/rcgcdw.py:244 -msgid "week" -msgid_plural "weeks" -msgstr[0] "Woche" -msgstr[1] "Wochen" +#~ msgid "minute" +#~ msgid_plural "minutes" +#~ msgstr[0] "Minute" +#~ msgstr[1] "Minuten" -#: src/rcgcdw.py:244 -msgid "month" -msgid_plural "months" -msgstr[0] "Monat" -msgstr[1] "Monate" +#~ msgid "hour" +#~ msgid_plural "hours" +#~ msgstr[0] "Stunde" +#~ msgstr[1] "Stunden" -#: src/rcgcdw.py:244 -msgid "year" -msgid_plural "years" -msgstr[0] "Jahr" -msgstr[1] "Jahre" +#~ msgid "day" +#~ msgid_plural "days" +#~ msgstr[0] "Tag" +#~ msgstr[1] "Tage" -#: src/rcgcdw.py:244 -msgid "millennium" -msgid_plural "millennia" -msgstr[0] "Jahrtausend" -msgstr[1] "Jahrtausende" +#~ msgid "week" +#~ msgid_plural "weeks" +#~ msgstr[0] "Woche" +#~ msgstr[1] "Wochen" -#: src/rcgcdw.py:244 -msgid "decade" -msgid_plural "decades" -msgstr[0] "Jahrzehnt" -msgstr[1] "Jahrzehnte" +#~ msgid "month" +#~ msgid_plural "months" +#~ msgstr[0] "Monat" +#~ msgstr[1] "Monate" -#: src/rcgcdw.py:244 -msgid "century" -msgid_plural "centuries" -msgstr[0] "Jahrhundert" -msgstr[1] "Jahrhunderte" +#~ msgid "year" +#~ msgid_plural "years" +#~ msgstr[0] "Jahr" +#~ msgstr[1] "Jahre" + +#~ msgid "millennium" +#~ msgid_plural "millennia" +#~ msgstr[0] "Jahrtausend" +#~ msgstr[1] "Jahrtausende" + +#~ msgid "decade" +#~ msgid_plural "decades" +#~ msgstr[0] "Jahrzehnt" +#~ msgstr[1] "Jahrzehnte" + +#~ msgid "century" +#~ msgid_plural "centuries" +#~ msgstr[0] "Jahrhundert" +#~ msgstr[1] "Jahrhunderte" diff --git a/locale/de/LC_MESSAGES/redaction.mo b/locale/de/LC_MESSAGES/redaction.mo index 1321f36..3850a03 100644 Binary files a/locale/de/LC_MESSAGES/redaction.mo and b/locale/de/LC_MESSAGES/redaction.mo differ diff --git a/locale/de/LC_MESSAGES/redaction.po b/locale/de/LC_MESSAGES/redaction.po index d3c7a61..a30f841 100644 --- a/locale/de/LC_MESSAGES/redaction.po +++ b/locale/de/LC_MESSAGES/redaction.po @@ -7,19 +7,25 @@ msgid "" msgstr "" "Project-Id-Version: RcGcDw\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-12-23 00:28+0100\n" -"PO-Revision-Date: 2020-11-20 09:22+0000\n" +"POT-Creation-Date: 2021-07-11 14:32+0200\n" +"PO-Revision-Date: 2021-07-30 10:44+0000\n" "Last-Translator: MarkusRost \n" -"Language-Team: German \n" +"Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.2.1\n" +"X-Generator: Weblate 4.6.2\n" -#: src/discord/redaction.py:62 src/discord/redaction.py:65 -#: src/discord/redaction.py:70 -msgid "Removed" -msgstr "Versteckt" +#: src/discord/redaction.py:77 +msgid "hidden" +msgstr "versteckt" + +#: src/discord/redaction.py:80 src/discord/redaction.py:85 +msgid "~~hidden~~" +msgstr "~~versteckt~~" + +#~ msgid "Removed" +#~ msgstr "Versteckt" diff --git a/locale/es/LC_MESSAGES/discussion_formatters.mo b/locale/es/LC_MESSAGES/discussion_formatters.mo deleted file mode 100644 index 8a62e21..0000000 Binary files a/locale/es/LC_MESSAGES/discussion_formatters.mo and /dev/null differ diff --git a/locale/es/LC_MESSAGES/formatters.mo b/locale/es/LC_MESSAGES/formatters.mo new file mode 100644 index 0000000..0bd9a5a Binary files /dev/null and b/locale/es/LC_MESSAGES/formatters.mo differ diff --git a/locale/es/LC_MESSAGES/formatters.po b/locale/es/LC_MESSAGES/formatters.po new file mode 100644 index 0000000..11a5d40 --- /dev/null +++ b/locale/es/LC_MESSAGES/formatters.po @@ -0,0 +1,2013 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the RcGcDw package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: RcGcDw\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-07-11 14:32+0200\n" +"PO-Revision-Date: 2021-07-30 10:44+0000\n" +"Last-Translator: Tamara Carvallo \n" +"Language-Team: Spanish \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.6.2\n" + +#: src/api/util.py:61 src/api/util.py:66 +msgid "__Only whitespace__" +msgstr "__Sólo espacios en blanco__" + +#: src/api/util.py:71 +msgid "Removed" +msgstr "Eliminado" + +#: src/api/util.py:73 +msgid "Added" +msgstr "Agregado" + +#: src/api/util.py:94 src/api/util.py:126 src/api/util.py:133 +#: src/api/util.py:141 extensions/base/discussions.py:247 +#: extensions/base/discussions.py:264 extensions/base/abusefilter.py:45 +msgid "Unregistered user" +msgstr "Usuario no registrado" + +#: src/api/util.py:160 +#, fuzzy +msgctxt "recent changes Tags" +msgid "Tags" +msgstr "Etiquetas" + +#: src/api/util.py:162 +msgid "**Added**: " +msgstr "**Agregó**: " + +#: src/api/util.py:163 +msgid " and {} more\n" +msgstr " y {} más\n" + +#: src/api/util.py:165 +msgid "**Removed**: " +msgstr "**Eliminó**: " + +#: src/api/util.py:166 +msgid " and {} more" +msgstr " y {} más" + +#: src/api/util.py:168 +msgid "Changed categories" +msgstr "Cambio las categorías" + +#: extensions/base/cargo.py:37 +#, python-brace-format +msgid "Created the Cargo table \"{table}\"" +msgstr "Creó la tabla Cargo \"{table}\"" + +#: extensions/base/cargo.py:45 +#, python-brace-format +msgid "[{author}]({author_url}) created the Cargo table \"{table}\"" +msgstr "[{author}]({author_url}) creó la tabla Cargo \"{table}\"" + +#: extensions/base/cargo.py:60 +#, python-brace-format +msgid "Recreated the Cargo table \"{table}\"" +msgstr "Recreó la tabla Cargo \"{table}\"" + +#: extensions/base/cargo.py:68 +#, python-brace-format +msgid "[{author}]({author_url}) recreated the Cargo table \"{table}\"" +msgstr "[{author}]({author_url}) recreó la tabla Cargo \"{table}\"" + +#: extensions/base/cargo.py:83 +#, python-brace-format +msgid "Replaced the Cargo table \"{table}\"" +msgstr "Reemplazó la tabla Cargo \"{table}\"" + +#: extensions/base/cargo.py:91 +#, python-brace-format +msgid "[{author}]({author_url}) replaced the Cargo table \"{table}\"" +msgstr "[{author}]({author_url}) reemplazó la tabla Cargo \"{table}\"" + +#: extensions/base/cargo.py:105 +#, python-brace-format +msgid "Deleted the Cargo table \"{table}\"" +msgstr "Eliminó la tabla Cargo \"{table}\"" + +#: extensions/base/cargo.py:112 +#, python-brace-format +msgid "[{author}]({author_url}) deleted the Cargo table \"{table}\"" +msgstr "[{author}]({author_url}) eliminó la tabla Cargo \"{table}\"" + +#: extensions/base/translate.py:41 +#, python-brace-format +msgid "Marked \"{article}\" for translation" +msgstr "Marcó \"{article}\" para traducir" + +#: extensions/base/translate.py:55 +#, python-brace-format +msgid "" +"[{author}]({author_url}) marked [{article}]({article_url}) for " +"translation{comment}" +msgstr "" +"[{author}]({author_url}) marcó [{article}]({article_url}) para " +"traducción{comment}" + +#: extensions/base/translate.py:70 +#, python-brace-format +msgid "Removed \"{article}\" from the translation system" +msgstr "Eliminó \"{article}\" del sistema de traducción" + +#: extensions/base/translate.py:80 +#, python-brace-format +msgid "" +"[{author}]({author_url}) removed [{article}]({article_url}) from the " +"translation system{comment}" +msgstr "" +"[{author}]({author_url}) eliminó [{article}]({article_url}) del sistema de " +"traducción{comment}" + +#: extensions/base/translate.py:95 +#, python-brace-format +msgid "Completed moving translation pages from \"{article}\" to \"{target}\"" +msgstr "" +"Completó el traslado de las páginas de traducción de \"{article}\" a \"" +"{target}\"" + +#: extensions/base/translate.py:106 +#, python-brace-format +msgid "" +"[{author}]({author_url}) completed moving translation pages from *{article}* " +"to [{target}]({target_url}){comment}" +msgstr "" +"[{author}]({author_url}) movió la configuración de protección de *{article}* " +"a [{target}]({target_url}){comment}" + +#: extensions/base/translate.py:121 +#, python-brace-format +msgid "Encountered a problem while moving \"{article}\" to \"{target}\"" +msgstr "Se encontró un problema al mover \"{article}\" a \"{target}\"" + +#: extensions/base/translate.py:133 +#, python-brace-format +msgid "" +"[{author}]({author_url}) encountered a problem while moving [{article}]" +"({article_url}) to [{target}]({target_url}){comment}" +msgstr "" +"[{author}]({author_url}) encontró un problema al mover " +"[{article}]({article_url}) a [{target}]({target_url}){comment}" + +#: extensions/base/translate.py:149 +#, python-brace-format +msgid "" +"Failed to delete \"{article}\" which belongs to translatable page " +"\"{target}\"" +msgstr "" +"No se pudo borrar \"{article}\" que pertenece a la página traducible \"" +"{target}\"" + +#: extensions/base/translate.py:161 +#, python-brace-format +msgid "" +"[{author}]({author_url}) failed to delete [{article}]({article_url}) which " +"belongs to translatable page [{target}]({target_url}){comment}" +msgstr "" +"[{author}]({author_url}) no pudo borrar [{article}]({article_url}) que " +"pertenece a la página traducible [{target}]({target_url}){comment}" + +#: extensions/base/translate.py:177 +#, python-brace-format +msgid "Completed deletion of translation page \"{article}\"" +msgstr "Se eliminó completamente la página de traducción \"{article}\"" + +#: extensions/base/translate.py:188 +#, python-brace-format +msgid "" +"[{author}]({author_url}) completed deletion of translation page [{article}]" +"({article_url}){comment}" +msgstr "" +"[{author}]({author_url}) eliminó la página de traducción " +"[{article}]({article_url}){comment}" + +#: extensions/base/translate.py:203 +#, python-brace-format +msgid "" +"Failed to delete \"{article}\" which belongs to translation page \"{target}\"" +msgstr "" +"No se pudo borrar \"{article}\" que pertenece a la página de traducción \"" +"{target}\"" + +#: extensions/base/translate.py:215 +#, python-brace-format +msgid "" +"[{author}]({author_url}) failed to delete [{article}]({article_url}) which " +"belongs to translation page [{target}]({target_url}){comment}" +msgstr "" +"[{author}]({author_url}) no pudo borrar [{article}]({article_url}) que " +"pertenece a la página de traducción [{target}]({target_url}){comment}" + +#: extensions/base/translate.py:231 +#, python-brace-format +msgid "Encouraged translation of \"{article}\"" +msgstr "Traducción recomendada de \"{article}\"" + +#: extensions/base/translate.py:240 +#, python-brace-format +msgid "" +"[{author}]({author_url}) encouraged translation of [{article}]({article_url})" +"{comment}" +msgstr "" +"[{author}]({author_url}) recomendó la traducción de " +"[{article}]({article_url}){comment}" + +#: extensions/base/translate.py:255 +#, python-brace-format +msgid "Discouraged translation of \"{article}\"" +msgstr "Traducción desaconsejada de \"{article}\"" + +#: extensions/base/translate.py:264 +#, python-brace-format +msgid "" +"[{author}]({author_url}) discouraged translation of [{article}]" +"({article_url}){comment}" +msgstr "" +"[{author}]({author_url}) desaconsejó la traducción de " +"[{article}]({article_url}){comment}" + +#: extensions/base/translate.py:282 +#, python-brace-format +msgid "Limited languages for \"{article}\" to `{languages}`" +msgstr "Idiomas limitados para \"{article}\" a `{languages}`" + +#: extensions/base/translate.py:285 +#, python-brace-format +msgid "Priority languages for \"{article}\" set to `{languages}`" +msgstr "" +"Los idiomas prioritarios para \"{article}\" se establecieron en `{languages}`" + +#: extensions/base/translate.py:288 +#, python-brace-format +msgid "Removed priority languages from \"{article}\"" +msgstr "Se quitaron los idiomas prioritarios de \"{article}\"" + +#: extensions/base/translate.py:301 +#, python-brace-format +msgid "" +"[{author}]({author_url}) limited languages for [{article}]({article_url}) to " +"`{languages}`{comment}" +msgstr "" +"[{author}]({author_url}) limitó los idiomas para [{article}]({article_url}) " +"a `{languages}`{comment}" + +#: extensions/base/translate.py:308 +#, python-brace-format +msgid "" +"[{author}]({author_url}) set the priority languages for [{article}]" +"({article_url}) to `{languages}`{comment}" +msgstr "" +"[{author}]({author_url}) estableció los idiomas de prioridad para " +"[{article}]({article_url}) en `{languages}`{comment}" + +#: extensions/base/translate.py:315 +#, python-brace-format +msgid "" +"[{author}]({author_url}) removed priority languages from [{article}]" +"({article_url}){comment}" +msgstr "" +"[{author}]({author_url}) eliminó los idiomas prioritarios de " +"[{article}]({article_url}){comment}" + +#: extensions/base/translate.py:331 +#, python-brace-format +msgid "Added translatable page \"{article}\" to aggregate group \"{group}\"" +msgstr "" +"Se agregó la página traducible \"{article}\" al grupo agregado \"{group}\"" + +#: extensions/base/translate.py:342 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) added translatable page [{article}]({article_url}) " +"to aggregate group \"{group}\"{comment}" +msgstr "" +"[{author}]({author_url}) cambió el modelo de contenido de la página " +"[{article}]({article_url}) de {old} a {new}{comment}" + +#: extensions/base/translate.py:357 +#, python-brace-format +msgid "" +"Removed translatable page \"{article}\" from aggregate group \"{group}\"" +msgstr "" + +#: extensions/base/translate.py:368 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) removed translatable page [{article}]" +"({article_url}) from aggregate group \"{group}\"{comment}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) eliminó la protección de [{article}]({article_url})" +"{comment}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) quitó la protección de [{article}]({article_url})" +"{comment}" + +#: extensions/base/translate.py:387 +#, fuzzy, python-brace-format +msgid "Reviewed translation \"{article}\"" +msgstr "Respondió a un comentario en {article}" + +#: extensions/base/translate.py:401 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) reviewed translation [{article}]({article_url})" +"{comment}" +msgstr "[{author}]({author_url}) restauró [{article}]({article_url}){comment}" + +#: extensions/base/translate.py:416 +#, python-brace-format +msgid "Changed the state of `{language}` translations of \"{article}\"" +msgstr "" + +#: extensions/base/translate.py:419 +msgid "Old state" +msgstr "" + +#: extensions/base/translate.py:420 +msgid "New state" +msgstr "" + +#: extensions/base/translate.py:431 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) changed the state of `{language}` translations of " +"[{article}]({article_url}) from `{old_state}` to `{new_state}`{comment}" +msgstr "" +"[{author}]({author_url}) cambió el modelo de contenido de la página " +"[{article}]({article_url}) de {old} a {new}{comment}" + +#: extensions/base/translate.py:439 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) changed the state of `{language}` translations of " +"[{article}]({article_url}) to `{new_state}`{comment}" +msgstr "" +"[{author}]({author_url}) cambió el modelo de contenido de la página " +"[{article}]({article_url}) de {old} a {new}{comment}" + +#: extensions/base/translate.py:452 extensions/base/translate.py:455 +msgid "(default)" +msgstr "" + +#: extensions/base/translate.py:464 +#, fuzzy, python-brace-format +msgid "Changed the language of \"{article}\"" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Cambió el nivel de protección de {article}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Modificó el nivel de protección de {article}" + +#: extensions/base/translate.py:465 +msgid "Old language" +msgstr "" + +#: extensions/base/translate.py:466 +msgid "New language" +msgstr "" + +#: extensions/base/translate.py:477 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) changed the language of [{article}]({article_url}) " +"from {old_lang} to {new_lang}{comment}" +msgstr "" +"[{author}]({author_url}) cambió el modelo de contenido de la página " +"[{article}]({article_url}) de {old} a {new}{comment}" + +#: extensions/base/discussions.py:148 extensions/base/discussions.py:207 +#: extensions/base/discussions.py:245 extensions/base/discussions.py:261 +#: extensions/base/discussions.py:284 extensions/base/discussions.py:306 +#: extensions/base/discussions.py:334 extensions/base/discussions.py:354 +msgid "unknown" +msgstr "desconocido" + +#: extensions/base/discussions.py:157 +#, python-brace-format +msgid "Created \"{title}\"" +msgstr "Creó \"{title}\"" + +#: extensions/base/discussions.py:161 +#, python-brace-format +msgid "Created a poll \"{title}\"" +msgstr "Creó una encuesta \"{title}\"" + +#: extensions/base/discussions.py:168 +msgid "Option {}" +msgstr "Opción {}" + +#: extensions/base/discussions.py:170 +#, python-brace-format +msgid "__[View image]({image_url})__" +msgstr "__[Ver imagen]({image_url})__" + +#: extensions/base/discussions.py:174 +#, python-brace-format +msgid "Created a quiz \"{title}\"" +msgstr "Creó un cuestionario \"{title}\"" + +#: extensions/base/discussions.py:193 extensions/base/discussions.py:195 +#, fuzzy +msgctxt "Fandom discussions Tags/Forums" +msgid "Tags" +msgstr "Etiquetas" + +#: extensions/base/discussions.py:193 +#, fuzzy +msgctxt "Fandom discussions amount of Tags/Forums" +msgid "{} tags" +msgstr "{} etiquetas" + +#: extensions/base/discussions.py:198 +#, python-brace-format +msgid "Replied to \"{title}\"" +msgstr "Respondió a \"{title}\"" + +#: extensions/base/discussions.py:214 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created [{title}](<{url}f/p/{threadId}>) in " +"{forumName}" +msgstr "" +"[{author}]({author_url}) creó [{title}](<{url}f/p/{threadId}>) en {forumName}" + +#: extensions/base/discussions.py:217 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a poll [{title}](<{url}f/p/{threadId}>) in " +"{forumName}" +msgstr "" +"[{author}]({author_url}) creó una encuesta [{title}](<{url}f/p/{threadId}>) " +"en {forumName}" + +#: extensions/base/discussions.py:220 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a quiz [{title}](<{url}f/p/{threadId}>) in " +"{forumName}" +msgstr "" +"[{author}]({author_url}) creó un cuestionario [{title}](<{url}f/p/{threadId}" +">) en {forumName}" + +#: extensions/base/discussions.py:234 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a [reply](<{url}f/p/{threadId}/r/{postId}>) " +"to [{title}](<{url}f/p/{threadId}>) in {forumName}" +msgstr "" +"[{author}]({author_url}) creó una [respuesta](<{url}f/p/{threadId}/r/{postId}" +">) a [{title}](<{url}f/p/{threadId}>) en {forumName}" + +#: extensions/base/discussions.py:292 +#, python-brace-format +msgid "Created \"{title}\" on {user}'s Message Wall" +msgstr "Creó \"{title}\" en el muro de mensajes de {user}" + +#: extensions/base/discussions.py:298 +#, python-brace-format +msgid "Replied to \"{title}\" on {user}'s Message Wall" +msgstr "Respondió a \"{title}\" en el muro de mensajes de {user}" + +#: extensions/base/discussions.py:312 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created [{title}](<{url}wiki/Message_Wall:" +"{user_wall}?threadId={threadId}>) on [{user}'s Message Wall](<{url}wiki/" +"Message_Wall:{user_wall}>)" +msgstr "" +"[{author}]({author_url}) creó [{title}](<{url}wiki/Message_Wall:{user_wall}?" +"threadId={threadId}>) en [{user}'s Message Wall](<{url}wiki/Message_Wall:" +"{user_wall}>)" + +#: extensions/base/discussions.py:318 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a [reply](<{url}wiki/Message_Wall:" +"{user_wall}?threadId={threadId}#{replyId}>) to [{title}](<{url}wiki/" +"Message_Wall:{user_wall}?threadId={threadId}>) on [{user}'s Message Wall]" +"(<{url}wiki/Message_Wall:{user_wall}>)" +msgstr "" +"[{author}]({author_url}) creó una [respuesta](<{url}wiki/Message_Wall:" +"{user_wall}?threadId={threadId}#{replyId}>) a [{title}](<{url}wiki/" +"Message_Wall:{user_wall}?threadId={threadId}>) en el [{user} Muro de " +"Mensajes](<{url}wiki/Message_Wall:{user_wall}>)" + +#: extensions/base/discussions.py:338 +#, python-brace-format +msgid "Commented on {article}" +msgstr "Comentó en {article}" + +#: extensions/base/discussions.py:344 +#, python-brace-format +msgid "Replied to a comment on {article}" +msgstr "Respondió a un comentario en {article}" + +#: extensions/base/discussions.py:359 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a [comment](<{url}?commentId={commentId}>) " +"on [{article}](<{url}>)" +msgstr "" +"[{author}]({author_url}) creó un [comentario](<{url}?commentId={commentId}>) " +"en [{article}](<{url}>)" + +#: extensions/base/discussions.py:365 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created a [reply](<{url}?commentId={commentId}" +"&replyId={replyId}>) to a [comment](<{url}?commentId={commentId}>) on " +"[{article}](<{url}>)" +msgstr "" +"[{author}]({author_url}) creó una [respuesta](<{url}?commentId={commentId}" +"&replyId={replyId}>) a un [comentario](<{url}?commentId={commentId}>) en " +"[{article}](<{url}>)" + +#: extensions/base/managewiki.py:34 +#, fuzzy +msgid "Changed wiki settings" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Cambió la configuración del wiki\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Modificó la configuración del wiki" + +#: extensions/base/managewiki.py:44 +#, fuzzy, python-brace-format +msgid "[{author}]({author_url}) changed wiki settings{reason}" +msgstr "[{author}]({author_url}) cambió la configuración del wiki ({reason})" + +#: extensions/base/managewiki.py:55 +#, python-brace-format +msgid "Deleted a \"{wiki}\" wiki" +msgstr "Eliminó un wiki \"{wiki}\"" + +#: extensions/base/managewiki.py:55 extensions/base/managewiki.py:67 +#: extensions/base/managewiki.py:103 extensions/base/managewiki.py:112 +#: extensions/base/managewiki.py:125 extensions/base/managewiki.py:126 +#: extensions/base/managewiki.py:135 extensions/base/managewiki.py:136 +#: extensions/base/managewiki.py:148 extensions/base/managewiki.py:149 +#: extensions/base/managewiki.py:160 extensions/base/managewiki.py:161 +#: extensions/base/managewiki.py:195 extensions/base/managewiki.py:204 +#: extensions/base/managewiki.py:217 extensions/base/managewiki.py:226 +#: extensions/base/abusefilter.py:55 extensions/base/abusefilter.py:56 +#: extensions/base/abusefilter.py:57 extensions/base/abusefilter.py:68 +#: extensions/base/abusefilter.py:69 extensions/base/abusefilter.py:70 +#: extensions/base/mediawiki.py:743 +msgid "Unknown" +msgstr "Desconocido" + +#: extensions/base/managewiki.py:63 +#, fuzzy, python-brace-format +msgid "[{author}]({author_url}) deleted a wiki *{wiki_name}*{comment}" +msgstr "[{author}]({author_url}) eliminó un wiki *{wiki_name}* ({comment})" + +#: extensions/base/managewiki.py:80 +#, fuzzy, python-brace-format +msgid "Deleted a \"{group}\" user group" +msgstr "Modificó el grupo de usuarios \"{usergroup_name}\"" + +#: extensions/base/managewiki.py:89 +#, fuzzy, python-brace-format +msgid "[{author}]({author_url}) deleted a usergroup *{group}*{comment}" +msgstr "" +"[{author}]({author_url}) modificó el grupo de usuarios *{group_name}* " +"({comment})" + +#: extensions/base/managewiki.py:103 +#, python-brace-format +msgid "Locked a \"{wiki}\" wiki" +msgstr "Protegió un wiki \"{wiki}\"" + +#: extensions/base/managewiki.py:111 +#, fuzzy, python-brace-format +msgid "[{author}]({author_url}) locked a wiki *{wiki_name}*{comment}" +msgstr "[{author}]({author_url}) protegió un wiki *{wiki_name}* ({comment})" + +#: extensions/base/managewiki.py:124 +#, fuzzy, python-brace-format +msgid "Modified \"{namespace_name}\" namespace" +msgstr "Modificó un espacio de nombres \"{namespace_name}\"" + +#: extensions/base/managewiki.py:126 extensions/base/managewiki.py:149 +msgid "Wiki" +msgstr "Wiki" + +#: extensions/base/managewiki.py:134 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) modified namespace *{namespace_name}* on " +"*{wiki_name}*{comment}" +msgstr "" +"[{author}]({author_url}) modificó un espacio de nombres *{namespace_name}* " +"en *{wiki_name}* ({comment})" + +#: extensions/base/managewiki.py:147 +#, python-brace-format +msgid "Deleted a \"{namespace_name}\" namespace" +msgstr "Eliminó un espacio de nombres \"{namespace_name}\"" + +#: extensions/base/managewiki.py:158 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) deleted a namespace *{namespace_name}* on " +"*{wiki_name}*{comment}" +msgstr "" +"[{author}]({author_url}) eliminó un espacio de nombres *{namespace_name}* en " +"*{wiki_name}* ({comment})" + +#: extensions/base/managewiki.py:173 +#, python-brace-format +msgid "Modified \"{usergroup_name}\" usergroup" +msgstr "Modificó el grupo de usuarios \"{usergroup_name}\"" + +#: extensions/base/managewiki.py:182 +#, fuzzy, python-brace-format +msgid "[{author}]({author_url}) modified user group *{group_name}*{comment}" +msgstr "" +"[{author}]({author_url}) modificó el grupo de usuarios *{group_name}* " +"({comment})" + +#: extensions/base/managewiki.py:195 +#, fuzzy, python-brace-format +msgid "Undeleted a \"{wiki}\" wiki" +msgstr "Eliminó un wiki \"{wiki}\"" + +#: extensions/base/managewiki.py:203 +#, fuzzy, python-brace-format +msgid "[{author}]({author_url}) undeleted a wiki *{wiki_name}*{comment}" +msgstr "[{author}]({author_url}) eliminó un wiki *{wiki_name}* ({comment})" + +#: extensions/base/managewiki.py:217 +#, fuzzy, python-brace-format +msgid "Unlocked a \"{wiki}\" wiki" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Desbloqueó un wiki \"{wiki}\"\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Desprotegió un wiki \"{wiki}\"" + +#: extensions/base/managewiki.py:225 +#, fuzzy, python-brace-format +msgid "[{author}]({author_url}) unlocked a wiki *{wiki_name}*{comment}" +msgstr "[{author}]({author_url}) desprotegió un wiki *{wiki_name}* ({comment})" + +#: extensions/base/datadump.py:36 +#, python-brace-format +msgid "Generated {file} dump" +msgstr "" + +#: extensions/base/datadump.py:45 +#, fuzzy, python-brace-format +msgid "[{author}]({author_url}) generated *{file}* dump{comment}" +msgstr "[{author}]({author_url}) eliminó un wiki *{wiki_name}* ({comment})" + +#: extensions/base/datadump.py:58 +#, fuzzy, python-brace-format +msgid "Deleted {file} dump" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Eliminó la página {article}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Página eliminada {article}" + +#: extensions/base/datadump.py:67 +#, fuzzy, python-brace-format +msgid "[{author}]({author_url}) deleted *{file}* dump{comment}" +msgstr "[{author}]({author_url}) eliminó un wiki *{wiki_name}* ({comment})" + +#: extensions/base/curseprofile.py:40 +#, python-brace-format +msgid "Edited {target}'s profile" +msgstr "Editó el perfil de {target}" + +#: extensions/base/curseprofile.py:42 +msgid "Edited their own profile" +msgstr "Editó su propio perfil" + +#: extensions/base/curseprofile.py:44 +#, python-brace-format +msgid "Cleared the {field} field" +msgstr "Borró el campo {field}" + +#: extensions/base/curseprofile.py:46 +#, python-brace-format +msgid "{field} field changed to: {desc}" +msgstr "El campo {field} cambió a: {desc}" + +#: extensions/base/curseprofile.py:58 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) cleared the {field} on [{target}]({target_url})'s " +"profile." +msgstr "" +"[{author}]({author_url}) editó el {field} en el perfil de {target}. " +"*({desc})*" + +#: extensions/base/curseprofile.py:60 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) edited the {field} on [{target}]({target_url})'s " +"profile. *({desc})*" +msgstr "" +"[{author}]({author_url}) editó el {field} en el perfil de {target}. " +"*({desc})*" + +#: extensions/base/curseprofile.py:65 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) cleared the {field} on [their own]({target_url}) " +"profile." +msgstr "" +"[{author}]({author_url}) editó el {field} en su propio perfil. *({desc})*" + +#: extensions/base/curseprofile.py:67 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) edited the {field} on [their own]({target_url}) " +"profile. *({desc})*" +msgstr "" +"[{author}]({author_url}) editó el {field} en su propio perfil. *({desc})*" + +#: extensions/base/curseprofile.py:82 +#, python-brace-format +msgid "Left a comment on {target}'s profile" +msgstr "Dejó un comentario en el perfil de {target}" + +#: extensions/base/curseprofile.py:84 +msgid "Left a comment on their own profile" +msgstr "Dejó un comentario en su propio perfil" + +#: extensions/base/curseprofile.py:97 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) left a [comment]({comment}) on {target}'s profile." +msgstr "" +"[{author}]({author_url}) dejó un [comentario]({comment}) en el perfil de " +"{target}" + +#: extensions/base/curseprofile.py:100 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) left a [comment]({comment}) on their own profile." +msgstr "" +"[{author}]({author_url}) dejó un [comentario]({comment}) en su propio perfil" + +#: extensions/base/curseprofile.py:113 +#, python-brace-format +msgid "Edited a comment on {target}'s profile" +msgstr "Editó un comentario en el perfil de {target}" + +#: extensions/base/curseprofile.py:115 +msgid "Edited a comment on their own profile" +msgstr "Editó un comentario en su propio perfil" + +#: extensions/base/curseprofile.py:128 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) edited a [comment]({comment}) on {target}'s profile." +msgstr "" +"[{author}]({author_url}) editó un [comentario]({comment}) en el perfil de " +"{target}" + +#: extensions/base/curseprofile.py:131 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) edited a [comment]({comment}) on their own profile." +msgstr "" +"[{author}]({author_url}) editó un [comentario]({comment}) en su propio perfil" + +#: extensions/base/curseprofile.py:144 +#, python-brace-format +msgid "Replied to a comment on {target}'s profile" +msgstr "Respondió a un comentario en el perfil de {target}" + +#: extensions/base/curseprofile.py:146 +msgid "Replied to a comment on their own profile" +msgstr "Respondió a un comentario en su propio perfil" + +#: extensions/base/curseprofile.py:159 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) replied to a [comment]({comment}) on {target}'s " +"profile." +msgstr "" +"[{author}]({author_url}) respondió a un [comentario]({comment}) en el perfil " +"de {target}" + +#: extensions/base/curseprofile.py:162 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) replied to a [comment]({comment}) on their own " +"profile." +msgstr "" +"[{author}]({author_url}) respondió a un [comentario]({comment}) en su propio " +"perfil" + +#: extensions/base/curseprofile.py:175 +#, python-brace-format +msgid "Deleted a comment on {target}'s profile" +msgstr "Eliminó un comentario en el perfil de {target}" + +#: extensions/base/curseprofile.py:177 +#, fuzzy +msgid "Deleted a comment on their own profile" +msgstr "Editó un comentario en su propio perfil" + +#: extensions/base/curseprofile.py:197 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) deleted a [comment]({comment}) on {target}'s " +"profile.{reason}" +msgstr "" +"[{author}]({author_url}) editó un [comentario]({comment}) en el perfil de " +"{target}" + +#: extensions/base/curseprofile.py:200 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) deleted a [comment]({comment}) on their own profile." +"{reason}" +msgstr "" +"[{author}]({author_url}) editó un [comentario]({comment}) en su propio perfil" + +#: extensions/base/curseprofile.py:214 +#, python-brace-format +msgid "Purged a comment on {target}'s profile" +msgstr "Borró un comentario en el perfil de {target}" + +#: extensions/base/curseprofile.py:216 +#, fuzzy +msgid "Purged a comment on their own profile" +msgstr "Editó un comentario en su propio perfil" + +#: extensions/base/curseprofile.py:230 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) purged a comment on [{target}]({link})'s profile." +"{reason}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) borró un comentario en el perfil de {target}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) eliminó un comentario en el perfil de {target}" + +#: extensions/base/curseprofile.py:233 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) purged a comment on [their own]({link}) profile." +"{reason}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) borró un comentario en su propio perfil\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) eliminó un comentario en su propio perfil" + +#: extensions/base/renameuser.py:38 +#, python-brace-format +msgid "Renamed user \"{old_name}\" with {edits} edit to \"{new_name}\"" +msgid_plural "Renamed user \"{old_name}\" with {edits} edits to \"{new_name}\"" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/renameuser.py:43 +#, python-brace-format +msgid "Renamed user \"{old_name}\" to \"{new_name}\"" +msgstr "" + +#: extensions/base/renameuser.py:58 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) renamed user *{old_name}* with {edits} edit to " +"[{new_name}]({link}){comment}" +msgid_plural "" +"[{author}]({author_url}) renamed user *{old_name}* with {edits} edits to " +"[{new_name}]({link}){comment}" +msgstr[0] "[{author}]({author_url}) eliminó [{page}]({page_link}){comment}" +msgstr[1] "[{author}]({author_url}) eliminó [{page}]({page_link}){comment}" + +#: extensions/base/renameuser.py:66 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) renamed user *{old_name}* to [{new_name}]({link})" +"{comment}" +msgstr "[{author}]({author_url}) eliminó [{page}]({page_link}){comment}" + +#: extensions/base/interwiki.py:37 +msgid "Added an entry to the interwiki table" +msgstr "Agregó una entrada a la tabla interwiki" + +#: extensions/base/interwiki.py:38 extensions/base/interwiki.py:65 +#, python-brace-format +msgid "Prefix: {prefix}, website: {website} | {desc}" +msgstr "Prefijo: {prefix}, sitio web: {website} | {desc}" + +#: extensions/base/interwiki.py:50 +#, python-brace-format +msgid "" +"[{author}]({author_url}) added an entry to the [interwiki table]" +"({table_url}) pointing to {website} with {prefix} prefix" +msgstr "" +"[{author}]({author_url}) agregó una entrada a la [tabla interwiki]" +"({table_url}) que apunta a {website} con el prefijo {prefix}" + +#: extensions/base/interwiki.py:64 +#, fuzzy +msgid "Edited an entry in interwiki table" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Editó una entrada en la tabla de interwiki\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Editó una entrada en la tabla interwiki" + +#: extensions/base/interwiki.py:77 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited an entry in [interwiki table]({table_url}) " +"pointing to {website} with {prefix} prefix" +msgstr "" +"[{author}]({author_url}) editó una entrada en la [tabla interwiki]" +"({table_url}) que apunta a {website} con el prefijo {prefix}" + +#: extensions/base/interwiki.py:91 +msgid "Deleted an entry in interwiki table" +msgstr "Eliminó una entrada en la tabla interwiki" + +#: extensions/base/interwiki.py:92 +#, python-brace-format +msgid "Prefix: {prefix} | {desc}" +msgstr "Prefijo: {prefix} | {desc}" + +#: extensions/base/interwiki.py:102 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) deleted an entry in [interwiki table]({table_url})" +"{desc}" +msgstr "" +"[{author}]({author_url}) eliminó una entrada en la [tabla interwiki]" +"({table_url})" + +#: extensions/base/abusefilter.py:29 +#, fuzzy +msgid "None" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Ninguno\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Ninguna" + +#: extensions/base/abusefilter.py:29 +msgid "Warning issued" +msgstr "Advertencia emitida" + +#: extensions/base/abusefilter.py:29 +msgid "**Blocked user**" +msgstr "**Usuario bloqueado**" + +#: extensions/base/abusefilter.py:29 +#, fuzzy +msgid "Tagged the edit" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Etiqueto la edición\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Etiquetó la edición" + +#: extensions/base/abusefilter.py:29 +msgid "Disallowed the action" +msgstr "Anuló la acción" + +#: extensions/base/abusefilter.py:29 +msgid "**IP range blocked**" +msgstr "**Rango de IP bloqueado**" + +#: extensions/base/abusefilter.py:29 +msgid "Throttled actions" +msgstr "Limitó acciones" + +#: extensions/base/abusefilter.py:29 +#, fuzzy +msgid "Removed autoconfirmed group" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Eliminó el grupo autoconfirmado\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Eliminó grupo autoconfirmado" + +#: extensions/base/abusefilter.py:29 +#, fuzzy +msgid "**Removed from privileged groups**" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"**Eliminado de los grupos privilegiados**\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"** Eliminado de los grupos privilegiados **" + +#: extensions/base/abusefilter.py:30 +msgid "Edit" +msgstr "Edición" + +#: extensions/base/abusefilter.py:30 +msgid "Upload" +msgstr "Carga" + +#: extensions/base/abusefilter.py:30 +msgid "Move" +msgstr "Traslado" + +#: extensions/base/abusefilter.py:30 +msgid "Stash upload" +msgstr "Carga de archivos" + +#: extensions/base/abusefilter.py:30 +#, fuzzy +msgid "Deletion" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Borrado\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Eliminación" + +#: extensions/base/abusefilter.py:30 +msgid "Account creation" +msgstr "Creación de cuenta" + +#: extensions/base/abusefilter.py:30 +msgid "Auto account creation" +msgstr "Creación de cuenta automática" + +#: extensions/base/abusefilter.py:54 +#, python-brace-format +msgid "{user} triggered \"{abuse_filter}\"" +msgstr "{user} activó \"{abuse_filter}\"" + +#: extensions/base/abusefilter.py:55 +msgid "Performed" +msgstr "Realizó" + +#: extensions/base/abusefilter.py:56 +msgid "Action taken" +msgstr "Acción tomada" + +#: extensions/base/abusefilter.py:57 +msgid "Title" +msgstr "Título" + +#: extensions/base/abusefilter.py:66 +#, python-brace-format +msgid "" +"[{author}]({author_url}) triggered *{abuse_filter}*, performing the action " +"\"{action}\" on *[{target}]({target_url})* - action taken: {result}." +msgstr "" +"[{author}]({author_url}) activó *{abuse_filter}*, realizando la acción " +"\"{action}\" en *[{target}]({target_url})* - acción tomada: {result}." + +#: extensions/base/abusefilter.py:83 +#, fuzzy, python-brace-format +msgid "Edited abuse filter number {number}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Editó el número de filtro de abuso {number}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Editó el número del filtro de abuso {number}" + +#: extensions/base/abusefilter.py:95 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited abuse filter [number {number}]({filter_url})" +msgstr "" +"[{author}]({author_url}) editó el filtro de abuso [número {number}]" +"({filter_url})" + +#: extensions/base/abusefilter.py:111 +#, fuzzy, python-brace-format +msgid "Created abuse filter number {number}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Creó el filtro de abuso número {number}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Creó el número de filtro de abuso {number}" + +#: extensions/base/abusefilter.py:119 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created abuse filter [number {number}]({filter_url})" +msgstr "" +"[{author}]({author_url}) creó el filtro de abuso [número {number}]" +"({filter_url})" + +#: extensions/base/mediawiki.py:37 +msgid "director" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "bot" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "editor" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "directors" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "sysop" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "bureaucrat" +msgstr "" + +#: extensions/base/mediawiki.py:37 +msgid "reviewer" +msgstr "" + +#: extensions/base/mediawiki.py:38 +msgid "autoreview" +msgstr "" + +#: extensions/base/mediawiki.py:38 +msgid "autopatrol" +msgstr "" + +#: extensions/base/mediawiki.py:38 +msgid "wiki_guardian" +msgstr "" + +#: extensions/base/mediawiki.py:70 +msgid "(N!) " +msgstr "(N!) " + +#: extensions/base/mediawiki.py:71 +msgid "m" +msgstr "m" + +#: extensions/base/mediawiki.py:72 +msgid "b" +msgstr "b" + +#: extensions/base/mediawiki.py:112 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) edited [{article}]({edit_link}){comment} {bold}" +"({sign}{edit_size}){bold}" +msgstr "" +"[{author}]({author_url}) editó [{article}]({edit_link}){comment} ({bold}" +"{sign}{edit_size}{bold})" + +#: extensions/base/mediawiki.py:117 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) created [{article}]({edit_link}){comment} {bold}" +"({sign}{edit_size}){bold}" +msgstr "" +"[{author}]({author_url}) creó [{article}]({edit_link}){comment} ({bold}{sign}" +"{edit_size}{bold})" + +#: extensions/base/mediawiki.py:190 extensions/base/mediawiki.py:223 +msgid "Options" +msgstr "Opciones" + +#: extensions/base/mediawiki.py:190 +#, python-brace-format +msgid "([preview]({link}) | [undo]({undolink}))" +msgstr "([vista previa]({link}) | [deshacer]({undolink}))" + +#: extensions/base/mediawiki.py:195 +#, python-brace-format +msgid "Uploaded a new version of {name}" +msgstr "Subió una nueva versión de {name}" + +#: extensions/base/mediawiki.py:197 +#, python-brace-format +msgid "Reverted a version of {name}" +msgstr "Revirtió una versión de {name}" + +#: extensions/base/mediawiki.py:199 +#, python-brace-format +msgid "Uploaded {name}" +msgstr "Subió {name}" + +#: extensions/base/mediawiki.py:208 +msgid "**No license!**" +msgstr "**¡Sin licencia!**" + +#: extensions/base/mediawiki.py:223 +#, python-brace-format +msgid "([preview]({link}))" +msgstr "([vista previa]({link}))" + +#: extensions/base/mediawiki.py:228 +msgid "" +"\n" +"License: {}" +msgstr "" +"\n" +"Licencia: {}" + +#: extensions/base/mediawiki.py:237 +#, python-brace-format +msgid "" +"[{author}]({author_url}) reverted a version of [{file}]({file_link}){comment}" +msgstr "" +"[{author}]({author_url}) revirtió una versión de [{file}]({file_link})" +"{comment}" + +#: extensions/base/mediawiki.py:248 +#, python-brace-format +msgid "" +"[{author}]({author_url}) uploaded a new version of [{file}]({file_link})" +"{comment}" +msgstr "" +"[{author}]({author_url}) subió una nueva versión de [{file}]({file_link})" +"{comment}" + +#: extensions/base/mediawiki.py:259 +#, python-brace-format +msgid "[{author}]({author_url}) uploaded [{file}]({file_link}){comment}" +msgstr "[{author}]({author_url}) subió [{file}]({file_link}){comment}" + +#: extensions/base/mediawiki.py:274 +#, fuzzy, python-brace-format +msgid "Deleted page {article}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Eliminó la página {article}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Página eliminada {article}" + +#: extensions/base/mediawiki.py:283 +#, python-brace-format +msgid "[{author}]({author_url}) deleted [{page}]({page_link}){comment}" +msgstr "[{author}]({author_url}) eliminó [{page}]({page_link}){comment}" + +#: extensions/base/mediawiki.py:298 +#, fuzzy, python-brace-format +msgid "Deleted redirect {article} by overwriting" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Eliminó la redirección {article} sobrescribiendola\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Eliminó la redirección {article} sobrescribiéndola" + +#: extensions/base/mediawiki.py:308 +#, python-brace-format +msgid "" +"[{author}]({author_url}) deleted redirect by overwriting [{page}]" +"({page_link}){comment}" +msgstr "" +"[{author}]({author_url}) eliminó la redirección al sobrescribir [{page}]" +"({page_link}){comment}" + +#: extensions/base/mediawiki.py:322 +#, python-brace-format +msgid "Restored {article}" +msgstr "Restauró {article}" + +#: extensions/base/mediawiki.py:331 +#, python-brace-format +msgid "[{author}]({author_url}) restored [{article}]({article_url}){comment}" +msgstr "[{author}]({author_url}) restauró [{article}]({article_url}){comment}" + +#: extensions/base/mediawiki.py:348 +#, fuzzy +msgid "Changed visibility of log events" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Cambió la visibilidad del registro de eventos\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Modificó la visibilidad del registro de eventos" + +#: extensions/base/mediawiki.py:356 +#, python-brace-format +msgid "[{author}]({author_url}) changed visibility of log events{comment}" +msgstr "" +"[{author}]({author_url}) cambió la visibilidad del registro de " +"eventos{comment}" + +#: extensions/base/mediawiki.py:370 +#, python-brace-format +msgid "Changed visibility of revision on page {article} " +msgid_plural "Changed visibility of {amount} revisions on page {article} " +msgstr[0] "Modificó la visibilidad de la revisión en la página {article} " +msgstr[1] "" +"Modificó la visibilidad de {amount} revisiones en la página {article} " + +#: extensions/base/mediawiki.py:383 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed visibility of revision on page [{article}]" +"({article_url}){comment}" +msgid_plural "" +"[{author}]({author_url}) changed visibility of {amount} revisions on page " +"[{article}]({article_url}){comment}" +msgstr[0] "" +"[{author}]({author_url}) cambió la visibilidad de la revisión en la página " +"[{article}]({article_url}){comment}" +msgstr[1] "" +"[{author}]({author_url}) cambió la visibilidad de {amount} revisiones en la " +"página [{article}]({article_url}){comment}" + +#: extensions/base/mediawiki.py:399 extensions/base/mediawiki.py:432 +msgid "No redirect has been made" +msgstr "No se ha creado una redirección" + +#: extensions/base/mediawiki.py:400 extensions/base/mediawiki.py:433 +#, fuzzy +msgid "A redirect has been made" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Se ha creado una redirección\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Se creó una redirección" + +#: extensions/base/mediawiki.py:401 +#, python-brace-format +msgid "Moved {redirect}{article} to {target}" +msgstr "Movió {redirect}{article} a {target}" + +#: extensions/base/mediawiki.py:412 extensions/base/mediawiki.py:444 +msgid "without making a redirect" +msgstr "sin crear una redirección" + +#: extensions/base/mediawiki.py:413 extensions/base/mediawiki.py:445 +msgid "with a redirect" +msgstr "con una redirección" + +#: extensions/base/mediawiki.py:416 +#, python-brace-format +msgid "" +"[{author}]({author_url}) moved {redirect}*{article}* to [{target}]" +"({target_url}) {made_a_redirect}{comment}" +msgstr "" +"[{author}]({author_url}) movió {redirect}*{article}* a [{target}]" +"({target_url}) {made_a_redirect}{comment}" + +#: extensions/base/mediawiki.py:434 +#, python-brace-format +msgid "Moved {redirect}{article} to {title} over redirect" +msgstr "Movió {redirect}{article} a {title} sobre la redirección" + +#: extensions/base/mediawiki.py:448 +#, python-brace-format +msgid "" +"[{author}]({author_url}) moved {redirect}*{article}* over redirect to " +"[{target}]({target_url}) {made_a_redirect}{comment}" +msgstr "" +"[{author}]({author_url}) movió {redirect}*{article}* sobre la redirección a " +"[{target}]({target_url}) {made_a_redirect}{comment}" + +#: extensions/base/mediawiki.py:464 +#, python-brace-format +msgid "Moved protection settings from {redirect}{article} to {title}" +msgstr "Movió la configuración de protección de {redirect}{article} a {title}" + +#: extensions/base/mediawiki.py:477 +#, python-brace-format +msgid "" +"[{author}]({author_url}) moved protection settings from {redirect}*{article}" +"* to [{target}]({target_url}){comment}" +msgstr "" +"[{author}]({author_url}) movió la configuración de protección de {redirect}" +"*{article}* a [{target}]({target_url}){comment}" + +#: extensions/base/mediawiki.py:492 +#, fuzzy, python-brace-format +msgid "Protected {target}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Protegió a {target}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Protegió {target}" + +#: extensions/base/mediawiki.py:495 extensions/base/mediawiki.py:510 +#: extensions/base/mediawiki.py:526 extensions/base/mediawiki.py:541 +msgid " [cascading]" +msgstr " [en cascada]" + +#: extensions/base/mediawiki.py:506 +#, python-brace-format +msgid "" +"[{author}]({author_url}) protected [{article}]({article_url}) with the " +"following settings: {settings}{comment}" +msgstr "" +"[{author}]({author_url}) protegió [{article}]({article_url}) con la " +"siguiente configuración: {settings}{comment}" + +#: extensions/base/mediawiki.py:523 +#, fuzzy, python-brace-format +msgid "Changed protection level for {article}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Cambió el nivel de protección de {article}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Modificó el nivel de protección de {article}" + +#: extensions/base/mediawiki.py:537 +#, python-brace-format +msgid "" +"[{author}]({author_url}) modified protection settings of [{article}]" +"({article_url}) to: {settings}{comment}" +msgstr "" +"[{author}]({author_url}) modificó la configuración de protección de " +"[{article}]({article_url}) a: {settings}{comment}" + +#: extensions/base/mediawiki.py:554 +#, fuzzy, python-brace-format +msgid "Removed protection from {article}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Quitó la protección de {article}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Eliminó la protección de {article}" + +#: extensions/base/mediawiki.py:563 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) removed protection from [{article}]({article_url})" +"{comment}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) eliminó la protección de [{article}]({article_url})" +"{comment}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) quitó la protección de [{article}]({article_url})" +"{comment}" + +#: extensions/base/mediawiki.py:572 +#, fuzzy +msgid "for infinity and beyond" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"hasta el fin de nuestros días\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"por toda la eternidad" + +#: extensions/base/mediawiki.py:581 +msgid "for less than a minute" +msgstr "" + +#: extensions/base/mediawiki.py:583 +msgid "year" +msgid_plural "years" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:583 +msgid "day" +msgid_plural "days" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:583 +msgid "hour" +msgid_plural "hours" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:584 +msgid "minute" +msgid_plural "minutes" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:589 +#, python-brace-format +msgid "for {time_number} {time_unit}" +msgstr "" + +#: extensions/base/mediawiki.py:608 +msgid "Blocked from editing the following pages: " +msgstr "Bloqueado de editar las siguientes páginas: " + +#: extensions/base/mediawiki.py:615 extensions/base/mediawiki.py:661 +#, fuzzy +msgid " and namespaces: " +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +" y los espacios de nombres: \n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +" y espacios de nombres: " + +#: extensions/base/mediawiki.py:617 +msgid "Blocked from editing pages on following namespaces: " +msgstr "Bloqueado de editar páginas en los siguientes espacios de nombres: " + +#: extensions/base/mediawiki.py:628 +msgid "Partial block details" +msgstr "Detalles del bloqueo parcial" + +#: extensions/base/mediawiki.py:631 +msgid "Block flags" +msgstr "" + +#: extensions/base/mediawiki.py:633 +#, fuzzy, python-brace-format +msgid "Blocked {blocked_user} {time}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Bloqueó a {blocked_user} {time}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Bloqueado {blocked_user}{time}" + +#: extensions/base/mediawiki.py:653 +msgid " on pages: " +msgstr " en las páginas: " + +#: extensions/base/mediawiki.py:663 +#, fuzzy +msgid " on namespaces: " +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +" en los espacios de nombres: \n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +" en espacios de nombres: " + +#: extensions/base/mediawiki.py:675 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) blocked [{user}]({user_url}) {time}" +"{restriction_desc}{comment}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) bloqueó [{user}]({user_url}) {time}" +"{restriction_desc}{comment}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) bloqueó a [{user}]({user_url}) {time}" +"{restriction_desc}{comment}" + +#: extensions/base/mediawiki.py:693 +#, fuzzy, python-brace-format +msgid "Changed block settings for {blocked_user}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Modificó la configuración de bloqueo de {blocked_user}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Se modificó la configuración de bloqueo de {blocked_user}" + +#: extensions/base/mediawiki.py:703 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed block settings for [{blocked_user}]" +"({user_url}){comment}" +msgstr "" +"[{author}]({author_url}) cambió la configuración de bloqueo de " +"[{blocked_user}]({user_url}){comment}" + +#: extensions/base/mediawiki.py:716 +#, fuzzy, python-brace-format +msgid "Unblocked {blocked_user}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Desbloqueó a {blocked_user}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Desbloqueado {blocked_user}" + +#: extensions/base/mediawiki.py:726 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) unblocked [{blocked_user}]({user_url}){comment}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) desbloqueó [{blocked_user}]({user_url}){comment}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) desbloqueó a [{blocked_user}]({user_url}){comment}" + +#: extensions/base/mediawiki.py:742 +msgid "Action has been hidden by administration" +msgstr "La administración ha ocultado la acción" + +#: extensions/base/mediawiki.py:749 +msgid "An action has been hidden by administration." +msgstr "La administración ha ocultado una acción." + +#: extensions/base/mediawiki.py:760 +#, python-brace-format +msgid "Imported {article} with {count} revision" +msgid_plural "Imported {article} with {count} revisions" +msgstr[0] "Importó {article} con {count} revisión" +msgstr[1] "Importó {article} con {count} revisiones" + +#: extensions/base/mediawiki.py:771 +#, python-brace-format +msgid "" +"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " +"revision{comment}" +msgid_plural "" +"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " +"revisions{comment}" +msgstr[0] "" +"[{author}]({author_url}) importó [{article}]({article_url}) con {count} " +"revisión{comment}" +msgstr[1] "" +"[{author}]({author_url}) importó [{article}]({article_url}) con {count} " +"revisiones{comment}" + +#: extensions/base/mediawiki.py:787 +#, fuzzy, python-brace-format +msgid "Imported {article} with {count} revision from \"{source}\"" +msgid_plural "Imported {article} with {count} revisions from \"{source}\"" +msgstr[0] "Importó {article} con {count} revisión" +msgstr[1] "Importó {article} con {count} revisiones" + +#: extensions/base/mediawiki.py:802 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " +"revision from [{source}]({source_url}){comment}" +msgid_plural "" +"[{author}]({author_url}) imported [{article}]({article_url}) with {count} " +"revisions from [{source}]({source_url}){comment}" +msgstr[0] "" +"[{author}]({author_url}) importó [{article}]({article_url}) con {count} " +"revisión{comment}" +msgstr[1] "" +"[{author}]({author_url}) importó [{article}]({article_url}) con {count} " +"revisiones{comment}" + +#: extensions/base/mediawiki.py:817 +#, python-brace-format +msgid " (until {date_and_time})" +msgstr "" + +#: extensions/base/mediawiki.py:834 +#, fuzzy, python-brace-format +msgid "Changed group membership for {target}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Cambió la membresía del grupo para {target}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Modificó el grupo de {target}" + +#: extensions/base/mediawiki.py:836 +msgid "System" +msgstr "Sistema" + +#: extensions/base/mediawiki.py:837 +#, python-brace-format +msgid "{target} got autopromoted to a new usergroup" +msgstr "{target} obtuvo una promoción automática a un nuevo grupo de usuarios" + +#: extensions/base/mediawiki.py:843 +#, fuzzy +msgid "Added group" +msgid_plural "Added groups" +msgstr[0] "Eliminado" +msgstr[1] "Eliminado" + +#: extensions/base/mediawiki.py:845 +#, fuzzy +msgid "Removed group" +msgid_plural "Removed groups" +msgstr[0] "Eliminado" +msgstr[1] "Eliminado" + +#: extensions/base/mediawiki.py:859 +#, python-brace-format +msgid "Added to {added} and removed from {removed}." +msgstr "" + +#: extensions/base/mediawiki.py:860 extensions/base/mediawiki.py:862 +#: extensions/base/mediawiki.py:864 extensions/base/mediawiki.py:871 +msgid ", " +msgstr "" + +#: extensions/base/mediawiki.py:862 +#, python-brace-format +msgid "Added to {added}." +msgstr "" + +#: extensions/base/mediawiki.py:864 +#, fuzzy, python-brace-format +msgid "Removed from {removed}." +msgstr "Eliminado" + +#: extensions/base/mediawiki.py:865 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) changed group membership for [{target}]" +"({target_url}): {group_changes}{comment}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) cambió la pertenencia al grupo de [{target}]" +"({target_url}) de {old_groups} a {new_groups}{comment}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) cambió el grupo de [{target}]({target_url}) de " +"{old_groups} a {new_groups}{comment}" + +#: extensions/base/mediawiki.py:869 +#, fuzzy, python-brace-format +msgid "The system autopromoted [{target}]({target_url}) to {added}.{comment}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"{author} promovió automáticamente a [{target}]({target_url}) de {old_groups} " +"a {new_groups}{comment}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"{author} promovió automáticamente [{target}]({target_url}) de {old_groups} a " +"{new_groups}{comment}" + +#: extensions/base/mediawiki.py:882 +#, python-brace-format +msgid "Merged revision histories of {article} into {dest}" +msgstr "Fusionó los historiales de revisión de {article} en {dest}" + +#: extensions/base/mediawiki.py:896 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) merged revision histories of [{article}]" +"({article_url}) into [{dest}]({dest_url}){comment}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) fusionó los historiales de revisión de [{article}]" +"({article_url}) con [{dest}]({dest_url}){comment}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"[{author}]({author_url}) fusionó los historiales de revisión de [{article}]" +"({article_url}) en [{dest}]({dest_url}){comment}" + +#: extensions/base/mediawiki.py:910 +#, fuzzy +msgid "Created account automatically" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Creó la cuenta automáticamente\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Creó una cuenta automáticamente" + +#: extensions/base/mediawiki.py:917 +#, python-brace-format +msgid "Account [{author}]({author_url}) was created automatically" +msgstr "La cuenta [{author}]({author_url}) se creó automáticamente" + +#: extensions/base/mediawiki.py:930 extensions/base/mediawiki.py:995 +#, fuzzy +msgid "Created account" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Creó la cuenta\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Creó una cuenta" + +#: extensions/base/mediawiki.py:937 extensions/base/mediawiki.py:1002 +#, python-brace-format +msgid "Account [{author}]({author_url}) was created" +msgstr "Se creó la cuenta [{author}]({author_url})" + +#: extensions/base/mediawiki.py:949 +#, python-brace-format +msgid "Created account {article}" +msgstr "Creó la cuenta {article}" + +#: extensions/base/mediawiki.py:958 +#, python-brace-format +msgid "" +"Account [{article}]({article_url}) was created by [{author}]({author_url})" +"{comment}" +msgstr "" +"La cuenta [{article}]({article_url}) fue creada por [{author}]({author_url})" +"{comment}" + +#: extensions/base/mediawiki.py:971 +#, python-brace-format +msgid "Created account {article} and password was sent by email" +msgstr "" +"Creó la cuenta {article} y la contraseña se envió por correo electrónico" + +#: extensions/base/mediawiki.py:982 +#, python-brace-format +msgid "" +"Account [{article}]({article_url}) was created by [{author}]({author_url}) " +"and password was sent by email{comment}" +msgstr "" +"La cuenta [{article}]({article_url}) fue creada por [{author}]({author_url}) " +"y la contraseña se envió por correo electrónico{comment}" + +#: extensions/base/mediawiki.py:1014 +#, fuzzy, python-brace-format +msgid "Changed the content model of the page {article}" +msgstr "" +"#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +"Modificó el modelo de contenido de la página {article}\n" +"#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +"Cambió el modelo de contenido de la página {article}" + +#: extensions/base/mediawiki.py:1016 +#, python-brace-format +msgid "Model changed from {old} to {new}: {reason}" +msgstr "El modelo cambió de {old} a {new}: {reason}" + +#: extensions/base/mediawiki.py:1028 +#, python-brace-format +msgid "" +"[{author}]({author_url}) changed the content model of the page [{article}]" +"({article_url}) from {old} to {new}{comment}" +msgstr "" +"[{author}]({author_url}) cambió el modelo de contenido de la página " +"[{article}]({article_url}) de {old} a {new}{comment}" + +#: extensions/base/mediawiki.py:1043 +#, python-brace-format +msgid "Created the page {article} using a non-default content model" +msgstr "" + +#: extensions/base/mediawiki.py:1045 +#, fuzzy, python-brace-format +msgid "Created with model {new}: {reason}" +msgstr "El modelo cambió de {old} a {new}: {reason}" + +#: extensions/base/mediawiki.py:1056 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) created the page [{article}]({article_url}) using a " +"non-default content model {new}{comment}" +msgstr "" +"[{author}]({author_url}) cambió el modelo de contenido de la página " +"[{article}]({article_url}) de {old} a {new}{comment}" + +#: extensions/base/mediawiki.py:1071 +#, fuzzy, python-brace-format +msgid "Created the tag \"{tag}\"" +msgstr "Creó una etiqueta \"{tag}\"" + +#: extensions/base/mediawiki.py:1081 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) created the [tag]({tag_url}) \"{tag}\"{comment}" +msgstr "[{author}]({author_url}) creó una [etiqueta]({tag_url}) \"{tag}\"" + +#: extensions/base/mediawiki.py:1102 +#, fuzzy, python-brace-format +msgid "Deleted the tag \"{tag}\"" +msgstr "Eliminó una etiqueta \"{tag}\"" + +#: extensions/base/mediawiki.py:1104 +#, fuzzy +msgid "Removed from" +msgstr "Eliminado" + +#: extensions/base/mediawiki.py:1104 +msgid "{} revision or log entry" +msgid_plural "{} revisions and/or log entries" +msgstr[0] "" +msgstr[1] "" + +#: extensions/base/mediawiki.py:1117 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\"{comment}" +msgstr "[{author}]({author_url}) eliminó una [etiqueta]({tag_url}) \"{tag}\"" + +#: extensions/base/mediawiki.py:1127 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\" and removed " +"it from {count} revision or log entry{comment}" +msgid_plural "" +"[{author}]({author_url}) deleted the [tag]({tag_url}) \"{tag}\" and removed " +"it from {count} revisions and/or log entries{comment}" +msgstr[0] "" +"[{author}]({author_url}) importó [{article}]({article_url}) con {count} " +"revisión{comment}" +msgstr[1] "" +"[{author}]({author_url}) importó [{article}]({article_url}) con {count} " +"revisiones{comment}" + +#: extensions/base/mediawiki.py:1144 +#, fuzzy, python-brace-format +msgid "Activated the tag \"{tag}\"" +msgstr "Activó una etiqueta \"{tag}\"" + +#: extensions/base/mediawiki.py:1153 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) activated the [tag]({tag_url}) \"{tag}\"{comment}" +msgstr "[{author}]({author_url}) activó una [etiqueta]({tag_url}) \"{tag}\"" + +#: extensions/base/mediawiki.py:1172 +#, fuzzy, python-brace-format +msgid "Deactivated the tag \"{tag}\"" +msgstr "Desactivó una etiqueta \"{tag}\"" + +#: extensions/base/mediawiki.py:1181 +#, fuzzy, python-brace-format +msgid "" +"[{author}]({author_url}) deactivated the [tag]({tag_url}) \"{tag}\"{comment}" +msgstr "[{author}]({author_url}) desactivó una [etiqueta]({tag_url}) \"{tag}\"" + +#: extensions/base/sprite.py:37 +#, python-brace-format +msgid "Edited the sprite for {article}" +msgstr "Editó el sprite de {article}" + +#: extensions/base/sprite.py:45 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited the sprite for [{article}]({article_url})" +msgstr "[{author}]({author_url}) editó el sprite de [{article}]({article_url})" + +#: extensions/base/sprite.py:60 +#, python-brace-format +msgid "Created the sprite sheet for {article}" +msgstr "Creó la hoja de sprites de {article}" + +#: extensions/base/sprite.py:68 +#, python-brace-format +msgid "" +"[{author}]({author_url}) created the sprite sheet for [{article}]" +"({article_url})" +msgstr "" +"[{author}]({author_url}) creó la hoja de sprites de [{article}]" +"({article_url})" + +#: extensions/base/sprite.py:79 +#, python-brace-format +msgid "Edited the slice for {article}" +msgstr "Editó el sector de {article}" + +#: extensions/base/sprite.py:86 +#, python-brace-format +msgid "" +"[{author}]({author_url}) edited the slice for [{article}]({article_url})" +msgstr "[{author}]({author_url}) editó el sector de [{article}]({article_url})" + +#, python-brace-format +#~ msgid "for {num} {translated_length}" +#~ msgstr "por {num}{translated_length}" + +#~ msgid "until {}" +#~ msgstr "hasta {}" + +#, python-brace-format +#~ msgid "[{author}]({author_url}) deleted a comment on {target}'s profile" +#~ msgstr "" +#~ "[{author}]({author_url}) eliminó un comentario en el perfil de {target}" + +#, python-brace-format +#~ msgid "[{author}]({author_url}) deleted a comment on their own profile" +#~ msgstr "[{author}]({author_url}) eliminó un comentario en su propio perfil" + +#~ msgid "none" +#~ msgstr "ninguno" + +#, python-brace-format +#~ msgid "[{author}]({author_url}) imported interwiki{comment}" +#~ msgstr "[{author}]({author_url}) importó interwiki{comment}" + +#, python-brace-format +#~ msgid "[{author}]({author_url}) restored a wiki *{wiki_name}* ({comment})" +#~ msgstr "[{author}]({author_url}) restauró un wiki *{wiki_name}* ({comment})" + +#, python-brace-format +#~ msgid "" +#~ "Unknown event `{event}` by [{author}]({author_url}), report it on the " +#~ "[support server](<{support}>)." +#~ msgstr "" +#~ "Evento desconocido `{event}` por [{author}]({author_url}), repórtalo en " +#~ "el [servidor de soporte](<{support}>)." + +#, fuzzy +#~ msgid "No description provided" +#~ msgstr "" +#~ "#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +#~ "No se proporcionó descripción\n" +#~ "#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +#~ "No se proporcionó una descripción" + +#~ msgid "unknown expiry time" +#~ msgstr "tiempo de caducidad desconocido" + +#, python-brace-format +#~ msgid "Groups changed from {old_groups} to {new_groups}{reason}" +#~ msgstr "Los grupos cambiaron de {old_groups} a {new_groups}{reason}" + +#~ msgid "Imported interwiki" +#~ msgstr "Importó interwiki" + +#, python-brace-format +#~ msgid "Restored a \"{wiki}\" wiki" +#~ msgstr "Restauró un wiki \"{wiki}\"" + +#, python-brace-format +#~ msgid "Unknown event `{event}`" +#~ msgstr "Evento desconocido `{event}`" + +#, fuzzy +#~ msgid "Report this on the support server" +#~ msgstr "" +#~ "#-#-#-#-# rcgcdw.po (RcGcDw) #-#-#-#-#\n" +#~ "Reportar esto en el servidor de soporte\n" +#~ "#-#-#-#-# formatters.po (RcGcDw) #-#-#-#-#\n" +#~ "Reporta esto en el servidor de soporte" diff --git a/locale/es/LC_MESSAGES/misc.po b/locale/es/LC_MESSAGES/misc.po index 0651905..360648c 100644 --- a/locale/es/LC_MESSAGES/misc.po +++ b/locale/es/LC_MESSAGES/misc.po @@ -7,11 +7,11 @@ msgid "" msgstr "" "Project-Id-Version: RcGcDw\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-18 14:13+0100\n" +"POT-Creation-Date: 2021-07-11 14:32+0200\n" "PO-Revision-Date: 2020-11-28 22:44+0000\n" "Last-Translator: Tamara Carvallo \n" -"Language-Team: Spanish " -"\n" +"Language-Team: Spanish \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -71,7 +71,7 @@ msgstr "ID de Discord" msgid "Battle.net handle" msgstr "Cuenta en Battle.net" -#: src/misc.py:114 +#: src/misc.py:139 msgid "" "\n" "__And more__" @@ -79,10 +79,10 @@ msgstr "" "\n" "__Y más__" -#: src/misc.py:271 +#: src/misc.py:328 msgid "Unknown" msgstr "Desconocido" -#: src/misc.py:273 +#: src/misc.py:330 msgid "unknown" msgstr "desconocido" diff --git a/locale/es/LC_MESSAGES/rc.po b/locale/es/LC_MESSAGES/rc.po index ebfdcb9..b52ab93 100644 --- a/locale/es/LC_MESSAGES/rc.po +++ b/locale/es/LC_MESSAGES/rc.po @@ -7,11 +7,11 @@ msgid "" msgstr "" "Project-Id-Version: RcGcDw\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-18 14:13+0100\n" +"POT-Creation-Date: 2021-04-14 16:24+0200\n" "PO-Revision-Date: 2020-12-06 14:17+0000\n" "Last-Translator: Tamara Carvallo \n" -"Language-Team: Spanish " -"\n" +"Language-Team: Spanish \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,24 +19,24 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.2.1\n" -#: src/rc.py:319 +#: src/rc.py:322 #, python-brace-format msgid "{wiki} seems to be down or unreachable." msgstr "{wiki} parece estar caído o no alcanzable." -#: src/rc.py:320 src/rc.py:332 +#: src/rc.py:323 src/rc.py:335 msgid "Connection status" msgstr "Estado de la conexión" -#: src/rc.py:330 +#: src/rc.py:333 #, python-brace-format msgid "Connection to {wiki} seems to be stable now." msgstr "La conexión a {wiki} parece estar estable ahora." -#: src/rc.py:401 +#: src/rc.py:404 msgid "~~hidden~~" msgstr "~~oculto~~" -#: src/rc.py:405 +#: src/rc.py:408 msgid "hidden" msgstr "oculto" diff --git a/locale/es/LC_MESSAGES/rc_formatters.mo b/locale/es/LC_MESSAGES/rc_formatters.mo deleted file mode 100644 index d25e423..0000000 Binary files a/locale/es/LC_MESSAGES/rc_formatters.mo and /dev/null differ diff --git a/locale/es/LC_MESSAGES/rcgcdw.po b/locale/es/LC_MESSAGES/rcgcdw.po index e25bbf0..09b0718 100644 --- a/locale/es/LC_MESSAGES/rcgcdw.po +++ b/locale/es/LC_MESSAGES/rcgcdw.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: RcGcDw\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-18 14:13+0100\n" +"POT-Creation-Date: 2021-07-11 14:32+0200\n" "PO-Revision-Date: 2021-01-22 13:58+0000\n" "Last-Translator: Tamara Carvallo \n" "Language-Team: Spanish