diff --git a/.env.dev.example b/.env.dev.example index 1e4fb981..9a4366e0 100644 --- a/.env.dev.example +++ b/.env.dev.example @@ -36,7 +36,7 @@ FLOWER_PORT=8888 #FLOWER_USER=mouse #FLOWER_PASSWORD=changeme -EMAIL_HOST="smtp.mailgun.org" +EMAIL_HOST=smtp.mailgun.org EMAIL_PORT=587 EMAIL_HOST_USER=mail@your.domain.here EMAIL_HOST_PASSWORD=emailpassword123 diff --git a/.env.prod.example b/.env.prod.example index 49729d53..56f52a28 100644 --- a/.env.prod.example +++ b/.env.prod.example @@ -36,7 +36,7 @@ FLOWER_PORT=8888 FLOWER_USER=mouse FLOWER_PASSWORD=changeme -EMAIL_HOST="smtp.mailgun.org" +EMAIL_HOST=smtp.mailgun.org EMAIL_PORT=587 EMAIL_HOST_USER=mail@your.domain.here EMAIL_HOST_PASSWORD=emailpassword123 diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 4896e07d..e1a52d26 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -7,7 +7,7 @@ from django.utils import timezone from bookwyrm import models from bookwyrm.redis_store import RedisStore, r -from bookwyrm.tasks import app +from bookwyrm.tasks import app, LOW, MEDIUM, HIGH class ActivityStream(RedisStore): @@ -277,7 +277,18 @@ def add_status_on_create(sender, instance, created, *args, **kwargs): def add_status_on_create_command(sender, instance, created): """runs this code only after the database commit completes""" - add_status_task.delay(instance.id, increment_unread=created) + priority = HIGH + # check if this is an old status, de-prioritize if so + # (this will happen if federation is very slow, or, more expectedly, on csv import) + one_day = 60 * 60 * 24 + if (instance.created_date - instance.published_date).seconds > one_day: + priority = LOW + + add_status_task.apply_async( + args=(instance.id,), + kwargs={"increment_unread": created}, + queue=priority, + ) if sender == models.Boost: handle_boost_task.delay(instance.id) @@ -409,7 +420,7 @@ def remove_statuses_on_unshelve(sender, instance, *args, **kwargs): # ---- TASKS -@app.task(queue="low_priority") +@app.task(queue=LOW) def add_book_statuses_task(user_id, book_id): """add statuses related to a book on shelve""" user = models.User.objects.get(id=user_id) @@ -417,7 +428,7 @@ def add_book_statuses_task(user_id, book_id): BooksStream().add_book_statuses(user, book) -@app.task(queue="low_priority") +@app.task(queue=LOW) def remove_book_statuses_task(user_id, book_id): """remove statuses about a book from a user's books feed""" user = models.User.objects.get(id=user_id) @@ -425,7 +436,7 @@ def remove_book_statuses_task(user_id, book_id): BooksStream().remove_book_statuses(user, book) -@app.task(queue="medium_priority") +@app.task(queue=MEDIUM) def populate_stream_task(stream, user_id): """background task for populating an empty activitystream""" user = models.User.objects.get(id=user_id) @@ -433,7 +444,7 @@ def populate_stream_task(stream, user_id): stream.populate_streams(user) -@app.task(queue="medium_priority") +@app.task(queue=MEDIUM) def remove_status_task(status_ids): """remove a status from any stream it might be in""" # this can take an id or a list of ids @@ -446,7 +457,7 @@ def remove_status_task(status_ids): stream.remove_object_from_related_stores(status) -@app.task(queue="high_priority") +@app.task(queue=HIGH) def add_status_task(status_id, increment_unread=False): """add a status to any stream it should be in""" status = models.Status.objects.get(id=status_id) @@ -458,7 +469,7 @@ def add_status_task(status_id, increment_unread=False): stream.add_status(status, increment_unread=increment_unread) -@app.task(queue="medium_priority") +@app.task(queue=MEDIUM) def remove_user_statuses_task(viewer_id, user_id, stream_list=None): """remove all statuses by a user from a viewer's stream""" stream_list = [streams[s] for s in stream_list] if stream_list else streams.values() @@ -468,7 +479,7 @@ def remove_user_statuses_task(viewer_id, user_id, stream_list=None): stream.remove_user_statuses(viewer, user) -@app.task(queue="medium_priority") +@app.task(queue=MEDIUM) def add_user_statuses_task(viewer_id, user_id, stream_list=None): """add all statuses by a user to a viewer's stream""" stream_list = [streams[s] for s in stream_list] if stream_list else streams.values() @@ -478,7 +489,7 @@ def add_user_statuses_task(viewer_id, user_id, stream_list=None): stream.add_user_statuses(viewer, user) -@app.task(queue="medium_priority") +@app.task(queue=MEDIUM) def handle_boost_task(boost_id): """remove the original post and other, earlier boosts""" instance = models.Status.objects.get(id=boost_id) diff --git a/bookwyrm/book_search.py b/bookwyrm/book_search.py index 6c89b61f..e42a6d8c 100644 --- a/bookwyrm/book_search.py +++ b/bookwyrm/book_search.py @@ -82,6 +82,8 @@ def search_identifiers(query, *filters, return_first=False): *filters, reduce(operator.or_, (Q(**f) for f in or_filters)) ).distinct() if results.count() <= 1: + if return_first: + return results.first() return results # when there are multiple editions of the same work, pick the default. @@ -124,6 +126,7 @@ def search_title_author(query, min_confidence, *filters, return_first=False): result = default else: result = editions.first() + if return_first: return result list_results.append(result) diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index 298f73da..847ca05c 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -201,12 +201,18 @@ class EditionForm(CustomForm): class AuthorForm(CustomForm): class Meta: model = models.Author - exclude = [ - "remote_id", - "origin_id", - "created_date", - "updated_date", - "search_vector", + fields = [ + "last_edited_by", + "name", + "aliases", + "bio", + "wikipedia_link", + "born", + "died", + "openlibrary_key", + "inventaire_id", + "librarything_key", + "goodreads_key", ] diff --git a/bookwyrm/importers/goodreads_import.py b/bookwyrm/importers/goodreads_import.py index c62e6582..c0dc0ea2 100644 --- a/bookwyrm/importers/goodreads_import.py +++ b/bookwyrm/importers/goodreads_import.py @@ -7,10 +7,3 @@ class GoodreadsImporter(Importer): For a more complete example of overriding see librarything_import.py""" service = "Goodreads" - - def parse_fields(self, entry): - """handle the specific fields in goodreads csvs""" - entry.update({"import_source": self.service}) - # add missing 'Date Started' field - entry.update({"Date Started": None}) - return entry diff --git a/bookwyrm/importers/importer.py b/bookwyrm/importers/importer.py index 6d898a2a..94e6734e 100644 --- a/bookwyrm/importers/importer.py +++ b/bookwyrm/importers/importer.py @@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _ from bookwyrm import models from bookwyrm.models import ImportJob, ImportItem -from bookwyrm.tasks import app +from bookwyrm.tasks import app, LOW logger = logging.getLogger(__name__) @@ -15,33 +15,90 @@ logger = logging.getLogger(__name__) class Importer: """Generic class for csv data import from an outside service""" - service = "Unknown" + service = "Import" delimiter = "," encoding = "UTF-8" - mandatory_fields = ["Title", "Author"] + + # these are from Goodreads + row_mappings_guesses = [ + ("id", ["id", "book id"]), + ("title", ["title"]), + ("authors", ["author", "authors", "primary author"]), + ("isbn_10", ["isbn10", "isbn"]), + ("isbn_13", ["isbn13", "isbn", "isbns"]), + ("shelf", ["shelf", "exclusive shelf", "read status"]), + ("review_name", ["review name"]), + ("review_body", ["my review", "review"]), + ("rating", ["my rating", "rating", "star rating"]), + ("date_added", ["date added", "entry date", "added"]), + ("date_started", ["date started", "started"]), + ("date_finished", ["date finished", "last date read", "date read", "finished"]), + ] + date_fields = ["date_added", "date_started", "date_finished"] + shelf_mapping_guesses = { + "to-read": ["to-read"], + "read": ["read"], + "reading": ["currently-reading", "reading"], + } def create_job(self, user, csv_file, include_reviews, privacy): """check over a csv and creates a database entry for the job""" + csv_reader = csv.DictReader(csv_file, delimiter=self.delimiter) + rows = enumerate(list(csv_reader)) job = ImportJob.objects.create( - user=user, include_reviews=include_reviews, privacy=privacy + user=user, + include_reviews=include_reviews, + privacy=privacy, + mappings=self.create_row_mappings(csv_reader.fieldnames), + source=self.service, ) - for index, entry in enumerate( - list(csv.DictReader(csv_file, delimiter=self.delimiter)) - ): - if not all(x in entry for x in self.mandatory_fields): - raise ValueError("Author and title must be in data.") - entry = self.parse_fields(entry) - self.save_item(job, index, entry) + + for index, entry in rows: + self.create_item(job, index, entry) return job - def save_item(self, job, index, data): # pylint: disable=no-self-use - """creates and saves an import item""" - ImportItem(job=job, index=index, data=data).save() + def update_legacy_job(self, job): + """patch up a job that was in the old format""" + items = job.items + headers = list(items.first().data.keys()) + job.mappings = self.create_row_mappings(headers) + job.updated_date = timezone.now() + job.save() - def parse_fields(self, entry): - """updates csv data with additional info""" - entry.update({"import_source": self.service}) - return entry + for item in items.all(): + normalized = self.normalize_row(item.data, job.mappings) + normalized["shelf"] = self.get_shelf(normalized) + item.normalized_data = normalized + item.save() + + def create_row_mappings(self, headers): + """guess what the headers mean""" + mappings = {} + for (key, guesses) in self.row_mappings_guesses: + value = [h for h in headers if h.lower() in guesses] + value = value[0] if len(value) else None + if value: + headers.remove(value) + mappings[key] = value + return mappings + + def create_item(self, job, index, data): + """creates and saves an import item""" + normalized = self.normalize_row(data, job.mappings) + normalized["shelf"] = self.get_shelf(normalized) + ImportItem(job=job, index=index, data=data, normalized_data=normalized).save() + + def get_shelf(self, normalized_row): + """determine which shelf to use""" + shelf_name = normalized_row["shelf"] + shelf = [ + s for (s, gs) in self.shelf_mapping_guesses.items() if shelf_name in gs + ] + return shelf[0] if shelf else None + + def normalize_row(self, entry, mappings): # pylint: disable=no-self-use + """use the dataclass to create the formatted row of data""" + return {k: entry.get(v) for k, v in mappings.items()} def create_retry_job(self, user, original_job, items): """retry items that didn't import""" @@ -49,55 +106,65 @@ class Importer: user=user, include_reviews=original_job.include_reviews, privacy=original_job.privacy, + # TODO: allow users to adjust mappings + mappings=original_job.mappings, retry=True, ) for item in items: - self.save_item(job, item.index, item.data) + # this will re-normalize the raw data + self.create_item(job, item.index, item.data) return job - def start_import(self, job): + def start_import(self, job): # pylint: disable=no-self-use """initalizes a csv import job""" - result = import_data.delay(self.service, job.id) + result = start_import_task.delay(job.id) job.task_id = result.id job.save() @app.task(queue="low_priority") -def import_data(source, job_id): - """does the actual lookup work in a celery task""" +def start_import_task(job_id): + """trigger the child tasks for each row""" job = ImportJob.objects.get(id=job_id) + # these are sub-tasks so that one big task doesn't use up all the memory in celery + for item in job.items.values_list("id", flat=True).all(): + import_item_task.delay(item) + + +@app.task(queue="low_priority") +def import_item_task(item_id): + """resolve a row into a book""" + item = models.ImportItem.objects.get(id=item_id) try: - for item in job.items.all(): - try: - item.resolve() - except Exception as err: # pylint: disable=broad-except - logger.exception(err) - item.fail_reason = _("Error loading book") - item.save() - continue + item.resolve() + except Exception as err: # pylint: disable=broad-except + item.fail_reason = _("Error loading book") + item.save() + item.update_job() + raise err - if item.book or item.book_guess: - item.save() + if item.book: + # shelves book and handles reviews + handle_imported_book(item) + else: + item.fail_reason = _("Could not find a match for book") - if item.book: - # shelves book and handles reviews - handle_imported_book( - source, job.user, item, job.include_reviews, job.privacy - ) - else: - item.fail_reason = _("Could not find a match for book") - item.save() - finally: - job.complete = True - job.save() + item.save() + item.update_job() -def handle_imported_book(source, user, item, include_reviews, privacy): +def handle_imported_book(item): """process a csv and then post about it""" + job = item.job + user = job.user if isinstance(item.book, models.Work): item.book = item.book.default_edition if not item.book: + item.fail_reason = _("Error loading book") + item.save() return + if not isinstance(item.book, models.Edition): + item.book = item.book.edition existing_shelf = models.ShelfBook.objects.filter(book=item.book, user=user).exists() @@ -105,9 +172,9 @@ def handle_imported_book(source, user, item, include_reviews, privacy): if item.shelf and not existing_shelf: desired_shelf = models.Shelf.objects.get(identifier=item.shelf, user=user) shelved_date = item.date_added or timezone.now() - models.ShelfBook.objects.create( + models.ShelfBook( book=item.book, shelf=desired_shelf, user=user, shelved_date=shelved_date - ) + ).save(priority=LOW) for read in item.reads: # check for an existing readthrough with the same dates @@ -122,35 +189,52 @@ def handle_imported_book(source, user, item, include_reviews, privacy): read.user = user read.save() - if include_reviews and (item.rating or item.review): + if job.include_reviews and (item.rating or item.review) and not item.linked_review: # we don't know the publication date of the review, # but "now" is a bad guess published_date_guess = item.date_read or item.date_added if item.review: # pylint: disable=consider-using-f-string - review_title = ( - "Review of {!r} on {!r}".format( - item.book.title, - source, - ) - if item.review - else "" + review_title = "Review of {!r} on {!r}".format( + item.book.title, + job.source, ) - models.Review.objects.create( + review = models.Review.objects.filter( user=user, book=item.book, name=review_title, - content=item.review, rating=item.rating, published_date=published_date_guess, - privacy=privacy, - ) + ).first() + if not review: + review = models.Review( + user=user, + book=item.book, + name=review_title, + content=item.review, + rating=item.rating, + published_date=published_date_guess, + privacy=job.privacy, + ) + review.save(software="bookwyrm", priority=LOW) else: # just a rating - models.ReviewRating.objects.create( + review = models.ReviewRating.objects.filter( user=user, book=item.book, - rating=item.rating, published_date=published_date_guess, - privacy=privacy, - ) + rating=item.rating, + ).first() + if not review: + review = models.ReviewRating( + user=user, + book=item.book, + rating=item.rating, + published_date=published_date_guess, + privacy=job.privacy, + ) + review.save(software="bookwyrm", priority=LOW) + + # only broadcast this review to other bookwyrm instances + item.linked_review = review + item.save() diff --git a/bookwyrm/importers/librarything_import.py b/bookwyrm/importers/librarything_import.py index b3175a82..1b61a6f1 100644 --- a/bookwyrm/importers/librarything_import.py +++ b/bookwyrm/importers/librarything_import.py @@ -1,7 +1,5 @@ -""" handle reading a csv from librarything """ +""" handle reading a tsv from librarything """ import re -import math - from . import Importer @@ -11,32 +9,18 @@ class LibrarythingImporter(Importer): service = "LibraryThing" delimiter = "\t" encoding = "ISO-8859-1" - # mandatory_fields : fields matching the book title and author - mandatory_fields = ["Title", "Primary Author"] - def parse_fields(self, entry): - """custom parsing for librarything""" - data = {} - data["import_source"] = self.service - data["Book Id"] = entry["Book Id"] - data["Title"] = entry["Title"] - data["Author"] = entry["Primary Author"] - data["ISBN13"] = entry["ISBN"] - data["My Review"] = entry["Review"] - if entry["Rating"]: - data["My Rating"] = math.ceil(float(entry["Rating"])) - else: - data["My Rating"] = "" - data["Date Added"] = re.sub(r"\[|\]", "", entry["Entry Date"]) - data["Date Started"] = re.sub(r"\[|\]", "", entry["Date Started"]) - data["Date Read"] = re.sub(r"\[|\]", "", entry["Date Read"]) + def normalize_row(self, entry, mappings): # pylint: disable=no-self-use + """use the dataclass to create the formatted row of data""" + remove_brackets = lambda v: re.sub(r"\[|\]", "", v) if v else None + normalized = {k: remove_brackets(entry.get(v)) for k, v in mappings.items()} + isbn_13 = normalized["isbn_13"].split(", ") + normalized["isbn_13"] = isbn_13[1] if len(isbn_13) > 0 else None + return normalized - data["Exclusive Shelf"] = None - if data["Date Read"]: - data["Exclusive Shelf"] = "read" - elif data["Date Started"]: - data["Exclusive Shelf"] = "reading" - else: - data["Exclusive Shelf"] = "to-read" - - return data + def get_shelf(self, normalized_row): + if normalized_row["date_finished"]: + return "read" + if normalized_row["date_started"]: + return "reading" + return "to-read" diff --git a/bookwyrm/importers/storygraph_import.py b/bookwyrm/importers/storygraph_import.py index 25498432..9368115d 100644 --- a/bookwyrm/importers/storygraph_import.py +++ b/bookwyrm/importers/storygraph_import.py @@ -1,7 +1,4 @@ -""" handle reading a csv from librarything """ -import re -import math - +""" handle reading a csv from storygraph""" from . import Importer @@ -9,26 +6,3 @@ class StorygraphImporter(Importer): """csv downloads from librarything""" service = "Storygraph" - # mandatory_fields : fields matching the book title and author - mandatory_fields = ["Title"] - - def parse_fields(self, entry): - """custom parsing for storygraph""" - data = {} - data["import_source"] = self.service - data["Title"] = entry["Title"] - data["Author"] = entry["Authors"] if "Authors" in entry else entry["Author"] - data["ISBN13"] = entry["ISBN"] - data["My Review"] = entry["Review"] - if entry["Star Rating"]: - data["My Rating"] = math.ceil(float(entry["Star Rating"])) - else: - data["My Rating"] = "" - - data["Date Added"] = re.sub(r"[/]", "-", entry["Date Added"]) - data["Date Read"] = re.sub(r"[/]", "-", entry["Last Date Read"]) - - data["Exclusive Shelf"] = ( - {"read": "read", "currently-reading": "reading", "to-read": "to-read"} - ).get(entry["Read Status"], None) - return data diff --git a/bookwyrm/migrations/0113_auto_20211110_2104.py b/bookwyrm/migrations/0113_auto_20211110_2104.py new file mode 100644 index 00000000..572ba280 --- /dev/null +++ b/bookwyrm/migrations/0113_auto_20211110_2104.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.5 on 2021-11-10 21:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0112_auto_20211022_0844"), + ] + + operations = [ + migrations.AddField( + model_name="importitem", + name="normalized_data", + field=models.JSONField(default={}), + preserve_default=False, + ), + migrations.AddField( + model_name="importjob", + name="mappings", + field=models.JSONField(default={}), + preserve_default=False, + ), + ] diff --git a/bookwyrm/migrations/0114_importjob_source.py b/bookwyrm/migrations/0114_importjob_source.py new file mode 100644 index 00000000..3ec1432e --- /dev/null +++ b/bookwyrm/migrations/0114_importjob_source.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.5 on 2021-11-13 00:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0113_auto_20211110_2104"), + ] + + operations = [ + migrations.AddField( + model_name="importjob", + name="source", + field=models.CharField(default="Import", max_length=100), + preserve_default=False, + ), + ] diff --git a/bookwyrm/migrations/0115_importitem_linked_review.py b/bookwyrm/migrations/0115_importitem_linked_review.py new file mode 100644 index 00000000..8cff9b8c --- /dev/null +++ b/bookwyrm/migrations/0115_importitem_linked_review.py @@ -0,0 +1,24 @@ +# Generated by Django 3.2.5 on 2021-11-13 19:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0114_importjob_source"), + ] + + operations = [ + migrations.AddField( + model_name="importitem", + name="linked_review", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="bookwyrm.review", + ), + ), + ] diff --git a/bookwyrm/migrations/0116_auto_20211114_1734.py b/bookwyrm/migrations/0116_auto_20211114_1734.py new file mode 100644 index 00000000..1da001bd --- /dev/null +++ b/bookwyrm/migrations/0116_auto_20211114_1734.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.5 on 2021-11-14 17:34 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0115_importitem_linked_review"), + ] + + operations = [ + migrations.RemoveField( + model_name="importjob", + name="task_id", + ), + migrations.AddField( + model_name="importjob", + name="updated_date", + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/bookwyrm/migrations/0117_alter_user_preferred_language.py b/bookwyrm/migrations/0117_alter_user_preferred_language.py new file mode 100644 index 00000000..c892b051 --- /dev/null +++ b/bookwyrm/migrations/0117_alter_user_preferred_language.py @@ -0,0 +1,32 @@ +# Generated by Django 3.2.5 on 2021-11-15 18:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0116_auto_20211114_1734"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="preferred_language", + field=models.CharField( + blank=True, + choices=[ + ("en-us", "English"), + ("de-de", "Deutsch (German)"), + ("es-es", "Español (Spanish)"), + ("fr-fr", "Français (French)"), + ("lt-lt", "lietuvių (Lithuanian)"), + ("pt-br", "Português - Brasil (Brazilian Portuguese)"), + ("zh-hans", "简体中文 (Simplified Chinese)"), + ("zh-hant", "繁體中文 (Traditional Chinese)"), + ], + max_length=255, + null=True, + ), + ), + ] diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index 3a88c524..402cb040 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -20,7 +20,7 @@ from django.utils.http import http_date from bookwyrm import activitypub from bookwyrm.settings import USER_AGENT, PAGE_LENGTH from bookwyrm.signatures import make_signature, make_digest -from bookwyrm.tasks import app +from bookwyrm.tasks import app, MEDIUM from bookwyrm.models.fields import ImageField, ManyToManyField logger = logging.getLogger(__name__) @@ -29,7 +29,6 @@ logger = logging.getLogger(__name__) PropertyField = namedtuple("PropertyField", ("set_activity_from_field")) - # pylint: disable=invalid-name def set_activity_from_property_field(activity, obj, field): """assign a model property value to the activity json""" @@ -126,12 +125,15 @@ class ActivitypubMixin: # there OUGHT to be only one match return match.first() - def broadcast(self, activity, sender, software=None): + def broadcast(self, activity, sender, software=None, queue=MEDIUM): """send out an activity""" - broadcast_task.delay( - sender.id, - json.dumps(activity, cls=activitypub.ActivityEncoder), - self.get_recipients(software=software), + broadcast_task.apply_async( + args=( + sender.id, + json.dumps(activity, cls=activitypub.ActivityEncoder), + self.get_recipients(software=software), + ), + queue=queue, ) def get_recipients(self, software=None): @@ -195,7 +197,7 @@ class ActivitypubMixin: class ObjectMixin(ActivitypubMixin): """add this mixin for object models that are AP serializable""" - def save(self, *args, created=None, **kwargs): + def save(self, *args, created=None, software=None, priority=MEDIUM, **kwargs): """broadcast created/updated/deleted objects as appropriate""" broadcast = kwargs.get("broadcast", True) # this bonus kwarg would cause an error in the base save method @@ -219,15 +221,17 @@ class ObjectMixin(ActivitypubMixin): return try: - software = None # do we have a "pure" activitypub version of this for mastodon? - if hasattr(self, "pure_content"): + if software != "bookwyrm" and hasattr(self, "pure_content"): pure_activity = self.to_create_activity(user, pure=True) - self.broadcast(pure_activity, user, software="other") + self.broadcast( + pure_activity, user, software="other", queue=priority + ) + # set bookwyrm so that that type is also sent software = "bookwyrm" # sends to BW only if we just did a pure version for masto activity = self.to_create_activity(user) - self.broadcast(activity, user, software=software) + self.broadcast(activity, user, software=software, queue=priority) except AttributeError: # janky as heck, this catches the mutliple inheritence chain # for boosts and ignores this auxilliary broadcast @@ -241,8 +245,7 @@ class ObjectMixin(ActivitypubMixin): if isinstance(self, user_model): user = self # book data tracks last editor - elif hasattr(self, "last_edited_by"): - user = self.last_edited_by + user = user or getattr(self, "last_edited_by", None) # again, if we don't know the user or they're remote, don't bother if not user or not user.local: return @@ -252,7 +255,7 @@ class ObjectMixin(ActivitypubMixin): activity = self.to_delete_activity(user) else: activity = self.to_update_activity(user) - self.broadcast(activity, user) + self.broadcast(activity, user, queue=priority) def to_create_activity(self, user, **kwargs): """returns the object wrapped in a Create activity""" @@ -375,9 +378,9 @@ class CollectionItemMixin(ActivitypubMixin): activity_serializer = activitypub.CollectionItem - def broadcast(self, activity, sender, software="bookwyrm"): + def broadcast(self, activity, sender, software="bookwyrm", queue=MEDIUM): """only send book collection updates to other bookwyrm instances""" - super().broadcast(activity, sender, software=software) + super().broadcast(activity, sender, software=software, queue=queue) @property def privacy(self): @@ -396,7 +399,7 @@ class CollectionItemMixin(ActivitypubMixin): return [] return [collection_field.user] - def save(self, *args, broadcast=True, **kwargs): + def save(self, *args, broadcast=True, priority=MEDIUM, **kwargs): """broadcast updated""" # first off, we want to save normally no matter what super().save(*args, **kwargs) @@ -407,7 +410,7 @@ class CollectionItemMixin(ActivitypubMixin): # adding an obj to the collection activity = self.to_add_activity(self.user) - self.broadcast(activity, self.user) + self.broadcast(activity, self.user, queue=priority) def delete(self, *args, broadcast=True, **kwargs): """broadcast a remove activity""" @@ -440,12 +443,12 @@ class CollectionItemMixin(ActivitypubMixin): class ActivityMixin(ActivitypubMixin): """add this mixin for models that are AP serializable""" - def save(self, *args, broadcast=True, **kwargs): + def save(self, *args, broadcast=True, priority=MEDIUM, **kwargs): """broadcast activity""" super().save(*args, **kwargs) user = self.user if hasattr(self, "user") else self.user_subject if broadcast and user.local: - self.broadcast(self.to_activity(), user) + self.broadcast(self.to_activity(), user, queue=priority) def delete(self, *args, broadcast=True, **kwargs): """nevermind, undo that activity""" @@ -502,7 +505,7 @@ def unfurl_related_field(related_field, sort_field=None): return related_field.remote_id -@app.task(queue="medium_priority") +@app.task(queue=MEDIUM) def broadcast_task(sender_id, activity, recipients): """the celery task for broadcast""" user_model = apps.get_model("bookwyrm.User", require_ready=True) diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 8ae75baf..d97a1b8a 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -66,9 +66,10 @@ class BookDataModel(ObjectMixin, BookWyrmModel): self.remote_id = None return super().save(*args, **kwargs) - def broadcast(self, activity, sender, software="bookwyrm"): + # pylint: disable=arguments-differ + def broadcast(self, activity, sender, software="bookwyrm", **kwargs): """only send book data updates to other bookwyrm instances""" - super().broadcast(activity, sender, software=software) + super().broadcast(activity, sender, software=software, **kwargs) class Book(BookDataModel): diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index ccd669cb..36107990 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -3,6 +3,7 @@ from dataclasses import MISSING import imghdr import re from uuid import uuid4 +from urllib.parse import urljoin import dateutil.parser from dateutil.parser import ParserError @@ -13,11 +14,12 @@ from django.db import models from django.forms import ClearableFileInput, ImageField as DjangoImageField from django.utils import timezone from django.utils.translation import gettext_lazy as _ +from django.utils.encoding import filepath_to_uri from bookwyrm import activitypub from bookwyrm.connectors import get_image from bookwyrm.sanitize_html import InputHtmlParser -from bookwyrm.settings import DOMAIN +from bookwyrm.settings import MEDIA_FULL_URL def validate_remote_id(value): @@ -381,17 +383,6 @@ class CustomImageField(DjangoImageField): widget = ClearableFileInputWithWarning -def image_serializer(value, alt): - """helper for serializing images""" - if value and hasattr(value, "url"): - url = value.url - else: - return None - if not url[:4] == "http": - url = f"https://{DOMAIN}{url}" - return activitypub.Document(url=url, name=alt) - - class ImageField(ActivitypubFieldMixin, models.ImageField): """activitypub-aware image field""" @@ -424,7 +415,12 @@ class ImageField(ActivitypubFieldMixin, models.ImageField): activity[key] = formatted def field_to_activity(self, value, alt=None): - return image_serializer(value, alt) + url = get_absolute_url(value) + + if not url: + return None + + return activitypub.Document(url=url, name=alt) def field_from_activity(self, value): image_slug = value @@ -461,6 +457,20 @@ class ImageField(ActivitypubFieldMixin, models.ImageField): ) +def get_absolute_url(value): + """returns an absolute URL for the image""" + name = getattr(value, "name") + if not name: + return None + + url = filepath_to_uri(name) + if url is not None: + url = url.lstrip("/") + url = urljoin(MEDIA_FULL_URL, url) + + return url + + class DateTimeField(ActivitypubFieldMixin, models.DateTimeField): """activitypub-aware datetime field""" diff --git a/bookwyrm/models/import_job.py b/bookwyrm/models/import_job.py index 22253fef..c4679585 100644 --- a/bookwyrm/models/import_job.py +++ b/bookwyrm/models/import_job.py @@ -6,20 +6,14 @@ from django.db import models from django.utils import timezone from bookwyrm.connectors import connector_manager -from bookwyrm.models import ReadThrough, User, Book +from bookwyrm.models import ReadThrough, User, Book, Edition from .fields import PrivacyLevels -# Mapping goodreads -> bookwyrm shelf titles. -GOODREADS_SHELVES = { - "read": "read", - "currently-reading": "reading", - "to-read": "to-read", -} - - def unquote_string(text): """resolve csv quote weirdness""" + if not text: + return None match = re.match(r'="([^"]*)"', text) if match: return match.group(1) @@ -41,14 +35,21 @@ class ImportJob(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) created_date = models.DateTimeField(default=timezone.now) - task_id = models.CharField(max_length=100, null=True) + updated_date = models.DateTimeField(default=timezone.now) include_reviews = models.BooleanField(default=True) + mappings = models.JSONField() complete = models.BooleanField(default=False) + source = models.CharField(max_length=100) privacy = models.CharField( max_length=255, default="public", choices=PrivacyLevels.choices ) retry = models.BooleanField(default=False) + @property + def pending_items(self): + """items that haven't been processed yet""" + return self.items.filter(fail_reason__isnull=True, book__isnull=True) + class ImportItem(models.Model): """a single line of a csv being imported""" @@ -56,6 +57,7 @@ class ImportItem(models.Model): job = models.ForeignKey(ImportJob, on_delete=models.CASCADE, related_name="items") index = models.IntegerField() data = models.JSONField() + normalized_data = models.JSONField() book = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True, blank=True) book_guess = models.ForeignKey( Book, @@ -65,9 +67,26 @@ class ImportItem(models.Model): related_name="book_guess", ) fail_reason = models.TextField(null=True) + linked_review = models.ForeignKey( + "Review", on_delete=models.SET_NULL, null=True, blank=True + ) + + def update_job(self): + """let the job know when the items get work done""" + job = self.job + job.updated_date = timezone.now() + job.save() + if not job.pending_items.exists() and not job.complete: + job.complete = True + job.save(update_fields=["complete"]) def resolve(self): """try various ways to lookup a book""" + # we might be calling this after manually adding the book, + # so no need to do searches + if self.book: + return + if self.isbn: self.book = self.get_book_from_isbn() else: @@ -85,6 +104,10 @@ class ImportItem(models.Model): self.isbn, min_confidence=0.999 ) if search_result: + # it's already in the right format + if isinstance(search_result, Edition): + return search_result + # it's just a search result, book needs to be created # raises ConnectorException return search_result.connector.get_or_create_book(search_result.key) return None @@ -96,6 +119,8 @@ class ImportItem(models.Model): search_term, min_confidence=0.1 ) if search_result: + if isinstance(search_result, Edition): + return (search_result, 1) # raises ConnectorException return ( search_result.connector.get_or_create_book(search_result.key), @@ -106,56 +131,62 @@ class ImportItem(models.Model): @property def title(self): """get the book title""" - return self.data["Title"] + return self.normalized_data.get("title") @property def author(self): - """get the book title""" - return self.data["Author"] + """get the book's authors""" + return self.normalized_data.get("authors") @property def isbn(self): """pulls out the isbn13 field from the csv line data""" - return unquote_string(self.data["ISBN13"]) + return unquote_string(self.normalized_data.get("isbn_13")) or unquote_string( + self.normalized_data.get("isbn_10") + ) @property def shelf(self): """the goodreads shelf field""" - if self.data["Exclusive Shelf"]: - return GOODREADS_SHELVES.get(self.data["Exclusive Shelf"]) - return None + return self.normalized_data.get("shelf") @property def review(self): """a user-written review, to be imported with the book data""" - return self.data["My Review"] + return self.normalized_data.get("review_body") @property def rating(self): """x/5 star rating for a book""" - if self.data.get("My Rating", None): - return int(self.data["My Rating"]) + if self.normalized_data.get("rating"): + return float(self.normalized_data.get("rating")) return None @property def date_added(self): """when the book was added to this dataset""" - if self.data["Date Added"]: - return timezone.make_aware(dateutil.parser.parse(self.data["Date Added"])) + if self.normalized_data.get("date_added"): + return timezone.make_aware( + dateutil.parser.parse(self.normalized_data.get("date_added")) + ) return None @property def date_started(self): """when the book was started""" - if "Date Started" in self.data and self.data["Date Started"]: - return timezone.make_aware(dateutil.parser.parse(self.data["Date Started"])) + if self.normalized_data.get("date_started"): + return timezone.make_aware( + dateutil.parser.parse(self.normalized_data.get("date_started")) + ) return None @property def date_read(self): """the date a book was completed""" - if self.data["Date Read"]: - return timezone.make_aware(dateutil.parser.parse(self.data["Date Read"])) + if self.normalized_data.get("date_finished"): + return timezone.make_aware( + dateutil.parser.parse(self.normalized_data.get("date_finished")) + ) return None @property @@ -174,7 +205,9 @@ class ImportItem(models.Model): if start_date and start_date is not None and not self.date_read: return [ReadThrough(start_date=start_date)] if self.date_read: - start_date = start_date if start_date < self.date_read else None + start_date = ( + start_date if start_date and start_date < self.date_read else None + ) return [ ReadThrough( start_date=start_date, @@ -185,8 +218,10 @@ class ImportItem(models.Model): def __repr__(self): # pylint: disable=consider-using-f-string - return "<{!r}Item {!r}>".format(self.data["import_source"], self.data["Title"]) + return "<{!r} Item {!r}>".format(self.index, self.normalized_data.get("title")) def __str__(self): # pylint: disable=consider-using-f-string - return "{} by {}".format(self.data["Title"], self.data["Author"]) + return "{} by {}".format( + self.normalized_data.get("title"), self.normalized_data.get("authors") + ) diff --git a/bookwyrm/models/notification.py b/bookwyrm/models/notification.py index 2f1aae4f..417bf759 100644 --- a/bookwyrm/models/notification.py +++ b/bookwyrm/models/notification.py @@ -157,9 +157,12 @@ def notify_user_on_unboost(sender, instance, *args, **kwargs): @receiver(models.signals.post_save, sender=ImportJob) # pylint: disable=unused-argument -def notify_user_on_import_complete(sender, instance, *args, **kwargs): +def notify_user_on_import_complete( + sender, instance, *args, update_fields=None, **kwargs +): """we imported your books! aren't you proud of us""" - if not instance.complete: + update_fields = update_fields or [] + if not instance.complete or "complete" not in update_fields: return Notification.objects.create( user=instance.user, diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 2b395ec8..c7c0a425 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -19,7 +19,6 @@ from bookwyrm.settings import ENABLE_PREVIEW_IMAGES from .activitypub_mixin import ActivitypubMixin, ActivityMixin from .activitypub_mixin import OrderedCollectionPageMixin from .base_model import BookWyrmModel -from .fields import image_serializer from .readthrough import ProgressMode from . import fields @@ -190,15 +189,26 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): if hasattr(activity, "name"): activity.name = self.pure_name activity.type = self.pure_type - activity.attachment = [ - image_serializer(b.cover, b.alt_text) - for b in self.mention_books.all()[:4] - if b.cover - ] - if hasattr(self, "book") and self.book.cover: - activity.attachment.append( - image_serializer(self.book.cover, self.book.alt_text) - ) + book = getattr(self, "book", None) + books = [book] if book else [] + books += list(self.mention_books.all()) + if len(books) == 1 and getattr(books[0], "preview_image", None): + covers = [ + activitypub.Document( + url=fields.get_absolute_url(books[0].preview_image), + name=books[0].alt_text, + ) + ] + else: + covers = [ + activitypub.Document( + url=fields.get_absolute_url(b.cover), + name=b.alt_text, + ) + for b in books + if b and b.cover + ] + activity.attachment = covers return activity def to_activity(self, pure=False): # pylint: disable=arguments-differ diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 44d65cca..d469e6fe 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -166,6 +166,7 @@ LANGUAGES = [ ("de-de", _("Deutsch (German)")), ("es-es", _("Español (Spanish)")), ("fr-fr", _("Français (French)")), + ("lt-lt", _("lietuvių (Lithuanian)")), ("pt-br", _("Português - Brasil (Brazilian Portuguese)")), ("zh-hans", _("简体中文 (Simplified Chinese)")), ("zh-hant", _("繁體中文 (Traditional Chinese)")), diff --git a/bookwyrm/tasks.py b/bookwyrm/tasks.py index b860e018..09e1d267 100644 --- a/bookwyrm/tasks.py +++ b/bookwyrm/tasks.py @@ -9,3 +9,8 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "celerywyrm.settings") app = Celery( "tasks", broker=settings.CELERY_BROKER_URL, backend=settings.CELERY_RESULT_BACKEND ) + +# priorities +LOW = "low_priority" +MEDIUM = "medium_priority" +HIGH = "high_priority" diff --git a/bookwyrm/templates/discover/card-header.html b/bookwyrm/templates/discover/card-header.html index 0eb9a678..8b9f6fc1 100644 --- a/bookwyrm/templates/discover/card-header.html +++ b/bookwyrm/templates/discover/card-header.html @@ -1,10 +1,24 @@ {% load i18n %} {% load utilities %} -{% with user_path=status.user.local_path username=status.user.display_name book_path=status.book.local_poth book_title=book|book_title %} +{% with user_path=status.user.local_path username=status.user.display_name book_path=book.local_path book_title=book|book_title %} {% if status.status_type == 'GeneratedNote' %} - {{ status.content|safe }} + {% if status.content == 'wants to read' %} + {% blocktrans trimmed %} + {{ username }} wants to read {{ book_title }} + {% endblocktrans %} + {% endif %} + {% if status.content == 'finished reading' %} + {% blocktrans trimmed %} + {{ username }} finished reading {{ book_title }} + {% endblocktrans %} + {% endif %} + {% if status.content == 'started reading' %} + {% blocktrans trimmed %} + {{ username }} started reading {{ book_title }} + {% endblocktrans %} + {% endif %} {% elif status.status_type == 'Rating' %} {% blocktrans trimmed %} {{ username }} rated {{ book_title }} diff --git a/bookwyrm/templates/feed/layout.html b/bookwyrm/templates/feed/layout.html index 8d79781b..6e7ec849 100644 --- a/bookwyrm/templates/feed/layout.html +++ b/bookwyrm/templates/feed/layout.html @@ -9,7 +9,7 @@ {% if user.is_authenticated %}
{% trans "There are no books here right now! Try searching for a book to get started" %}
{% else %} diff --git a/bookwyrm/templates/import/import.html b/bookwyrm/templates/import/import.html index 81f0daa5..314a6861 100644 --- a/bookwyrm/templates/import/import.html +++ b/bookwyrm/templates/import/import.html @@ -46,10 +46,10 @@
- {% trans "Import still in progress." %}
-
- {% trans "(Hit reload to update!)" %}
-
+ {% trans "Row" %} + | ++ {% trans "Title" %} + | ++ {% trans "ISBN" %} + | ++ {% trans "Author" %} + | ++ {% trans "Shelf" %} + | ++ {% trans "Review" %} + | + {% block import_cols_headers %} ++ {% trans "Book" %} + | ++ {% trans "Status" %} + | + {% endblock %} +
---|---|---|---|---|---|---|---|
+ + {% trans "Import preview unavailable." %} + + |
+ |||||||
+ {{ item.index }} + | + {% endblock %} ++ {{ item.normalized_data.title }} + | ++ {{ item.isbn|default:'' }} + | ++ {{ item.normalized_data.authors }} + | ++ {{ item.normalized_data.shelf }} + | +
+ {% if item.rating %}
+ {% include 'snippets/stars.html' with rating=item.rating %} + {% endif %} + {% if item.review %} +{{ item.review|truncatechars:100 }} + {% endif %} + {% if item.linked_review %} + {% trans "View imported review" %} + {% endif %} + |
+ {% block import_cols %}
+ + {% if item.book %} + + {% include 'snippets/book_cover.html' with book=item.book cover_class='is-h-s' size='small' %} + + {% endif %} + | +
+ {% if item.book %}
+
+ {% trans "Imported" %}
+
+ {% elif item.fail_reason %}
+
+
+ {% if item.book_guess %}
+ {% trans "Needs manual review" %}
+ {% else %}
+ {{ item.fail_reason }}
+ {% endif %}
+
+ {% else %}
+
+
+ {% trans "Pending" %}
+ {# retry option if an item appears to be hanging #}
+ {% if job.created_date != job.updated_date and inactive_time > 24 %}
+
+ {% endif %}
+
+ {% endif %}
+ |
+ {% endblock %}
+
- Line {{ item.index }}: - {{ item.data.Title }} by - {{ item.data.Author }} -
-- {{ item.fail_reason }}. -
-- {% trans "Book" %} - | -- {% trans "Title" %} - | -- {% trans "Author" %} - | -- | -
---|---|---|---|
- {% if item.book %} - - {% include 'snippets/book_cover.html' with book=item.book cover_class='is-h-s' size='small' %} - - {% endif %} - | -- {{ item.data.Title }} - | -- {{ item.data.Author }} - | -- {% if item.book %} - - {% trans "Imported" %} - - {% endif %} - | -
+ {% trans "Approving a suggestion will permanently add the suggested book to your shelves and associate your reading dates, reviews, and ratings with that book." %} +
++ {% include 'snippets/book_titleby.html' with book=guess %} +
++ {% trans "Re-trying an import can fix missing items in cases such as:" %} +
++ {% trans "Contact your admin or open an issue if you are seeing unexpected failed items." %} +
+(comment on "Test Edition")
', ) self.assertEqual(activity["attachment"][0].type, "Document") - self.assertEqual( - activity["attachment"][0].url, - f"https://{settings.DOMAIN}{self.book.cover.url}", + self.assertTrue( + re.match( + r"https:\/\/your.domain.here\/images\/covers\/test_[A-z0-9]+.jpg", + activity["attachment"][0].url, + ) ) self.assertEqual(activity["attachment"][0].name, "Test Edition") @@ -257,9 +262,11 @@ class Status(TestCase): f'a sickening sense test content', ) self.assertEqual(activity["attachment"][0].type, "Document") - self.assertEqual( - activity["attachment"][0].url, - f"https://{settings.DOMAIN}{self.book.cover.url}", + self.assertTrue( + re.match( + r"https:\/\/your.domain.here\/images\/covers\/test_[A-z0-9]+.jpg", + activity["attachment"][0].url, + ) ) self.assertEqual(activity["attachment"][0].name, "Test Edition") @@ -298,9 +305,11 @@ class Status(TestCase): ) self.assertEqual(activity["content"], "test content") self.assertEqual(activity["attachment"][0].type, "Document") - self.assertEqual( - activity["attachment"][0].url, - f"https://{settings.DOMAIN}{self.book.cover.url}", + self.assertTrue( + re.match( + r"https:\/\/your.domain.here\/images\/covers\/test_[A-z0-9]+.jpg", + activity["attachment"][0].url, + ) ) self.assertEqual(activity["attachment"][0].name, "Test Edition") @@ -320,9 +329,11 @@ class Status(TestCase): ) self.assertEqual(activity["content"], "test content") self.assertEqual(activity["attachment"][0].type, "Document") - self.assertEqual( - activity["attachment"][0].url, - f"https://{settings.DOMAIN}{self.book.cover.url}", + self.assertTrue( + re.match( + r"https:\/\/your.domain.here\/images\/covers\/test_[A-z0-9]+.jpg", + activity["attachment"][0].url, + ) ) self.assertEqual(activity["attachment"][0].name, "Test Edition") @@ -341,27 +352,25 @@ class Status(TestCase): f'rated {self.book.title}: 3 stars', ) self.assertEqual(activity["attachment"][0].type, "Document") - self.assertEqual( - activity["attachment"][0].url, - f"https://{settings.DOMAIN}{self.book.cover.url}", + self.assertTrue( + re.match( + r"https:\/\/your.domain.here\/images\/covers\/test_[A-z0-9]+.jpg", + activity["attachment"][0].url, + ) ) self.assertEqual(activity["attachment"][0].name, "Test Edition") def test_favorite(self, *_): """fav a status""" - real_broadcast = models.Favorite.broadcast - - def fav_broadcast_mock(_, activity, user): - """ok""" - self.assertEqual(user.remote_id, self.local_user.remote_id) - self.assertEqual(activity["type"], "Like") - - models.Favorite.broadcast = fav_broadcast_mock - status = models.Status.objects.create( content="test content", user=self.local_user ) - fav = models.Favorite.objects.create(status=status, user=self.local_user) + + with patch("bookwyrm.models.Favorite.broadcast") as mock: + fav = models.Favorite.objects.create(status=status, user=self.local_user) + args = mock.call_args[0] + self.assertEqual(args[1].remote_id, self.local_user.remote_id) + self.assertEqual(args[0]["type"], "Like") # can't fav a status twice with self.assertRaises(IntegrityError): @@ -371,7 +380,6 @@ class Status(TestCase): self.assertEqual(activity["type"], "Like") self.assertEqual(activity["actor"], self.local_user.remote_id) self.assertEqual(activity["object"], status.remote_id) - models.Favorite.broadcast = real_broadcast def test_boost(self, *_): """boosting, this one's a bit fussy""" diff --git a/bookwyrm/tests/models/test_user_model.py b/bookwyrm/tests/models/test_user_model.py index 528d3fdc..389928cd 100644 --- a/bookwyrm/tests/models/test_user_model.py +++ b/bookwyrm/tests/models/test_user_model.py @@ -165,12 +165,12 @@ class User(TestCase): """deactivate a user""" self.assertTrue(self.user.is_active) with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.delay" + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" ) as broadcast_mock: self.user.delete() self.assertEqual(broadcast_mock.call_count, 1) - activity = json.loads(broadcast_mock.call_args[0][1]) + activity = json.loads(broadcast_mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Delete") self.assertEqual(activity["object"], self.user.remote_id) self.assertFalse(self.user.is_active) diff --git a/bookwyrm/tests/test_book_search.py b/bookwyrm/tests/test_book_search.py index 4b9a0681..16435fff 100644 --- a/bookwyrm/tests/test_book_search.py +++ b/bookwyrm/tests/test_book_search.py @@ -57,12 +57,24 @@ class BookSearch(TestCase): self.assertEqual(len(results), 1) self.assertEqual(results[0], self.second_edition) + def test_search_identifiers_return_first(self): + """search by unique identifiers""" + result = book_search.search_identifiers("hello", return_first=True) + self.assertEqual(result, self.second_edition) + def test_search_title_author(self): """search by unique identifiers""" results = book_search.search_title_author("Another", min_confidence=0) self.assertEqual(len(results), 1) self.assertEqual(results[0], self.second_edition) + def test_search_title_author_return_first(self): + """search by unique identifiers""" + results = book_search.search_title_author( + "Another", min_confidence=0, return_first=True + ) + self.assertEqual(results, self.second_edition) + def test_format_search_result(self): """format a search result""" result = book_search.format_search_result(self.first_edition) diff --git a/bookwyrm/tests/test_postgres.py b/bookwyrm/tests/test_postgres.py index 70775d47..62451257 100644 --- a/bookwyrm/tests/test_postgres.py +++ b/bookwyrm/tests/test_postgres.py @@ -5,7 +5,7 @@ from django.test import TestCase from bookwyrm import models -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") class PostgresTriggers(TestCase): """special migrations, fancy stuff ya know""" diff --git a/bookwyrm/tests/test_suggested_users.py b/bookwyrm/tests/test_suggested_users.py index f625ac10..dce5d770 100644 --- a/bookwyrm/tests/test_suggested_users.py +++ b/bookwyrm/tests/test_suggested_users.py @@ -9,7 +9,7 @@ from bookwyrm import models from bookwyrm.suggested_users import suggested_users, get_annotated_users -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") @@ -168,7 +168,7 @@ class SuggestedUsers(TestCase): remote_id="https://example.com/book/1", parent_work=work, ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): # 1 shared follow self.local_user.following.add(user_2) user_1.followers.add(user_2) @@ -213,7 +213,7 @@ class SuggestedUsers(TestCase): user.following.add(user_1) user.followers.add(self.local_user) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): for i in range(3): book = models.Edition.objects.create( title=i, diff --git a/bookwyrm/tests/test_templatetags.py b/bookwyrm/tests/test_templatetags.py index 5954ce27..ed4466f5 100644 --- a/bookwyrm/tests/test_templatetags.py +++ b/bookwyrm/tests/test_templatetags.py @@ -44,7 +44,7 @@ class TemplateTags(TestCase): def test_get_user_rating(self, *_): """get a user's most recent rating of a book""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.Review.objects.create(user=self.user, book=self.book, rating=3) self.assertEqual(bookwyrm_tags.get_user_rating(self.book, self.user), 3) @@ -63,7 +63,7 @@ class TemplateTags(TestCase): utilities.get_user_identifier(self.remote_user), "rat@example.com" ) - @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") def test_get_replies(self, *_): """direct replies to a status""" parent = models.Review.objects.create( @@ -90,7 +90,7 @@ class TemplateTags(TestCase): def test_get_parent(self, *_): """get the reply parent of a status""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): parent = models.Review.objects.create( user=self.user, book=self.book, content="hi" ) @@ -107,7 +107,7 @@ class TemplateTags(TestCase): status = models.Review.objects.create(user=self.remote_user, book=self.book) self.assertFalse(interaction.get_user_liked(self.user, status)) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.Favorite.objects.create(user=self.user, status=status) self.assertTrue(interaction.get_user_liked(self.user, status)) @@ -116,13 +116,13 @@ class TemplateTags(TestCase): status = models.Review.objects.create(user=self.remote_user, book=self.book) self.assertFalse(interaction.get_user_boosted(self.user, status)) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.Boost.objects.create(user=self.user, boosted_status=status) self.assertTrue(interaction.get_user_boosted(self.user, status)) def test_get_boosted(self, *_): """load a boosted status""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): status = models.Review.objects.create(user=self.remote_user, book=self.book) boost = models.Boost.objects.create(user=self.user, boosted_status=status) boosted = status_display.get_boosted(boost) @@ -166,7 +166,7 @@ class TemplateTags(TestCase): def test_related_status(self, *_): """gets the subclass model for a notification status""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): status = models.Status.objects.create(content="hi", user=self.user) notification = models.Notification.objects.create( user=self.user, notification_type="MENTION", related_status=status diff --git a/bookwyrm/tests/views/admin/test_reports.py b/bookwyrm/tests/views/admin/test_reports.py index 2b063446..8b9fe9f5 100644 --- a/bookwyrm/tests/views/admin/test_reports.py +++ b/bookwyrm/tests/views/admin/test_reports.py @@ -151,10 +151,12 @@ class ReportViews(TestCase): request.user.is_superuser = True # de-activate - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: views.moderator_delete_user(request, self.rat.id) self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[0][1]) + activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Delete") self.rat.refresh_from_db() diff --git a/bookwyrm/tests/views/admin/test_user_admin.py b/bookwyrm/tests/views/admin/test_user_admin.py index ef35c220..486fe45e 100644 --- a/bookwyrm/tests/views/admin/test_user_admin.py +++ b/bookwyrm/tests/views/admin/test_user_admin.py @@ -67,7 +67,7 @@ class UserAdminViews(TestCase): request.user = self.local_user request.user.is_superuser = True - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): result = view(request, self.local_user.id) self.assertIsInstance(result, TemplateResponse) diff --git a/bookwyrm/tests/views/books/test_book.py b/bookwyrm/tests/views/books/test_book.py index a078f161..561e2192 100644 --- a/bookwyrm/tests/views/books/test_book.py +++ b/bookwyrm/tests/views/books/test_book.py @@ -78,7 +78,7 @@ class BookViews(TestCase): self.assertIsInstance(result, ActivitypubResponse) self.assertEqual(result.status_code, 200) - @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.activitystreams.add_status_task.delay") def test_book_page_statuses(self, *_): """there are so many views, this just makes sure it LOADS""" @@ -169,7 +169,7 @@ class BookViews(TestCase): request.user = self.local_user with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.delay" + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" ) as delay_mock: views.upload_cover(request, self.book.id) self.assertEqual(delay_mock.call_count, 1) @@ -188,7 +188,7 @@ class BookViews(TestCase): request.user = self.local_user with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.delay" + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" ) as delay_mock: views.upload_cover(request, self.book.id) self.assertEqual(delay_mock.call_count, 1) @@ -202,7 +202,7 @@ class BookViews(TestCase): request = self.factory.post("", {"description": "new description hi"}) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.add_description(request, self.book.id) self.book.refresh_from_db() diff --git a/bookwyrm/tests/views/books/test_edit_book.py b/bookwyrm/tests/views/books/test_edit_book.py index 7bf5708f..cd957858 100644 --- a/bookwyrm/tests/views/books/test_edit_book.py +++ b/bookwyrm/tests/views/books/test_edit_book.py @@ -79,7 +79,7 @@ class EditBookViews(TestCase): request = self.factory.post("", form.data) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): view(request, self.book.id) self.book.refresh_from_db() @@ -115,7 +115,7 @@ class EditBookViews(TestCase): request = self.factory.post("", form.data) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): view(request, self.book.id) self.book.refresh_from_db() @@ -136,7 +136,7 @@ class EditBookViews(TestCase): request = self.factory.post("", form.data) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): view(request, self.book.id) self.book.refresh_from_db() self.assertEqual(self.book.title, "New Title") @@ -207,7 +207,7 @@ class EditBookViews(TestCase): request.user = self.local_user with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.delay" + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" ) as delay_mock: views.upload_cover(request, self.book.id) self.assertEqual(delay_mock.call_count, 1) diff --git a/bookwyrm/tests/views/books/test_editions.py b/bookwyrm/tests/views/books/test_editions.py index 2f41fe66..17f15654 100644 --- a/bookwyrm/tests/views/books/test_editions.py +++ b/bookwyrm/tests/views/books/test_editions.py @@ -111,7 +111,7 @@ class BookViews(TestCase): work = models.Work.objects.create(title="test work") edition1 = models.Edition.objects.create(title="first ed", parent_work=work) edition2 = models.Edition.objects.create(title="second ed", parent_work=work) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): shelf = models.Shelf.objects.create(name="Test Shelf", user=self.local_user) models.ShelfBook.objects.create( book=edition1, @@ -124,7 +124,7 @@ class BookViews(TestCase): self.assertEqual(models.ReadThrough.objects.get().book, edition1) request = self.factory.post("", {"edition": edition2.id}) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.switch_edition(request) self.assertEqual(models.ShelfBook.objects.get().book, edition2) diff --git a/bookwyrm/tests/views/imports/__init__.py b/bookwyrm/tests/views/imports/__init__.py new file mode 100644 index 00000000..b6e690fd --- /dev/null +++ b/bookwyrm/tests/views/imports/__init__.py @@ -0,0 +1 @@ +from . import * diff --git a/bookwyrm/tests/views/test_import.py b/bookwyrm/tests/views/imports/test_import.py similarity index 72% rename from bookwyrm/tests/views/test_import.py rename to bookwyrm/tests/views/imports/test_import.py index 2027d284..b8b8b328 100644 --- a/bookwyrm/tests/views/test_import.py +++ b/bookwyrm/tests/views/imports/test_import.py @@ -5,6 +5,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile from django.template.response import TemplateResponse from django.test import TestCase from django.test.client import RequestFactory +from bookwyrm.tests.validate_html import validate_html from bookwyrm import forms, models, views @@ -34,32 +35,35 @@ class ImportViews(TestCase): request.user = self.local_user result = view(request) self.assertIsInstance(result, TemplateResponse) - result.render() + validate_html(result.render()) self.assertEqual(result.status_code, 200) def test_import_status(self): """there are so many views, this just makes sure it LOADS""" view = views.ImportStatus.as_view() - import_job = models.ImportJob.objects.create(user=self.local_user) + import_job = models.ImportJob.objects.create(user=self.local_user, mappings={}) request = self.factory.get("") request.user = self.local_user with patch("bookwyrm.tasks.app.AsyncResult") as async_result: async_result.return_value = [] result = view(request, import_job.id) self.assertIsInstance(result, TemplateResponse) - result.render() + validate_html(result.render()) self.assertEqual(result.status_code, 200) def test_start_import(self): """retry failed items""" view = views.Import.as_view() form = forms.ImportForm() - form.data["source"] = "LibraryThing" + form.data["source"] = "Goodreads" form.data["privacy"] = "public" form.data["include_reviews"] = False - csv_file = pathlib.Path(__file__).parent.joinpath("../data/goodreads.csv") + csv_file = pathlib.Path(__file__).parent.joinpath("../../data/goodreads.csv") form.data["csv_file"] = SimpleUploadedFile( - csv_file, open(csv_file, "rb").read(), content_type="text/csv" + # pylint: disable=consider-using-with + csv_file, + open(csv_file, "rb").read(), + content_type="text/csv", ) request = self.factory.post("", form.data) @@ -70,22 +74,3 @@ class ImportViews(TestCase): job = models.ImportJob.objects.get() self.assertFalse(job.include_reviews) self.assertEqual(job.privacy, "public") - - def test_retry_import(self): - """retry failed items""" - view = views.ImportStatus.as_view() - import_job = models.ImportJob.objects.create( - user=self.local_user, privacy="unlisted" - ) - request = self.factory.post("") - request.user = self.local_user - - with patch("bookwyrm.importers.Importer.start_import"): - view(request, import_job.id) - - self.assertEqual(models.ImportJob.objects.count(), 2) - retry_job = models.ImportJob.objects.last() - - self.assertTrue(retry_job.retry) - self.assertEqual(retry_job.user, self.local_user) - self.assertEqual(retry_job.privacy, "unlisted") diff --git a/bookwyrm/tests/views/imports/test_import_review.py b/bookwyrm/tests/views/imports/test_import_review.py new file mode 100644 index 00000000..2ab48468 --- /dev/null +++ b/bookwyrm/tests/views/imports/test_import_review.py @@ -0,0 +1,87 @@ +""" test for app action functionality """ +from unittest.mock import patch +from django.template.response import TemplateResponse +from django.test import TestCase +from django.test.client import RequestFactory +from bookwyrm.tests.validate_html import validate_html + +from bookwyrm import models, views + + +class ImportManualReviewViews(TestCase): + """goodreads import views""" + + def setUp(self): + """we need basic test data and mocks""" + self.factory = RequestFactory() + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): + self.local_user = models.User.objects.create_user( + "mouse@local.com", + "mouse@mouse.mouse", + "password", + local=True, + localname="mouse", + ) + models.SiteSettings.objects.create() + self.job = models.ImportJob.objects.create(user=self.local_user, mappings={}) + + work = models.Work.objects.create(title="Test Work") + self.book = models.Edition.objects.create( + title="Example Edition", + remote_id="https://example.com/book/1", + parent_work=work, + ) + + def test_import_troubleshoot_get(self): + """there are so many views, this just makes sure it LOADS""" + view = views.ImportManualReview.as_view() + request = self.factory.get("") + request.user = self.local_user + with patch("bookwyrm.tasks.app.AsyncResult") as async_result: + async_result.return_value = [] + result = view(request, self.job.id) + self.assertIsInstance(result, TemplateResponse) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + + def test_approve_item(self): + """a guess is correct""" + import_item = models.ImportItem.objects.create( + index=0, + job=self.job, + book_guess=self.book, + fail_reason="no match", + data={}, + normalized_data={}, + ) + request = self.factory.post("") + request.user = self.local_user + + with patch("bookwyrm.importers.importer.import_item_task.delay") as mock: + views.approve_import_item(request, self.job.id, import_item.id) + self.assertEqual(mock.call_count, 1) + import_item.refresh_from_db() + self.assertIsNone(import_item.fail_reason) + self.assertIsNone(import_item.book_guess) + self.assertEqual(import_item.book.id, self.book.id) + + def test_delete_item(self): + """a guess is correct""" + import_item = models.ImportItem.objects.create( + index=0, + job=self.job, + book_guess=self.book, + fail_reason="no match", + data={}, + normalized_data={}, + ) + request = self.factory.post("") + request.user = self.local_user + + views.delete_import_item(request, self.job.id, import_item.id) + import_item.refresh_from_db() + self.assertEqual(import_item.fail_reason, "no match") + self.assertIsNone(import_item.book_guess) + self.assertIsNone(import_item.book) diff --git a/bookwyrm/tests/views/imports/test_import_troubleshoot.py b/bookwyrm/tests/views/imports/test_import_troubleshoot.py new file mode 100644 index 00000000..5359cc1e --- /dev/null +++ b/bookwyrm/tests/views/imports/test_import_troubleshoot.py @@ -0,0 +1,59 @@ +""" test for app action functionality """ +from unittest.mock import patch +from django.template.response import TemplateResponse +from django.test import TestCase +from django.test.client import RequestFactory +from bookwyrm.tests.validate_html import validate_html + +from bookwyrm import models, views + + +class ImportTroubleshootViews(TestCase): + """goodreads import views""" + + def setUp(self): + """we need basic test data and mocks""" + self.factory = RequestFactory() + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): + self.local_user = models.User.objects.create_user( + "mouse@local.com", + "mouse@mouse.mouse", + "password", + local=True, + localname="mouse", + ) + models.SiteSettings.objects.create() + + def test_import_troubleshoot_get(self): + """there are so many views, this just makes sure it LOADS""" + view = views.ImportTroubleshoot.as_view() + import_job = models.ImportJob.objects.create(user=self.local_user, mappings={}) + request = self.factory.get("") + request.user = self.local_user + with patch("bookwyrm.tasks.app.AsyncResult") as async_result: + async_result.return_value = [] + result = view(request, import_job.id) + self.assertIsInstance(result, TemplateResponse) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + + def test_retry_import(self): + """retry failed items""" + view = views.ImportTroubleshoot.as_view() + import_job = models.ImportJob.objects.create( + user=self.local_user, privacy="unlisted", mappings={} + ) + request = self.factory.post("") + request.user = self.local_user + + with patch("bookwyrm.importers.Importer.start_import"): + view(request, import_job.id) + + self.assertEqual(models.ImportJob.objects.count(), 2) + retry_job = models.ImportJob.objects.last() + + self.assertTrue(retry_job.retry) + self.assertEqual(retry_job.user, self.local_user) + self.assertEqual(retry_job.privacy, "unlisted") diff --git a/bookwyrm/tests/views/inbox/test_inbox_announce.py b/bookwyrm/tests/views/inbox/test_inbox_announce.py index 3a108878..a291552d 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_announce.py +++ b/bookwyrm/tests/views/inbox/test_inbox_announce.py @@ -36,7 +36,7 @@ class InboxActivities(TestCase): outbox="https://example.com/users/rat/outbox", ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): with patch("bookwyrm.activitystreams.add_status_task.delay"): self.status = models.Status.objects.create( user=self.local_user, diff --git a/bookwyrm/tests/views/inbox/test_inbox_block.py b/bookwyrm/tests/views/inbox/test_inbox_block.py index ffd74dbd..f6898fc6 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_block.py +++ b/bookwyrm/tests/views/inbox/test_inbox_block.py @@ -40,7 +40,7 @@ class InboxBlock(TestCase): def test_handle_blocks(self): """create a "block" database entry from an activity""" self.local_user.followers.add(self.remote_user) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.UserFollowRequest.objects.create( user_subject=self.local_user, user_object=self.remote_user ) diff --git a/bookwyrm/tests/views/inbox/test_inbox_create.py b/bookwyrm/tests/views/inbox/test_inbox_create.py index 76fd366c..53b17d68 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_create.py +++ b/bookwyrm/tests/views/inbox/test_inbox_create.py @@ -10,7 +10,7 @@ from bookwyrm.activitypub import ActivitySerializerError # pylint: disable=too-many-public-methods -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") class InboxCreate(TestCase): """readthrough tests""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_follow.py b/bookwyrm/tests/views/inbox/test_inbox_follow.py index 6b629c2f..71f101ca 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_follow.py +++ b/bookwyrm/tests/views/inbox/test_inbox_follow.py @@ -49,10 +49,12 @@ class InboxRelationships(TestCase): } self.assertFalse(models.UserFollowRequest.objects.exists()) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: views.inbox.activity_task(activity) self.assertEqual(mock.call_count, 1) - response_activity = json.loads(mock.call_args[0][1]) + response_activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(response_activity["type"], "Accept") # notification created @@ -77,17 +79,19 @@ class InboxRelationships(TestCase): "object": "https://example.com/user/mouse", } - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.inbox.activity_task(activity) # the follow relationship should exist follow = models.UserFollows.objects.get(user_object=self.local_user) self.assertEqual(follow.user_subject, self.remote_user) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: views.inbox.activity_task(activity) self.assertEqual(mock.call_count, 1) - response_activity = json.loads(mock.call_args[0][1]) + response_activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(response_activity["type"], "Accept") # the follow relationship should STILL exist @@ -109,7 +113,7 @@ class InboxRelationships(TestCase): broadcast=False, update_fields=["manually_approves_followers"] ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.inbox.activity_task(activity) # notification created @@ -132,7 +136,7 @@ class InboxRelationships(TestCase): self.local_user.save( broadcast=False, update_fields=["manually_approves_followers"] ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): request = models.UserFollowRequest.objects.create( user_subject=self.remote_user, user_object=self.local_user ) @@ -160,7 +164,7 @@ class InboxRelationships(TestCase): def test_unfollow(self): """remove a relationship""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): rel = models.UserFollows.objects.create( user_subject=self.remote_user, user_object=self.local_user ) @@ -186,7 +190,7 @@ class InboxRelationships(TestCase): @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") def test_follow_accept(self, _): """a remote user approved a follow request from local""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): rel = models.UserFollowRequest.objects.create( user_subject=self.local_user, user_object=self.remote_user ) @@ -217,7 +221,7 @@ class InboxRelationships(TestCase): def test_follow_reject(self): """turn down a follow request""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): rel = models.UserFollowRequest.objects.create( user_subject=self.local_user, user_object=self.remote_user ) diff --git a/bookwyrm/tests/views/inbox/test_inbox_like.py b/bookwyrm/tests/views/inbox/test_inbox_like.py index db8f1fca..2f1b6629 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_like.py +++ b/bookwyrm/tests/views/inbox/test_inbox_like.py @@ -35,7 +35,7 @@ class InboxActivities(TestCase): outbox="https://example.com/users/rat/outbox", ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): with patch("bookwyrm.activitystreams.add_status_task.delay"): self.status = models.Status.objects.create( user=self.local_user, diff --git a/bookwyrm/tests/views/inbox/test_inbox_remove.py b/bookwyrm/tests/views/inbox/test_inbox_remove.py index cb4e4a16..55cc8120 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_remove.py +++ b/bookwyrm/tests/views/inbox/test_inbox_remove.py @@ -75,7 +75,7 @@ class InboxRemove(TestCase): def test_handle_remove_book_from_list(self): """listing a book""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): booklist = models.List.objects.create( name="test list", user=self.local_user, diff --git a/bookwyrm/tests/views/inbox/test_inbox_update.py b/bookwyrm/tests/views/inbox/test_inbox_update.py index 0efeac0c..248c1ad2 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_update.py +++ b/bookwyrm/tests/views/inbox/test_inbox_update.py @@ -50,7 +50,7 @@ class InboxUpdate(TestCase): def test_update_list(self): """a new list""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): book_list = models.List.objects.create( name="hi", remote_id="https://example.com/list/22", user=self.local_user ) @@ -171,7 +171,7 @@ class InboxUpdate(TestCase): book = models.Work.objects.get(id=book.id) self.assertEqual(book.title, "Piranesi") - @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.activitystreams.add_status_task.delay") def test_update_status(self, *_): """edit a status""" diff --git a/bookwyrm/tests/views/preferences/test_block.py b/bookwyrm/tests/views/preferences/test_block.py index b23a6cbc..975142a1 100644 --- a/bookwyrm/tests/views/preferences/test_block.py +++ b/bookwyrm/tests/views/preferences/test_block.py @@ -9,7 +9,7 @@ from bookwyrm import models, views from bookwyrm.tests.validate_html import validate_html -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") class BlockViews(TestCase): """view user and edit profile""" diff --git a/bookwyrm/tests/views/preferences/test_delete_user.py b/bookwyrm/tests/views/preferences/test_delete_user.py index 09f722f7..b6d87ccd 100644 --- a/bookwyrm/tests/views/preferences/test_delete_user.py +++ b/bookwyrm/tests/views/preferences/test_delete_user.py @@ -35,9 +35,9 @@ class DeleteUserViews(TestCase): self.book = models.Edition.objects.create( title="test", parent_work=models.Work.objects.create(title="test work") ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"), patch( - "bookwyrm.activitystreams.add_book_statuses_task.delay" - ): + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ), patch("bookwyrm.activitystreams.add_book_statuses_task.delay"): models.ShelfBook.objects.create( book=self.book, user=self.local_user, @@ -70,11 +70,11 @@ class DeleteUserViews(TestCase): self.assertIsNone(self.local_user.name) with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.delay" + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" ) as delay_mock: view(request) self.assertEqual(delay_mock.call_count, 1) - activity = json.loads(delay_mock.call_args[0][1]) + activity = json.loads(delay_mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Delete") self.assertEqual(activity["actor"], self.local_user.remote_id) self.assertEqual( diff --git a/bookwyrm/tests/views/preferences/test_edit_user.py b/bookwyrm/tests/views/preferences/test_edit_user.py index b52875a9..7a845fbe 100644 --- a/bookwyrm/tests/views/preferences/test_edit_user.py +++ b/bookwyrm/tests/views/preferences/test_edit_user.py @@ -38,9 +38,9 @@ class EditUserViews(TestCase): self.book = models.Edition.objects.create( title="test", parent_work=models.Work.objects.create(title="test work") ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"), patch( - "bookwyrm.activitystreams.add_book_statuses_task.delay" - ): + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ), patch("bookwyrm.activitystreams.add_book_statuses_task.delay"): models.ShelfBook.objects.create( book=self.book, user=self.local_user, @@ -74,7 +74,7 @@ class EditUserViews(TestCase): self.assertIsNone(self.local_user.name) with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.delay" + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" ) as delay_mock: view(request) self.assertEqual(delay_mock.call_count, 1) @@ -100,7 +100,7 @@ class EditUserViews(TestCase): request.user = self.local_user with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.delay" + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" ) as delay_mock: view(request) self.assertEqual(delay_mock.call_count, 1) diff --git a/bookwyrm/tests/views/shelf/test_shelf.py b/bookwyrm/tests/views/shelf/test_shelf.py index 71df3631..ab88de0a 100644 --- a/bookwyrm/tests/views/shelf/test_shelf.py +++ b/bookwyrm/tests/views/shelf/test_shelf.py @@ -11,7 +11,7 @@ from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.tests.validate_html import validate_html -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @@ -39,7 +39,7 @@ class ShelfViews(TestCase): remote_id="https://example.com/book/1", parent_work=self.work, ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): self.shelf = models.Shelf.objects.create( name="Test Shelf", identifier="test-shelf", user=self.local_user ) @@ -142,7 +142,7 @@ class ShelfViews(TestCase): "", {"privacy": "public", "user": self.local_user.id, "name": "cool name"} ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): view(request, request.user.username, shelf.identifier) shelf.refresh_from_db() @@ -159,7 +159,7 @@ class ShelfViews(TestCase): "", {"privacy": "public", "user": self.local_user.id, "name": "cool name"} ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): view(request, request.user.username, shelf.identifier) self.assertEqual(shelf.name, "To Read") diff --git a/bookwyrm/tests/views/shelf/test_shelf_actions.py b/bookwyrm/tests/views/shelf/test_shelf_actions.py index 3efae0f4..1a7d56fd 100644 --- a/bookwyrm/tests/views/shelf/test_shelf_actions.py +++ b/bookwyrm/tests/views/shelf/test_shelf_actions.py @@ -9,7 +9,7 @@ from django.test.client import RequestFactory from bookwyrm import forms, models, views -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @@ -37,7 +37,7 @@ class ShelfActionViews(TestCase): remote_id="https://example.com/book/1", parent_work=self.work, ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): self.shelf = models.Shelf.objects.create( name="Test Shelf", identifier="test-shelf", user=self.local_user ) @@ -49,11 +49,13 @@ class ShelfActionViews(TestCase): "", {"book": self.book.id, "shelf": self.shelf.identifier} ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: views.shelve(request) self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[0][1]) + activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Add") item = models.ShelfBook.objects.get() @@ -69,7 +71,7 @@ class ShelfActionViews(TestCase): ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.shelve(request) # make sure the book is on the shelf self.assertEqual(shelf.books.get(), self.book) @@ -82,7 +84,7 @@ class ShelfActionViews(TestCase): ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.shelve(request) # make sure the book is on the shelf self.assertEqual(shelf.books.get(), self.book) @@ -95,7 +97,7 @@ class ShelfActionViews(TestCase): ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.shelve(request) # make sure the book is on the shelf self.assertEqual(shelf.books.get(), self.book) @@ -118,7 +120,7 @@ class ShelfActionViews(TestCase): ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.shelve(request) # make sure the book is on the shelf self.assertEqual(shelf.books.get(), self.book) @@ -126,7 +128,7 @@ class ShelfActionViews(TestCase): def test_unshelve(self, *_): """remove a book from a shelf""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.ShelfBook.objects.create( book=self.book, user=self.local_user, shelf=self.shelf ) @@ -136,9 +138,11 @@ class ShelfActionViews(TestCase): self.assertEqual(self.shelf.books.count(), 1) request = self.factory.post("", {"book": self.book.id, "shelf": self.shelf.id}) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: views.unshelve(request) - activity = json.loads(mock.call_args[0][1]) + activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Remove") self.assertEqual(activity["object"]["id"], item.remote_id) self.assertEqual(self.shelf.books.count(), 0) @@ -192,7 +196,7 @@ class ShelfActionViews(TestCase): def test_delete_shelf_has_book(self, *_): """delete a brand new custom shelf""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.ShelfBook.objects.create( book=self.book, user=self.local_user, shelf=self.shelf ) diff --git a/bookwyrm/tests/views/test_author.py b/bookwyrm/tests/views/test_author.py index ccbfe549..32b1565e 100644 --- a/bookwyrm/tests/views/test_author.py +++ b/bookwyrm/tests/views/test_author.py @@ -111,7 +111,7 @@ class AuthorViews(TestCase): request = self.factory.post("", form.data) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): view(request, author.id) author.refresh_from_db() self.assertEqual(author.name, "New Name") diff --git a/bookwyrm/tests/views/test_discover.py b/bookwyrm/tests/views/test_discover.py index 4b8927bc..b2a82241 100644 --- a/bookwyrm/tests/views/test_discover.py +++ b/bookwyrm/tests/views/test_discover.py @@ -41,7 +41,7 @@ class DiscoverViews(TestCase): self.assertEqual(result.status_code, 200) result.render() - @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.activitystreams.add_status_task.delay") def test_discover_page(self, *_): """there are so many views, this just makes sure it LOADS""" diff --git a/bookwyrm/tests/views/test_feed.py b/bookwyrm/tests/views/test_feed.py index a6f220b5..5c6a4dd3 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -57,7 +57,7 @@ class FeedViews(TestCase): def test_status_page(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Status.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): status = models.Status.objects.create(content="hi", user=self.local_user) request = self.factory.get("") request.user = self.local_user @@ -95,7 +95,7 @@ class FeedViews(TestCase): local=True, localname="rat", ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): status = models.Status.objects.create(content="hi", user=another_user) request = self.factory.get("") @@ -115,7 +115,7 @@ class FeedViews(TestCase): image = Image.open(image_file) output = BytesIO() image.save(output, format=image.format) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): status = models.Review.objects.create( content="hi", user=self.local_user, @@ -144,7 +144,7 @@ class FeedViews(TestCase): def test_replies_page(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Replies.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): status = models.Status.objects.create(content="hi", user=self.local_user) request = self.factory.get("") request.user = self.local_user @@ -171,7 +171,7 @@ class FeedViews(TestCase): result.render() self.assertEqual(result.status_code, 200) - @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") def test_get_suggested_book(self, *_): """gets books the ~*~ algorithm ~*~ thinks you want to post about""" diff --git a/bookwyrm/tests/views/test_follow.py b/bookwyrm/tests/views/test_follow.py index 947c55cf..25b5a014 100644 --- a/bookwyrm/tests/views/test_follow.py +++ b/bookwyrm/tests/views/test_follow.py @@ -59,7 +59,7 @@ class FollowViews(TestCase): request.user = self.local_user self.assertEqual(models.UserFollowRequest.objects.count(), 0) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.follow(request) rel = models.UserFollowRequest.objects.get() @@ -86,7 +86,7 @@ class FollowViews(TestCase): request.user = self.local_user self.assertEqual(models.UserFollowRequest.objects.count(), 0) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.follow(request) rel = models.UserFollowRequest.objects.get() @@ -111,7 +111,7 @@ class FollowViews(TestCase): request.user = self.local_user self.assertEqual(models.UserFollowRequest.objects.count(), 0) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.follow(request) rel = models.UserFollows.objects.get() @@ -127,10 +127,12 @@ class FollowViews(TestCase): request.user = self.local_user self.remote_user.followers.add(self.local_user) self.assertEqual(self.remote_user.followers.count(), 1) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: views.unfollow(request) self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args_list[0][0][1]) + activity = json.loads(mock.call_args_list[0][1]["args"][1]) self.assertEqual(activity["type"], "Undo") self.assertEqual(self.remote_user.followers.count(), 0) @@ -147,7 +149,7 @@ class FollowViews(TestCase): user_subject=self.remote_user, user_object=self.local_user ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.accept_follow_request(request) # request should be deleted self.assertEqual(models.UserFollowRequest.objects.filter(id=rel.id).count(), 0) @@ -166,7 +168,7 @@ class FollowViews(TestCase): user_subject=self.remote_user, user_object=self.local_user ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.delete_follow_request(request) # request should be deleted self.assertEqual(models.UserFollowRequest.objects.filter(id=rel.id).count(), 0) diff --git a/bookwyrm/tests/views/test_get_started.py b/bookwyrm/tests/views/test_get_started.py index ff441b57..6d1819a4 100644 --- a/bookwyrm/tests/views/test_get_started.py +++ b/bookwyrm/tests/views/test_get_started.py @@ -56,7 +56,7 @@ class GetStartedViews(TestCase): self.assertIsNone(self.local_user.name) with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.delay" + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" ) as delay_mock: view(request) self.assertEqual(delay_mock.call_count, 1) @@ -98,7 +98,7 @@ class GetStartedViews(TestCase): self.assertFalse(self.local_user.shelfbook_set.exists()) with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.delay" + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" ) as delay_mock: view(request) self.assertEqual(delay_mock.call_count, 1) diff --git a/bookwyrm/tests/views/test_goal.py b/bookwyrm/tests/views/test_goal.py index 557510d7..73207240 100644 --- a/bookwyrm/tests/views/test_goal.py +++ b/bookwyrm/tests/views/test_goal.py @@ -123,7 +123,7 @@ class GoalViews(TestCase): }, ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): view(request, self.local_user.localname, self.year) goal = models.AnnualGoal.objects.get() diff --git a/bookwyrm/tests/views/test_group.py b/bookwyrm/tests/views/test_group.py index c7e0a0f7..b18ce6b4 100644 --- a/bookwyrm/tests/views/test_group.py +++ b/bookwyrm/tests/views/test_group.py @@ -10,7 +10,7 @@ from bookwyrm import models, views, forms from bookwyrm.tests.validate_html import validate_html -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") class GroupViews(TestCase): """view group and edit details""" diff --git a/bookwyrm/tests/views/test_helpers.py b/bookwyrm/tests/views/test_helpers.py index 8f7b45a3..1aae830f 100644 --- a/bookwyrm/tests/views/test_helpers.py +++ b/bookwyrm/tests/views/test_helpers.py @@ -55,7 +55,7 @@ class ViewsHelpers(TestCase): datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json") self.userdata = json.loads(datafile.read_bytes()) del self.userdata["icon"] - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): self.shelf = models.Shelf.objects.create( name="Test Shelf", identifier="test-shelf", user=self.local_user ) @@ -166,7 +166,7 @@ class ViewsHelpers(TestCase): def test_handle_reading_status_to_read(self, *_): """posts shelve activities""" shelf = self.local_user.shelf_set.get(identifier="to-read") - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.helpers.handle_reading_status( self.local_user, shelf, self.book, "public" ) @@ -178,7 +178,7 @@ class ViewsHelpers(TestCase): def test_handle_reading_status_reading(self, *_): """posts shelve activities""" shelf = self.local_user.shelf_set.get(identifier="reading") - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.helpers.handle_reading_status( self.local_user, shelf, self.book, "public" ) @@ -190,7 +190,7 @@ class ViewsHelpers(TestCase): def test_handle_reading_status_read(self, *_): """posts shelve activities""" shelf = self.local_user.shelf_set.get(identifier="read") - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.helpers.handle_reading_status( self.local_user, shelf, self.book, "public" ) @@ -201,7 +201,7 @@ class ViewsHelpers(TestCase): def test_handle_reading_status_other(self, *_): """posts shelve activities""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.helpers.handle_reading_status( self.local_user, self.shelf, self.book, "public" ) diff --git a/bookwyrm/tests/views/test_interaction.py b/bookwyrm/tests/views/test_interaction.py index e8b9353e..aa402952 100644 --- a/bookwyrm/tests/views/test_interaction.py +++ b/bookwyrm/tests/views/test_interaction.py @@ -7,7 +7,7 @@ from django.test.client import RequestFactory from bookwyrm import models, views -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.activitystreams.remove_status_task.delay") class InteractionViews(TestCase): """viewing and creating statuses""" @@ -74,7 +74,7 @@ class InteractionViews(TestCase): self.assertEqual(models.Favorite.objects.count(), 1) self.assertEqual(models.Notification.objects.count(), 1) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): view(request, status.id) self.assertEqual(models.Favorite.objects.count(), 0) self.assertEqual(models.Notification.objects.count(), 0) @@ -110,12 +110,12 @@ class InteractionViews(TestCase): status = models.Status.objects.create(user=self.local_user, content="hi") with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.delay" + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" ) as broadcast_mock: view(request, status.id) self.assertEqual(broadcast_mock.call_count, 1) - activity = json.loads(broadcast_mock.call_args[0][1]) + activity = json.loads(broadcast_mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Announce") boost = models.Boost.objects.get() diff --git a/bookwyrm/tests/views/test_list.py b/bookwyrm/tests/views/test_list.py index 35befec6..c670ad18 100644 --- a/bookwyrm/tests/views/test_list.py +++ b/bookwyrm/tests/views/test_list.py @@ -61,7 +61,7 @@ class ListViews(TestCase): parent_work=work_four, ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): self.list = models.List.objects.create( name="Test List", user=self.local_user ) @@ -73,7 +73,7 @@ class ListViews(TestCase): def test_lists_page(self): """there are so many views, this just makes sure it LOADS""" view = views.Lists.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.List.objects.create(name="Public list", user=self.local_user) models.List.objects.create( name="Private list", privacy="direct", user=self.local_user @@ -96,7 +96,7 @@ class ListViews(TestCase): def test_saved_lists_page(self): """there are so many views, this just makes sure it LOADS""" view = views.SavedLists.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): booklist = models.List.objects.create( name="Public list", user=self.local_user ) @@ -116,7 +116,7 @@ class ListViews(TestCase): def test_saved_lists_page_empty(self): """there are so many views, this just makes sure it LOADS""" view = views.SavedLists.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.List.objects.create(name="Public list", user=self.local_user) models.List.objects.create( name="Private list", privacy="direct", user=self.local_user @@ -153,11 +153,13 @@ class ListViews(TestCase): }, ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: result = view(request) self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[0][1]) + activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Create") self.assertEqual(activity["actor"], self.local_user.remote_id) @@ -172,7 +174,7 @@ class ListViews(TestCase): view = views.List.as_view() request = self.factory.get("") request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.ListItem.objects.create( book_list=self.list, user=self.local_user, @@ -191,7 +193,7 @@ class ListViews(TestCase): def test_list_page_sorted(self): """there are so many views, this just makes sure it LOADS""" view = views.List.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): for (i, book) in enumerate([self.book, self.book_two, self.book_three]): models.ListItem.objects.create( book_list=self.list, @@ -253,7 +255,7 @@ class ListViews(TestCase): def test_list_page_logged_out(self): """there are so many views, this just makes sure it LOADS""" view = views.List.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.ListItem.objects.create( book_list=self.list, user=self.local_user, @@ -276,7 +278,7 @@ class ListViews(TestCase): view = views.List.as_view() request = self.factory.get("") request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.ListItem.objects.create( book_list=self.list, user=self.local_user, @@ -320,11 +322,13 @@ class ListViews(TestCase): ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: result = view(request, self.list.id) self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[0][1]) + activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Update") self.assertEqual(activity["actor"], self.local_user.remote_id) self.assertEqual(activity["object"]["id"], self.list.remote_id) @@ -340,7 +344,7 @@ class ListViews(TestCase): def test_curate_page(self): """there are so many views, this just makes sure it LOADS""" view = views.Curate.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.List.objects.create(name="Public list", user=self.local_user) models.List.objects.create( name="Private list", privacy="direct", user=self.local_user @@ -360,7 +364,7 @@ class ListViews(TestCase): def test_user_lists_page(self): """there are so many views, this just makes sure it LOADS""" view = views.UserLists.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.List.objects.create(name="Public list", user=self.local_user) models.List.objects.create( name="Private list", privacy="direct", user=self.local_user diff --git a/bookwyrm/tests/views/test_list_actions.py b/bookwyrm/tests/views/test_list_actions.py index f7775d19..1d9f46b3 100644 --- a/bookwyrm/tests/views/test_list_actions.py +++ b/bookwyrm/tests/views/test_list_actions.py @@ -61,7 +61,7 @@ class ListActionViews(TestCase): parent_work=work_four, ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): self.list = models.List.objects.create( name="Test List", user=self.local_user ) @@ -71,7 +71,7 @@ class ListActionViews(TestCase): def test_delete_list(self): """delete an entire list""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.ListItem.objects.create( book_list=self.list, user=self.local_user, @@ -88,9 +88,11 @@ class ListActionViews(TestCase): ) request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: views.delete_list(request, self.list.id) - activity = json.loads(mock.call_args[0][1]) + activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Delete") self.assertEqual(activity["actor"], self.local_user.remote_id) self.assertEqual(activity["object"]["id"], self.list.remote_id) @@ -110,7 +112,7 @@ class ListActionViews(TestCase): def test_curate_approve(self): """approve a pending item""" view = views.Curate.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): pending = models.ListItem.objects.create( book_list=self.list, user=self.local_user, @@ -128,11 +130,13 @@ class ListActionViews(TestCase): ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: view(request, self.list.id) self.assertEqual(mock.call_count, 2) - activity = json.loads(mock.call_args[0][1]) + activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Add") self.assertEqual(activity["actor"], self.local_user.remote_id) self.assertEqual(activity["target"], self.list.remote_id) @@ -145,7 +149,7 @@ class ListActionViews(TestCase): def test_curate_reject(self): """approve a pending item""" view = views.Curate.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): pending = models.ListItem.objects.create( book_list=self.list, user=self.local_user, @@ -179,10 +183,12 @@ class ListActionViews(TestCase): ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: views.list.add_book(request) self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[0][1]) + activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Add") self.assertEqual(activity["actor"], self.local_user.remote_id) self.assertEqual(activity["target"], self.list.remote_id) @@ -214,7 +220,7 @@ class ListActionViews(TestCase): }, ) request_two.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.list.add_book(request_one) views.list.add_book(request_two) @@ -256,7 +262,7 @@ class ListActionViews(TestCase): ) request_three.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.list.add_book(request_one) views.list.add_book(request_two) views.list.add_book(request_three) @@ -271,7 +277,7 @@ class ListActionViews(TestCase): remove_request = self.factory.post("", {"item": items[1].id}) remove_request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.list.remove_book(remove_request, self.list.id) items = self.list.listitem_set.order_by("order").all() self.assertEqual(items[0].book, self.book) @@ -293,7 +299,7 @@ class ListActionViews(TestCase): }, ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.ListItem.objects.create( book_list=self.list, user=self.local_user, @@ -330,7 +336,7 @@ class ListActionViews(TestCase): its order should be at the end of the approved books and before the remaining pending books. """ - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.ListItem.objects.create( book_list=self.list, user=self.local_user, @@ -370,7 +376,7 @@ class ListActionViews(TestCase): ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): view(request, self.list.id) items = self.list.listitem_set.order_by("order").all() @@ -422,7 +428,7 @@ class ListActionViews(TestCase): ) request_three.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.list.add_book(request_one) views.list.add_book(request_two) views.list.add_book(request_three) @@ -437,7 +443,7 @@ class ListActionViews(TestCase): set_position_request = self.factory.post("", {"position": 1}) set_position_request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.list.set_book_position(set_position_request, items[2].id) items = self.list.listitem_set.order_by("order").all() self.assertEqual(items[0].book, self.book_three) @@ -460,10 +466,12 @@ class ListActionViews(TestCase): ) request.user = self.rat - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: views.list.add_book(request) self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[0][1]) + activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Add") self.assertEqual(activity["actor"], self.rat.remote_id) self.assertEqual(activity["target"], self.list.remote_id) @@ -486,11 +494,13 @@ class ListActionViews(TestCase): ) request.user = self.rat - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: views.list.add_book(request) self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[0][1]) + activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Add") self.assertEqual(activity["actor"], self.rat.remote_id) @@ -516,10 +526,12 @@ class ListActionViews(TestCase): ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: views.list.add_book(request) self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[0][1]) + activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Add") self.assertEqual(activity["actor"], self.local_user.remote_id) self.assertEqual(activity["target"], self.list.remote_id) @@ -532,7 +544,7 @@ class ListActionViews(TestCase): def test_remove_book(self): """take an item off a list""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): item = models.ListItem.objects.create( book_list=self.list, user=self.local_user, @@ -549,13 +561,13 @@ class ListActionViews(TestCase): ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.list.remove_book(request, self.list.id) self.assertFalse(self.list.listitem_set.exists()) def test_remove_book_unauthorized(self): """take an item off a list""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): item = models.ListItem.objects.create( book_list=self.list, user=self.local_user, book=self.book, order=1 ) diff --git a/bookwyrm/tests/views/test_notifications.py b/bookwyrm/tests/views/test_notifications.py index dd28a811..5df62b1d 100644 --- a/bookwyrm/tests/views/test_notifications.py +++ b/bookwyrm/tests/views/test_notifications.py @@ -25,7 +25,7 @@ class NotificationViews(TestCase): local=True, localname="mouse", ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): self.status = models.Status.objects.create( content="hi", user=self.local_user, diff --git a/bookwyrm/tests/views/test_outbox.py b/bookwyrm/tests/views/test_outbox.py index a1f62cc6..5c5d47b0 100644 --- a/bookwyrm/tests/views/test_outbox.py +++ b/bookwyrm/tests/views/test_outbox.py @@ -11,7 +11,7 @@ from bookwyrm.settings import USER_AGENT # pylint: disable=too-many-public-methods -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") class OutboxView(TestCase): """sends out activities""" diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index 4e5206f6..4ec50165 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -64,7 +64,7 @@ class ReadingViews(TestCase): }, ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.ReadingStatus.as_view()(request, "start", self.book.id) self.assertEqual(shelf.books.get(), self.book) @@ -100,7 +100,7 @@ class ReadingViews(TestCase): }, ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.ReadingStatus.as_view()(request, "start", self.book.id) self.assertEqual(shelf.books.get(), self.book) @@ -124,7 +124,7 @@ class ReadingViews(TestCase): def test_start_reading_reshelve(self, *_): """begin a book""" to_read_shelf = self.local_user.shelf_set.get(identifier=models.Shelf.TO_READ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.ShelfBook.objects.create( shelf=to_read_shelf, book=self.book, user=self.local_user ) @@ -135,7 +135,7 @@ class ReadingViews(TestCase): request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.ReadingStatus.as_view()(request, "start", self.book.id) self.assertFalse(to_read_shelf.books.exists()) @@ -162,7 +162,7 @@ class ReadingViews(TestCase): ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.ReadingStatus.as_view()(request, "finish", self.book.id) self.assertEqual(shelf.books.get(), self.book) @@ -267,7 +267,7 @@ class ReadingViews(TestCase): }, ) request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): views.update_progress(request, self.book.id) status = models.Comment.objects.get() diff --git a/bookwyrm/tests/views/test_readthrough.py b/bookwyrm/tests/views/test_readthrough.py index ef149ce3..5b554748 100644 --- a/bookwyrm/tests/views/test_readthrough.py +++ b/bookwyrm/tests/views/test_readthrough.py @@ -9,7 +9,7 @@ from bookwyrm import models @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") class ReadThrough(TestCase): @@ -32,7 +32,7 @@ class ReadThrough(TestCase): "cinco", "cinco@example.com", "seissiete", local=True, localname="cinco" ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): self.client.force_login(self.user) @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") diff --git a/bookwyrm/tests/views/test_rss_feed.py b/bookwyrm/tests/views/test_rss_feed.py index d4d11261..409c306d 100644 --- a/bookwyrm/tests/views/test_rss_feed.py +++ b/bookwyrm/tests/views/test_rss_feed.py @@ -6,7 +6,7 @@ from bookwyrm import models from bookwyrm.views import rss_feed -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.activitystreams.ActivityStream.get_activity_stream") @patch("bookwyrm.activitystreams.add_status_task.delay") class RssFeedView(TestCase): diff --git a/bookwyrm/tests/views/test_search.py b/bookwyrm/tests/views/test_search.py index 3299249a..f8045511 100644 --- a/bookwyrm/tests/views/test_search.py +++ b/bookwyrm/tests/views/test_search.py @@ -139,7 +139,7 @@ class Views(TestCase): def test_search_lists(self): """searches remote connectors""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): booklist = models.List.objects.create( user=self.local_user, name="test list" ) diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index db61b152..b5d7ac16 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -14,7 +14,7 @@ from bookwyrm.tests.validate_html import validate_html @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.activitystreams.remove_status_task.delay") -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") class StatusViews(TestCase): """viewing and creating statuses""" @@ -310,7 +310,7 @@ http://www.fish.com/""" with patch("bookwyrm.activitystreams.remove_status_task.delay") as redis_mock: view(request, status.id) self.assertTrue(redis_mock.called) - activity = json.loads(mock.call_args_list[1][0][1]) + activity = json.loads(mock.call_args_list[1][1]["args"][1]) self.assertEqual(activity["type"], "Delete") self.assertEqual(activity["object"]["type"], "Tombstone") status.refresh_from_db() @@ -344,7 +344,7 @@ http://www.fish.com/""" with patch("bookwyrm.activitystreams.remove_status_task.delay") as redis_mock: view(request, status.id) self.assertTrue(redis_mock.called) - activity = json.loads(mock.call_args_list[1][0][1]) + activity = json.loads(mock.call_args_list[1][1]["args"][1]) self.assertEqual(activity["type"], "Delete") self.assertEqual(activity["object"]["type"], "Tombstone") status.refresh_from_db() @@ -396,7 +396,7 @@ http://www.fish.com/""" request.user = self.local_user view(request, "comment", existing_status_id=status.id) - activity = json.loads(mock.call_args_list[1][0][1]) + activity = json.loads(mock.call_args_list[1][1]["args"][1]) self.assertEqual(activity["type"], "Update") self.assertEqual(activity["object"]["id"], status.remote_id) diff --git a/bookwyrm/tests/views/test_user.py b/bookwyrm/tests/views/test_user.py index 1183fa24..ddb029cc 100644 --- a/bookwyrm/tests/views/test_user.py +++ b/bookwyrm/tests/views/test_user.py @@ -34,9 +34,11 @@ class UserViews(TestCase): self.book = models.Edition.objects.create( title="test", parent_work=models.Work.objects.create(title="test work") ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"), patch( - "bookwyrm.suggested_users.rerank_suggestions_task.delay" - ), patch("bookwyrm.activitystreams.add_book_statuses_task.delay"): + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ), patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.add_book_statuses_task.delay" + ): models.ShelfBook.objects.create( book=self.book, user=self.local_user, diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 839d783f..514bb7e6 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -237,7 +237,41 @@ urlpatterns = [ re_path(r"^search/?$", views.Search.as_view(), name="search"), # imports re_path(r"^import/?$", views.Import.as_view(), name="import"), - re_path(r"^import/(\d+)/?$", views.ImportStatus.as_view(), name="import-status"), + re_path( + r"^import/(?P%(confirmation_code)s
\" at login."
-msgstr "Oder gibt den code \"%(confirmation_code)s
\" beim Login ein."
+msgstr "Oder gibt den Code „%(confirmation_code)s
“ bei der Anmeldung ein."
#: bookwyrm/templates/email/confirm/subject.html:2
msgid "Please confirm your email"
@@ -945,12 +966,12 @@ msgstr "Bitte bestätige deine E-Mail-Adresse"
#: bookwyrm/templates/email/confirm/text_content.html:10
#, python-format
msgid "Or enter the code \"%(confirmation_code)s\" at login."
-msgstr "Oder gibt den code \"%(confirmation_code)s
\" beim Login ein."
+msgstr "Oder gibt den Code „%(confirmation_code)s
“ bei der Anmeldung ein."
#: bookwyrm/templates/email/html_layout.html:15
#: bookwyrm/templates/email/text_layout.html:2
msgid "Hi there,"
-msgstr "Moin,"
+msgstr "Hallo,"
#: bookwyrm/templates/email/html_layout.html:21
#, python-format
@@ -959,7 +980,7 @@ msgstr "BookWyrm wird auf über %(site_n
#: bookwyrm/templates/email/invite/text_content.html:4
#, python-format
msgid "You're invited to join %(site_name)s! Click the link below to create an account."
-msgstr "Du bist eingeladen, %(site_name)s beizutreten! Klicke auf den Link unten um einen Account zu erstellen."
+msgstr "Du bist eingeladen, %(site_name)s beizutreten! Klicke auf den Link unten, um ein Benutzer*inkonto zu erstellen."
#: bookwyrm/templates/email/invite/text_content.html:8
#, python-format
@@ -990,15 +1011,15 @@ msgstr "Erfahre mehr über %(site_name)s:"
#: bookwyrm/templates/email/password_reset/text_content.html:4
#, python-format
msgid "You requested to reset your %(site_name)s password. Click the link below to set a new password and log in to your account."
-msgstr "Du hast beantragt, dein %(site_name)s Passwort zu ändern. Klicke auf den Link unten, um ein neues Passwort zu erstellen und dich einzuloggen."
+msgstr "Du hast beantragt, dein %(site_name)s-Passwort zu ändern. Klicke auf den Link unten, um ein neues Passwort zu erstellen und dich anzumelden."
#: bookwyrm/templates/email/password_reset/html_content.html:9
-#: bookwyrm/templates/password_reset.html:4
-#: bookwyrm/templates/password_reset.html:10
-#: bookwyrm/templates/password_reset_request.html:4
-#: bookwyrm/templates/password_reset_request.html:10
+#: bookwyrm/templates/landing/password_reset.html:4
+#: bookwyrm/templates/landing/password_reset.html:10
+#: bookwyrm/templates/landing/password_reset_request.html:4
+#: bookwyrm/templates/landing/password_reset_request.html:10
msgid "Reset Password"
-msgstr "Passwort zurücksetzen!"
+msgstr "Passwort zurücksetzen"
#: bookwyrm/templates/email/password_reset/html_content.html:13
#: bookwyrm/templates/email/password_reset/text_content.html:8
@@ -1008,7 +1029,7 @@ msgstr "Falls du dein Passwort gar nicht zurücksetzen wolltest, kannst du diese
#: bookwyrm/templates/email/password_reset/subject.html:2
#, python-format
msgid "Reset your %(site_name)s password"
-msgstr "Dein Passwort für %(site_name)s zurücksetzen"
+msgstr "Passwort für %(site_name)s zurücksetzen"
#: bookwyrm/templates/feed/direct_messages.html:8
#, python-format
@@ -1031,44 +1052,45 @@ msgstr "Du hast momentan keine Nachrichten."
#: bookwyrm/templates/feed/feed.html:22
#, python-format
msgid "load 0 unread status(es)"
-msgstr "lese 0 ungelesene Status"
+msgstr "lade 0 ungelesene Statusmeldung(en)"
#: bookwyrm/templates/feed/feed.html:38
msgid "There aren't any activities right now! Try following a user to get started"
-msgstr "Hier sind noch keine Aktivitäten! Folge anderen, um loszulegen"
+msgstr "Hier sind noch keine Aktivitäten! Folge Anderen, um loszulegen"
#: bookwyrm/templates/feed/goal_card.html:6
#: bookwyrm/templates/feed/layout.html:90
#: bookwyrm/templates/user/goal_form.html:6
#, python-format
msgid "%(year)s Reading Goal"
-msgstr "%(year)s Leseziel"
+msgstr "Leseziel für %(year)s"
#: bookwyrm/templates/feed/goal_card.html:18
#, python-format
msgid "You can set or change your reading goal any time from your profile page"
-msgstr "Du kannst dein Leseziel jederzeit auf deiner Profilseite setzen oder ändern."
+msgstr "Du kannst dein Leseziel jederzeit auf deiner Profilseite festlegen oder ändern"
#: bookwyrm/templates/feed/layout.html:5
msgid "Updates"
msgstr "Updates"
-#: bookwyrm/templates/feed/layout.html:12
-#: bookwyrm/templates/user/books_header.html:3
-msgid "Your books"
+#: bookwyrm/templates/feed/layout.html:12 bookwyrm/templates/layout.html:106
+msgid "Your Books"
msgstr "Deine Bücher"
#: bookwyrm/templates/feed/layout.html:14
msgid "There are no books here right now! Try searching for a book to get started"
-msgstr "Hier sind noch keine Bücher! Versuche nach Büchern zu suchen um loszulegen"
+msgstr "Hier sind noch keine Bücher! Versuche, nach Büchern zu suchen, um loszulegen"
#: bookwyrm/templates/feed/layout.html:25
#: bookwyrm/templates/shelf/shelf.html:38
+#: bookwyrm/templates/user/books_header.html:4
msgid "To Read"
msgstr "Zu lesen"
#: bookwyrm/templates/feed/layout.html:26
#: bookwyrm/templates/shelf/shelf.html:40
+#: bookwyrm/templates/user/books_header.html:6
msgid "Currently Reading"
msgstr "Lese ich gerade"
@@ -1076,6 +1098,7 @@ msgstr "Lese ich gerade"
#: bookwyrm/templates/shelf/shelf.html:42
#: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:23
#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:12
+#: bookwyrm/templates/user/books_header.html:8
msgid "Read"
msgstr "Gelesen"
@@ -1086,11 +1109,11 @@ msgstr "Wem noch folgen?"
#: bookwyrm/templates/feed/suggested_users.html:9
msgid "Don't show suggested users"
-msgstr "Keine vorgeschlagenen User anzeigen"
+msgstr "Keine vorgeschlagenen Benutzer*innen anzeigen"
#: bookwyrm/templates/feed/suggested_users.html:14
msgid "View directory"
-msgstr "Zeige Verzeichnis"
+msgstr "Verzeichnis anzeigen"
#: bookwyrm/templates/get_started/book_preview.html:6
#, python-format
@@ -1102,14 +1125,14 @@ msgid "What are you reading?"
msgstr "Was liest du gerade?"
#: bookwyrm/templates/get_started/books.html:9
-#: bookwyrm/templates/layout.html:45 bookwyrm/templates/lists/list.html:137
+#: bookwyrm/templates/layout.html:45 bookwyrm/templates/lists/list.html:138
msgid "Search for a book"
msgstr "Nach einem Buch suchen"
#: bookwyrm/templates/get_started/books.html:11
#, python-format
msgid "No books found for \"%(query)s\""
-msgstr "Keine Bücher für \"%(query)s\" gefunden"
+msgstr "Keine Bücher für „%(query)s“ gefunden"
#: bookwyrm/templates/get_started/books.html:11
#, python-format
@@ -1120,8 +1143,9 @@ msgstr "Du kannst Bücher hinzufügen, wenn du %(site_name)s benutzt."
#: bookwyrm/templates/get_started/books.html:17
#: bookwyrm/templates/get_started/users.html:18
#: bookwyrm/templates/get_started/users.html:19
-#: bookwyrm/templates/layout.html:51 bookwyrm/templates/layout.html:52
-#: bookwyrm/templates/lists/list.html:141
+#: bookwyrm/templates/groups/group.html:19
+#: bookwyrm/templates/groups/group.html:20 bookwyrm/templates/layout.html:51
+#: bookwyrm/templates/layout.html:52 bookwyrm/templates/lists/list.html:142
#: bookwyrm/templates/search/layout.html:4
#: bookwyrm/templates/search/layout.html:9
msgid "Search"
@@ -1137,7 +1161,7 @@ msgid "Popular on %(site_name)s"
msgstr "Auf %(site_name)s beliebt"
#: bookwyrm/templates/get_started/books.html:58
-#: bookwyrm/templates/lists/list.html:154
+#: bookwyrm/templates/lists/list.html:155
msgid "No books found"
msgstr "Keine Bücher gefunden"
@@ -1184,16 +1208,16 @@ msgstr "Fertigstellen"
#: bookwyrm/templates/get_started/profile.html:15
#: bookwyrm/templates/preferences/edit_user.html:42
msgid "Display name:"
-msgstr "Displayname:"
+msgstr "Anzeigename:"
#: bookwyrm/templates/get_started/profile.html:22
#: bookwyrm/templates/preferences/edit_user.html:49
msgid "Summary:"
-msgstr "Bio:"
+msgstr "Zusammenfassung:"
#: bookwyrm/templates/get_started/profile.html:23
msgid "A little bit about you"
-msgstr "Etwas über dich"
+msgstr "Einige Angaben zu dir"
#: bookwyrm/templates/get_started/profile.html:32
#: bookwyrm/templates/preferences/edit_user.html:27
@@ -1203,16 +1227,16 @@ msgstr "Avatar:"
#: bookwyrm/templates/get_started/profile.html:42
#: bookwyrm/templates/preferences/edit_user.html:110
msgid "Manually approve followers:"
-msgstr "Folgende manuell bestätigen"
+msgstr "Follower*innen manuell bestätigen:"
#: bookwyrm/templates/get_started/profile.html:48
#: bookwyrm/templates/preferences/edit_user.html:80
msgid "Show this account in suggested users:"
-msgstr "Diesen Account in vorgeschlagenen Usern zeigen"
+msgstr "Dieses Benutzer*inkonto in vorgeschlagene Benutzer*innen einschließen:"
#: bookwyrm/templates/get_started/profile.html:52
msgid "Your account will show up in the directory, and may be recommended to other BookWyrm users."
-msgstr "Dein Account wird im Verzeichnis gezeigt und möglicherweise anderen Usern vorgeschlagen."
+msgstr "Dein Benutzer*inkonto wird im Verzeichnis gezeigt und möglicherweise anderen Benutzer*innen vorgeschlagen."
#: bookwyrm/templates/get_started/users.html:11
msgid "Search for a user"
@@ -1221,11 +1245,112 @@ msgstr "Benutzer*in suchen"
#: bookwyrm/templates/get_started/users.html:13
#, python-format
msgid "No users found for \"%(query)s\""
-msgstr "Keine Nutzer*innen für \"%(query)s\" gefunden"
+msgstr "Keine Benutzer*innen für „%(query)s“ gefunden"
+
+#: bookwyrm/templates/groups/create_form.html:5
+msgid "Create Group"
+msgstr "Gruppe erstellen"
+
+#: bookwyrm/templates/groups/created_text.html:4
+#, python-format
+msgid "Managed by %(username)s"
+msgstr "Administriert von %(username)s"
+
+#: bookwyrm/templates/groups/delete_group_modal.html:4
+msgid "Delete this group?"
+msgstr "Diese Gruppe löschen?"
+
+#: bookwyrm/templates/groups/delete_group_modal.html:7
+#: bookwyrm/templates/lists/delete_list_modal.html:7
+msgid "This action cannot be un-done"
+msgstr "Diese Aktion kann nicht rückgängig gemacht werden"
+
+#: bookwyrm/templates/groups/delete_group_modal.html:15
+#: bookwyrm/templates/lists/delete_list_modal.html:15
+#: bookwyrm/templates/settings/announcements/announcement.html:20
+#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:49
+#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:36
+#: bookwyrm/templates/snippets/delete_readthrough_modal.html:15
+#: bookwyrm/templates/snippets/follow_request_buttons.html:12
+#: bookwyrm/templates/snippets/join_invitation_buttons.html:13
+msgid "Delete"
+msgstr "Löschen"
+
+#: bookwyrm/templates/groups/edit_form.html:5
+msgid "Edit Group"
+msgstr "Gruppe bearbeiten"
+
+#: bookwyrm/templates/groups/find_users.html:6
+msgid "Add new members!"
+msgstr "Mitglieder hinzufügen!"
+
+#: bookwyrm/templates/groups/form.html:8
+msgid "Group Name:"
+msgstr "Gruppenname:"
+
+#: bookwyrm/templates/groups/form.html:12
+msgid "Group Description:"
+msgstr "Gruppenbeschreibung:"
+
+#: bookwyrm/templates/groups/form.html:30
+msgid "Delete group"
+msgstr "Gruppe löschen"
+
+#: bookwyrm/templates/groups/group.html:15
+msgid "Search to add a user"
+msgstr "Hinzuzufügende*n Benutzer*in suchen"
+
+#: bookwyrm/templates/groups/group.html:36
+msgid "This group has no lists"
+msgstr "Diese Gruppe enthält keine Listen"
+
+#: bookwyrm/templates/groups/layout.html:16
+msgid "Edit group"
+msgstr "Gruppe bearbeiten"
+
+#: bookwyrm/templates/groups/members.html:8
+msgid "Members can add and remove books on a group's book lists"
+msgstr "Mitglieder können Bücher in den Buchlisten einer Gruppe hinzufügen und entfernen"
+
+#: bookwyrm/templates/groups/members.html:19
+msgid "Leave group"
+msgstr "Gruppe verlassen"
+
+#: bookwyrm/templates/groups/members.html:41
+#: bookwyrm/templates/groups/suggested_users.html:32
+#: bookwyrm/templates/snippets/suggested_users.html:31
+#: bookwyrm/templates/user/user_preview.html:36
+msgid "Follows you"
+msgstr "Folgt dir"
+
+#: bookwyrm/templates/groups/suggested_users.html:17
+#: bookwyrm/templates/snippets/suggested_users.html:16
+#, python-format
+msgid "%(mutuals)s follower you follow"
+msgid_plural "%(mutuals)s followers you follow"
+msgstr[0] "%(mutuals)s Follower*in, der*die du folgst"
+msgstr[1] "%(mutuals)s Follower*innen, denen du folgst"
+
+#: bookwyrm/templates/groups/suggested_users.html:24
+#: bookwyrm/templates/snippets/suggested_users.html:23
+#, python-format
+msgid "%(shared_books)s book on your shelves"
+msgid_plural "%(shared_books)s books on your shelves"
+msgstr[0] "%(shared_books)s Buch in deinen Regalen"
+msgstr[1] "%(shared_books)s Bücher in deinen Regalen"
+
+#: bookwyrm/templates/groups/suggested_users.html:40
+#, python-format
+msgid "No potential members found for \"%(user_query)s\""
+msgstr "Keine potentiellen Mitglieder für „%(user_query)s“ gefunden"
+
+#: bookwyrm/templates/groups/user_groups.html:15
+msgid "Manager"
+msgstr "Gruppenadministrator*in"
#: bookwyrm/templates/import/import.html:5
#: bookwyrm/templates/import/import.html:9
-#: bookwyrm/templates/shelf/shelf.html:57
+#: bookwyrm/templates/shelf/shelf.html:61
msgid "Import Books"
msgstr "Bücher importieren"
@@ -1239,11 +1364,11 @@ msgstr "Datei:"
#: bookwyrm/templates/import/import.html:45
msgid "Include reviews"
-msgstr "Bewertungen importieren"
+msgstr "Besprechungen einschließen"
#: bookwyrm/templates/import/import.html:50
msgid "Privacy setting for imported reviews:"
-msgstr "Datenschutzeinstellung für importierte Bewertungen"
+msgstr "Datenschutzeinstellung für importierte Besprechungen:"
#: bookwyrm/templates/import/import.html:56
#: bookwyrm/templates/settings/federation/instance_blocklist.html:64
@@ -1252,107 +1377,167 @@ msgstr "Importieren"
#: bookwyrm/templates/import/import.html:61
msgid "Recent Imports"
-msgstr "Aktuelle Importe"
+msgstr "Zuletzt importiert"
#: bookwyrm/templates/import/import.html:63
msgid "No recent imports"
msgstr "Keine aktuellen Importe"
#: bookwyrm/templates/import/import_status.html:6
-#: bookwyrm/templates/import/import_status.html:10
+#: bookwyrm/templates/import/import_status.html:15
+#: bookwyrm/templates/import/import_status.html:29
msgid "Import Status"
msgstr "Importstatus"
-#: bookwyrm/templates/import/import_status.html:11
-msgid "Back to imports"
-msgstr "Zurück zu Importen"
+#: bookwyrm/templates/import/import_status.html:13
+#: bookwyrm/templates/import/import_status.html:27
+msgid "Retry Status"
+msgstr ""
-#: bookwyrm/templates/import/import_status.html:15
+#: bookwyrm/templates/import/import_status.html:22
+msgid "Imports"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:39
msgid "Import started:"
msgstr "Import gestartet:"
-#: bookwyrm/templates/import/import_status.html:20
-msgid "Import completed:"
-msgstr "Import abgeschlossen:"
-
-#: bookwyrm/templates/import/import_status.html:24
-msgid "TASK FAILED"
-msgstr "AUFGABE GESCHEITERT"
-
-#: bookwyrm/templates/import/import_status.html:32
-msgid "Import still in progress."
-msgstr "Import läuft noch."
-
-#: bookwyrm/templates/import/import_status.html:34
-msgid "(Hit reload to update!)"
-msgstr "(Aktualisiere für ein Update!)"
-
-#: bookwyrm/templates/import/import_status.html:41
-msgid "Failed to load"
-msgstr "Laden fehlgeschlagen"
+#: bookwyrm/templates/import/import_status.html:48
+msgid "In progress"
+msgstr ""
#: bookwyrm/templates/import/import_status.html:50
-#, python-format
-msgid "Jump to the bottom of the list to select the %(failed_count)s items which failed to import."
-msgstr "Zum Ende der Liste springen, um die %(failed_count)s Einträge, deren Import fehlschlug, auszuwählen."
+msgid "Refresh"
+msgstr ""
#: bookwyrm/templates/import/import_status.html:62
#, python-format
-msgid "Line %(index)s: %(title)s by %(author)s"
-msgstr "Zeile %(index)s: %(title)s von %(author)s"
+msgid "%(display_counter)s item needs manual approval."
+msgid_plural "%(display_counter)s items need manual approval."
+msgstr[0] ""
+msgstr[1] ""
-#: bookwyrm/templates/import/import_status.html:82
-msgid "Select all"
-msgstr "Alle auswählen"
+#: bookwyrm/templates/import/import_status.html:67
+#: bookwyrm/templates/import/manual_review.html:8
+msgid "Review items"
+msgstr ""
-#: bookwyrm/templates/import/import_status.html:85
-msgid "Retry items"
-msgstr "Punkte erneut versuchen"
+#: bookwyrm/templates/import/import_status.html:73
+#, python-format
+msgid "%(display_counter)s item failed to import."
+msgid_plural "%(display_counter)s items failed to import."
+msgstr[0] ""
+msgstr[1] ""
-#: bookwyrm/templates/import/import_status.html:112
-msgid "Successfully imported"
-msgstr "Erfolgreich importiert"
+#: bookwyrm/templates/import/import_status.html:79
+msgid "View and troubleshoot failed items"
+msgstr ""
-#: bookwyrm/templates/import/import_status.html:114
-msgid "Import Progress"
-msgstr "Import-Fortschritt"
+#: bookwyrm/templates/import/import_status.html:91
+msgid "Row"
+msgstr ""
-#: bookwyrm/templates/import/import_status.html:119
-msgid "Book"
-msgstr "Buch"
-
-#: bookwyrm/templates/import/import_status.html:122
-#: bookwyrm/templates/shelf/shelf.html:128
-#: bookwyrm/templates/shelf/shelf.html:150
+#: bookwyrm/templates/import/import_status.html:94
+#: bookwyrm/templates/shelf/shelf.html:141
+#: bookwyrm/templates/shelf/shelf.html:163
msgid "Title"
msgstr "Titel"
-#: bookwyrm/templates/import/import_status.html:125
-#: bookwyrm/templates/shelf/shelf.html:129
-#: bookwyrm/templates/shelf/shelf.html:153
+#: bookwyrm/templates/import/import_status.html:97
+msgid "ISBN"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:100
+#: bookwyrm/templates/shelf/shelf.html:142
+#: bookwyrm/templates/shelf/shelf.html:166
msgid "Author"
msgstr "Autor*in"
-#: bookwyrm/templates/import/import_status.html:148
+#: bookwyrm/templates/import/import_status.html:103
+msgid "Shelf"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:106
+#: bookwyrm/templates/import/manual_review.html:13
+#: bookwyrm/templates/snippets/create_status.html:17
+msgid "Review"
+msgstr "Besprechen"
+
+#: bookwyrm/templates/import/import_status.html:110
+msgid "Book"
+msgstr "Buch"
+
+#: bookwyrm/templates/import/import_status.html:113
+#: bookwyrm/templates/settings/announcements/announcements.html:38
+#: bookwyrm/templates/settings/federation/instance_list.html:46
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:44
+#: bookwyrm/templates/settings/invites/status_filter.html:5
+#: bookwyrm/templates/settings/users/user_admin.html:34
+#: bookwyrm/templates/settings/users/user_info.html:20
+msgid "Status"
+msgstr "Status"
+
+#: bookwyrm/templates/import/import_status.html:144
+msgid "View imported review"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:158
msgid "Imported"
msgstr "Importiert"
+#: bookwyrm/templates/import/import_status.html:164
+msgid "Needs manual review"
+msgstr ""
+
+#: bookwyrm/templates/import/manual_review.html:5
+#: bookwyrm/templates/import/troubleshoot.html:4
+msgid "Import Troubleshooting"
+msgstr ""
+
+#: bookwyrm/templates/import/manual_review.html:21
+msgid "Approving a suggestion will permanently add the suggested book to your shelves and associate your reading dates, reviews, and ratings with that book."
+msgstr ""
+
+#: bookwyrm/templates/import/manual_review.html:56
+#: bookwyrm/templates/lists/curate.html:57
+msgid "Approve"
+msgstr "Bestätigen"
+
+#: bookwyrm/templates/import/manual_review.html:64
+msgid "Reject"
+msgstr ""
+
#: bookwyrm/templates/import/tooltip.html:6
msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account."
msgstr "Du kannst deine Goodreads-Daten von der Import/Export-Seite deines Goodreads-Kontos downloaden."
-#: bookwyrm/templates/invite.html:4 bookwyrm/templates/invite.html:8
-#: bookwyrm/templates/login.html:49
-msgid "Create an Account"
-msgstr "Erstelle einen Account"
+#: bookwyrm/templates/import/troubleshoot.html:7
+msgid "Failed items"
+msgstr ""
-#: bookwyrm/templates/invite.html:21
-msgid "Permission Denied"
-msgstr "Zugiff verweigert"
+#: bookwyrm/templates/import/troubleshoot.html:12
+msgid "Troubleshooting"
+msgstr ""
-#: bookwyrm/templates/invite.html:22
-msgid "Sorry! This invite code is no longer valid."
-msgstr "Sorry! Dieser Einladecode ist mehr gültig."
+#: bookwyrm/templates/import/troubleshoot.html:20
+msgid "Re-trying an import can fix missing items in cases such as:"
+msgstr ""
+
+#: bookwyrm/templates/import/troubleshoot.html:23
+msgid "The book has been added to the instance since this import"
+msgstr ""
+
+#: bookwyrm/templates/import/troubleshoot.html:24
+msgid "A transient error or timeout caused the external data source to be unavailable."
+msgstr ""
+
+#: bookwyrm/templates/import/troubleshoot.html:25
+msgid "BookWyrm has been updated since this import with a bug fix"
+msgstr ""
+
+#: bookwyrm/templates/import/troubleshoot.html:28
+msgid "Contact your admin or open an issue if you are seeing unexpected failed items."
+msgstr ""
#: bookwyrm/templates/landing/about.html:7 bookwyrm/templates/layout.html:230
#, python-format
@@ -1369,9 +1554,23 @@ msgstr "Verhaltenskodex"
msgid "Privacy Policy"
msgstr "Datenschutzerklärung"
+#: bookwyrm/templates/landing/invite.html:4
+#: bookwyrm/templates/landing/invite.html:8
+#: bookwyrm/templates/landing/login.html:49
+msgid "Create an Account"
+msgstr "Erstelle ein Benutzer*inkonto"
+
+#: bookwyrm/templates/landing/invite.html:21
+msgid "Permission Denied"
+msgstr "Zugiff verweigert"
+
+#: bookwyrm/templates/landing/invite.html:22
+msgid "Sorry! This invite code is no longer valid."
+msgstr "Tut uns leid! Dieser Einladungscode ist mehr gültig."
+
#: bookwyrm/templates/landing/landing.html:6
msgid "Recent Books"
-msgstr "Aktive Bücher"
+msgstr "Zuletzt aktive Bücher"
#: bookwyrm/templates/landing/layout.html:17
msgid "Decentralized"
@@ -1388,7 +1587,7 @@ msgstr "Nichtkommerziell"
#: bookwyrm/templates/landing/layout.html:45
#, python-format
msgid "Join %(name)s"
-msgstr "Tritt %(name)s bei"
+msgstr "%(name)s beitreten"
#: bookwyrm/templates/landing/layout.html:47
msgid "Request an Invitation"
@@ -1405,7 +1604,54 @@ msgstr "Danke! Deine Anfrage ist eingegangen."
#: bookwyrm/templates/landing/layout.html:82
msgid "Your Account"
-msgstr "Dein Account"
+msgstr "Dein Benutzer*inkonto"
+
+#: bookwyrm/templates/landing/login.html:4
+msgid "Login"
+msgstr "Anmeldung"
+
+#: bookwyrm/templates/landing/login.html:7
+#: bookwyrm/templates/landing/login.html:37 bookwyrm/templates/layout.html:179
+msgid "Log in"
+msgstr "Anmelden"
+
+#: bookwyrm/templates/landing/login.html:15
+msgid "Success! Email address confirmed."
+msgstr "Alles klar! E-Mail-Adresse bestätigt."
+
+#: bookwyrm/templates/landing/login.html:21 bookwyrm/templates/layout.html:170
+#: bookwyrm/templates/snippets/register_form.html:4
+msgid "Username:"
+msgstr "Benutzer*inname:"
+
+#: bookwyrm/templates/landing/login.html:27
+#: bookwyrm/templates/landing/password_reset.html:17
+#: bookwyrm/templates/layout.html:174
+#: bookwyrm/templates/snippets/register_form.html:22
+msgid "Password:"
+msgstr "Passwort:"
+
+#: bookwyrm/templates/landing/login.html:40 bookwyrm/templates/layout.html:176
+msgid "Forgot your password?"
+msgstr "Passwort vergessen?"
+
+#: bookwyrm/templates/landing/login.html:62
+msgid "More about this site"
+msgstr "Mehr über diese Seite"
+
+#: bookwyrm/templates/landing/password_reset.html:23
+#: bookwyrm/templates/preferences/change_password.html:18
+#: bookwyrm/templates/preferences/delete_user.html:20
+msgid "Confirm password:"
+msgstr "Passwort bestätigen:"
+
+#: bookwyrm/templates/landing/password_reset_request.html:14
+msgid "A link to reset your password will be sent to your email address"
+msgstr "Ein Link zum Zurücksetzen deines Passworts wird an deine E-Mail-Adresse geschickt"
+
+#: bookwyrm/templates/landing/password_reset_request.html:28
+msgid "Reset password"
+msgstr "Passwort zurücksetzen"
#: bookwyrm/templates/layout.html:13
#, python-format
@@ -1418,16 +1664,12 @@ msgstr "Nach einem Buch, einem*r Benutzer*in oder einer Liste suchen"
#: bookwyrm/templates/layout.html:61 bookwyrm/templates/layout.html:62
msgid "Main navigation menu"
-msgstr "Navigationshauptmenü"
+msgstr "Navigations-Hauptmenü"
#: bookwyrm/templates/layout.html:72
msgid "Feed"
msgstr "Feed"
-#: bookwyrm/templates/layout.html:106
-msgid "Your Books"
-msgstr "Deine Bücher"
-
#: bookwyrm/templates/layout.html:116
msgid "Settings"
msgstr "Einstellungen"
@@ -1454,25 +1696,10 @@ msgstr "Abmelden"
msgid "Notifications"
msgstr "Benachrichtigungen"
-#: bookwyrm/templates/layout.html:170 bookwyrm/templates/layout.html:174
-#: bookwyrm/templates/login.html:21
-#: bookwyrm/templates/snippets/register_form.html:4
-msgid "Username:"
-msgstr "Benutzer*inname:"
-
#: bookwyrm/templates/layout.html:175
msgid "password"
msgstr "Passwort"
-#: bookwyrm/templates/layout.html:176 bookwyrm/templates/login.html:40
-msgid "Forgot your password?"
-msgstr "Passwort vergessen?"
-
-#: bookwyrm/templates/layout.html:179 bookwyrm/templates/login.html:7
-#: bookwyrm/templates/login.html:37
-msgid "Log in"
-msgstr "Anmelden"
-
#: bookwyrm/templates/layout.html:187
msgid "Join"
msgstr "Beitreten"
@@ -1487,7 +1714,7 @@ msgstr "Fehler beim veröffentlichen des Status"
#: bookwyrm/templates/layout.html:234
msgid "Contact site admin"
-msgstr "Admin kontaktieren"
+msgstr "Administrator*in kontaktieren"
#: bookwyrm/templates/layout.html:238
msgid "Documentation"
@@ -1513,10 +1740,15 @@ msgstr "Liste erstellen"
#: bookwyrm/templates/lists/created_text.html:5
#, python-format
+msgid "Created by %(username)s and managed by %(groupname)s"
+msgstr "Erstellt von %(username)s und administriert von %(groupname)s"
+
+#: bookwyrm/templates/lists/created_text.html:7
+#, python-format
msgid "Created and curated by %(username)s"
msgstr "Erstellt und betreut von %(username)s"
-#: bookwyrm/templates/lists/created_text.html:7
+#: bookwyrm/templates/lists/created_text.html:9
#, python-format
msgid "Created by %(username)s"
msgstr "Erstellt von %(username)s"
@@ -1537,10 +1769,6 @@ msgstr "Du bist soweit!"
msgid "Suggested by"
msgstr "Vorgeschlagen von"
-#: bookwyrm/templates/lists/curate.html:57
-msgid "Approve"
-msgstr "Bestätigen"
-
#: bookwyrm/templates/lists/curate.html:63
msgid "Discard"
msgstr "Ablehnen"
@@ -1549,118 +1777,130 @@ msgstr "Ablehnen"
msgid "Delete this list?"
msgstr "Diese Liste löschen?"
-#: bookwyrm/templates/lists/delete_list_modal.html:7
-msgid "This action cannot be un-done"
-msgstr "Diese Aktion kann nicht rückgängig gemacht werden"
-
-#: bookwyrm/templates/lists/delete_list_modal.html:15
-#: bookwyrm/templates/settings/announcements/announcement.html:20
-#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:49
-#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:36
-#: bookwyrm/templates/snippets/delete_readthrough_modal.html:15
-#: bookwyrm/templates/snippets/follow_request_buttons.html:12
-msgid "Delete"
-msgstr "Löschen"
-
#: bookwyrm/templates/lists/edit_form.html:5
#: bookwyrm/templates/lists/layout.html:16
msgid "Edit List"
msgstr "Liste bearbeiten"
-#: bookwyrm/templates/lists/form.html:18
+#: bookwyrm/templates/lists/form.html:19
msgid "List curation:"
msgstr "Listenkuratierung:"
-#: bookwyrm/templates/lists/form.html:21
+#: bookwyrm/templates/lists/form.html:22
msgid "Closed"
msgstr "Geschlossen"
-#: bookwyrm/templates/lists/form.html:22
+#: bookwyrm/templates/lists/form.html:23
msgid "Only you can add and remove books to this list"
msgstr "Nur du kannst Bücher hinzufügen oder entfernen"
-#: bookwyrm/templates/lists/form.html:26
+#: bookwyrm/templates/lists/form.html:27
msgid "Curated"
msgstr "Kuratiert"
-#: bookwyrm/templates/lists/form.html:27
+#: bookwyrm/templates/lists/form.html:28
msgid "Anyone can suggest books, subject to your approval"
-msgstr "Alle können Bücher vorschlagen, du kannst diese bestätigen"
+msgstr "Jede*r kann Bücher vorschlagen, du musst diese bestätigen"
-#: bookwyrm/templates/lists/form.html:31
+#: bookwyrm/templates/lists/form.html:32
msgctxt "curation type"
msgid "Open"
msgstr "Offen"
-#: bookwyrm/templates/lists/form.html:32
+#: bookwyrm/templates/lists/form.html:33
msgid "Anyone can add books to this list"
-msgstr "Alle können Bücher hinzufügen"
+msgstr "Jede*r kann Bücher hinzufügen"
-#: bookwyrm/templates/lists/form.html:50
+#: bookwyrm/templates/lists/form.html:37
+msgid "Group"
+msgstr "Gruppe"
+
+#: bookwyrm/templates/lists/form.html:38
+msgid "Group members can add to and remove from this list"
+msgstr "Gruppenmitglieder können Bücher zu dieser Liste hinzufügen und von dieser entfernen"
+
+#: bookwyrm/templates/lists/form.html:41
+msgid "Select Group"
+msgstr "Gruppe auswählen"
+
+#: bookwyrm/templates/lists/form.html:45
+msgid "Select a group"
+msgstr "Eine Gruppe auswählen"
+
+#: bookwyrm/templates/lists/form.html:56
+msgid "You don't have any Groups yet!"
+msgstr "Du hast noch keine Gruppen!"
+
+#: bookwyrm/templates/lists/form.html:58
+msgid "Create a Group"
+msgstr "Gruppe erstellen"
+
+#: bookwyrm/templates/lists/form.html:81
msgid "Delete list"
msgstr "Liste löschen"
-#: bookwyrm/templates/lists/list.html:20
+#: bookwyrm/templates/lists/list.html:21
msgid "You successfully suggested a book for this list!"
-msgstr "Du hast erfolgreich ein Buch für diese Liste vorgeschlagen!"
+msgstr "Dein Buchvorschlag wurde dieser Liste hinzugefügt!"
-#: bookwyrm/templates/lists/list.html:22
+#: bookwyrm/templates/lists/list.html:23
msgid "You successfully added a book to this list!"
-msgstr "Du hast erfolgreich ein Buch zu dieser Liste hinzugefügt!"
+msgstr "Du hast ein Buch zu dieser Liste hinzugefügt!"
-#: bookwyrm/templates/lists/list.html:28
+#: bookwyrm/templates/lists/list.html:29
msgid "This list is currently empty"
msgstr "Diese Liste ist momentan leer"
-#: bookwyrm/templates/lists/list.html:66
+#: bookwyrm/templates/lists/list.html:67
#, python-format
msgid "Added by %(username)s"
msgstr "Hinzugefügt von %(username)s"
-#: bookwyrm/templates/lists/list.html:75
+#: bookwyrm/templates/lists/list.html:76
msgid "List position"
msgstr "Listenposition"
-#: bookwyrm/templates/lists/list.html:81
+#: bookwyrm/templates/lists/list.html:82
msgid "Set"
msgstr "Übernehmen"
-#: bookwyrm/templates/lists/list.html:91
+#: bookwyrm/templates/lists/list.html:92
+#: bookwyrm/templates/snippets/remove_from_group_button.html:19
#: bookwyrm/templates/snippets/shelf_selector.html:26
msgid "Remove"
msgstr "Entfernen"
-#: bookwyrm/templates/lists/list.html:105
-#: bookwyrm/templates/lists/list.html:122
+#: bookwyrm/templates/lists/list.html:106
+#: bookwyrm/templates/lists/list.html:123
msgid "Sort List"
msgstr "Liste sortieren"
-#: bookwyrm/templates/lists/list.html:115
+#: bookwyrm/templates/lists/list.html:116
msgid "Direction"
msgstr "Reihenfolge"
-#: bookwyrm/templates/lists/list.html:129
+#: bookwyrm/templates/lists/list.html:130
msgid "Add Books"
msgstr "Bücher hinzufügen"
-#: bookwyrm/templates/lists/list.html:131
+#: bookwyrm/templates/lists/list.html:132
msgid "Suggest Books"
msgstr "Bücher vorschlagen"
-#: bookwyrm/templates/lists/list.html:142
+#: bookwyrm/templates/lists/list.html:143
msgid "search"
msgstr "suchen"
-#: bookwyrm/templates/lists/list.html:148
+#: bookwyrm/templates/lists/list.html:149
msgid "Clear search"
-msgstr "Suche leeren"
+msgstr "Suche zurücksetzen"
-#: bookwyrm/templates/lists/list.html:153
+#: bookwyrm/templates/lists/list.html:154
#, python-format
msgid "No books found matching the query \"%(query)s\""
-msgstr "Keine passenden Bücher zu \"%(query)s\" gefunden"
+msgstr "Keine passenden Bücher zu „%(query)s“ gefunden"
-#: bookwyrm/templates/lists/list.html:181
+#: bookwyrm/templates/lists/list.html:182
msgid "Suggest"
msgstr "Vorschlagen"
@@ -1672,35 +1912,23 @@ msgstr "Gespeichert"
msgid "Your Lists"
msgstr "Deine Listen"
-#: bookwyrm/templates/lists/lists.html:35
+#: bookwyrm/templates/lists/lists.html:36
msgid "All Lists"
msgstr "Alle Listen"
-#: bookwyrm/templates/lists/lists.html:39
+#: bookwyrm/templates/lists/lists.html:40
msgid "Saved Lists"
msgstr "Gespeicherte Listen"
-#: bookwyrm/templates/login.html:4
-msgid "Login"
-msgstr "Anmeldung"
-
-#: bookwyrm/templates/login.html:15
-msgid "Success! Email address confirmed."
-msgstr "Alles klar! E-Mai- Adresse bestätigt."
-
-#: bookwyrm/templates/login.html:27 bookwyrm/templates/password_reset.html:17
-#: bookwyrm/templates/snippets/register_form.html:22
-msgid "Password:"
-msgstr "Passwort:"
-
-#: bookwyrm/templates/login.html:62
-msgid "More about this site"
-msgstr "Mehr über diese Seite"
+#: bookwyrm/templates/notifications/items/accept.html:16
+#, python-format
+msgid "accepted your invitation to join group \"%(group_name)s\""
+msgstr "hat deine Einladung angenommen, der Gruppe „%(group_name)s“ beizutreten"
#: bookwyrm/templates/notifications/items/add.html:24
#, python-format
msgid "added %(book_title)s to your list \"%(list_name)s\""
-msgstr "%(book_title)s zu deiner Liste \"%(list_name)s\" hinzugefügt"
+msgstr "%(book_title)s zu deiner Liste „%(list_name)s“ hinzugefügt"
#: bookwyrm/templates/notifications/items/add.html:31
#, python-format
@@ -1710,7 +1938,7 @@ msgstr "hat vorgeschlagen, %(book_title)s
#: bookwyrm/templates/notifications/items/boost.html:19
#, python-format
msgid "boosted your review of %(book_title)s"
-msgstr "hat deine Bewertung von %(book_title)s geteilt"
+msgstr "hat deine Besprechung von %(book_title)s geteilt"
#: bookwyrm/templates/notifications/items/boost.html:25
#, python-format
@@ -1730,11 +1958,11 @@ msgstr "hat deinen Status geteilt"
#: bookwyrm/templates/notifications/items/fav.html:19
#, python-format
msgid "liked your review of %(book_title)s"
-msgstr "hat deine Besprechung von %(book_title)s favorisiert"
+msgstr "hat deine Besprechung von %(book_title)s favorisiert"
#: bookwyrm/templates/notifications/items/fav.html:25
#, python-format
-msgid "liked your comment on%(book_title)s"
+msgid "liked your comment on %(book_title)s"
msgstr "hat deinen Kommentar zu %(book_title)s favorisiert"
#: bookwyrm/templates/notifications/items/fav.html:31
@@ -1753,17 +1981,32 @@ msgstr "folgt dir"
#: bookwyrm/templates/notifications/items/follow_request.html:11
msgid "sent you a follow request"
-msgstr "hat dir eine Folgeanfrage geschickt"
+msgstr "möchte dir folgen"
#: bookwyrm/templates/notifications/items/import.html:14
#, python-format
msgid "Your import completed."
msgstr "Dein Import ist fertig."
+#: bookwyrm/templates/notifications/items/invite.html:15
+#, python-format
+msgid "invited you to join the group \"%(group_name)s\""
+msgstr "hat dich eingeladen, der Gruppe „%(group_name)s“ beizutreten"
+
+#: bookwyrm/templates/notifications/items/join.html:16
+#, python-format
+msgid "has joined your group \"%(group_name)s\""
+msgstr "ist deiner Gruppe „%(group_name)s“ beigetreten"
+
+#: bookwyrm/templates/notifications/items/leave.html:16
+#, python-format
+msgid "has left your group \"%(group_name)s\""
+msgstr "hat deine Gruppe „%(group_name)s“ verlassen"
+
#: bookwyrm/templates/notifications/items/mention.html:20
#, python-format
msgid "mentioned you in a review of %(book_title)s"
-msgstr "hat dich in einer Bewertung von %(book_title)s erwähnt"
+msgstr "hat dich in einer Besprechung von %(book_title)s erwähnt"
#: bookwyrm/templates/notifications/items/mention.html:26
#, python-format
@@ -1780,10 +2023,20 @@ msgstr "hat dich in einem Zitat von %(book_titl
msgid "mentioned you in a status"
msgstr "hat dich in einem Status erwähnt"
+#: bookwyrm/templates/notifications/items/remove.html:17
+#, python-format
+msgid "has been removed from your group \"%(group_name)s\""
+msgstr "wurde aus deiner Gruppe „%(group_name)s“ entfernt"
+
+#: bookwyrm/templates/notifications/items/remove.html:23
+#, python-format
+msgid "You have been removed from the \"%(group_name)s\" group"
+msgstr "Du wurdest aus der Gruppe „%(group_name)s“ entfernt"
+
#: bookwyrm/templates/notifications/items/reply.html:21
#, python-format
msgid "replied to your review of %(book_title)s"
-msgstr "hat auf deine Bewertung von %(book_title)s geantwortet "
+msgstr "hat auf deine Besprechung von %(book_title)s geantwortet"
#: bookwyrm/templates/notifications/items/reply.html:27
#, python-format
@@ -1805,6 +2058,21 @@ msgstr "hat auf deinen Status report needs moderation."
msgstr "Eine neue Meldung muss moderiert werden."
+#: bookwyrm/templates/notifications/items/update.html:16
+#, python-format
+msgid "has changed the privacy level for %(group_name)s"
+msgstr "hat die Sichtbarkeit von %(group_name)s geändert"
+
+#: bookwyrm/templates/notifications/items/update.html:20
+#, python-format
+msgid "has changed the name of %(group_name)s"
+msgstr "hat den Namen von %(group_name)s geändert"
+
+#: bookwyrm/templates/notifications/items/update.html:24
+#, python-format
+msgid "has changed the description of %(group_name)s"
+msgstr "hat die Beschreibung von %(group_name)s geändert"
+
#: bookwyrm/templates/notifications/notifications_page.html:18
msgid "Delete notifications"
msgstr "Benachrichtigungen löschen"
@@ -1821,29 +2089,15 @@ msgstr "Erwähnungen"
msgid "You're all caught up!"
msgstr "Du bist auf dem neusten Stand!"
-#: bookwyrm/templates/password_reset.html:23
-#: bookwyrm/templates/preferences/change_password.html:18
-#: bookwyrm/templates/preferences/delete_user.html:20
-msgid "Confirm password:"
-msgstr "Passwort bestätigen:"
-
-#: bookwyrm/templates/password_reset_request.html:14
-msgid "A link to reset your password will be sent to your email address"
-msgstr "Ein Link zum Zurücksetzen deines Passworts wird an deine Mailadresse geschickt"
-
-#: bookwyrm/templates/password_reset_request.html:28
-msgid "Reset password"
-msgstr "Passwort zurücksetzen"
-
#: bookwyrm/templates/preferences/blocks.html:4
#: bookwyrm/templates/preferences/blocks.html:7
#: bookwyrm/templates/preferences/layout.html:31
msgid "Blocked Users"
-msgstr "Blockierte Nutzer*innen"
+msgstr "Gesperrte Benutzer*innen"
#: bookwyrm/templates/preferences/blocks.html:12
msgid "No users currently blocked."
-msgstr "Momentan keine Nutzer*innen blockiert."
+msgstr "Momentan keine Benutzer*innen gesperrt."
#: bookwyrm/templates/preferences/change_password.html:4
#: bookwyrm/templates/preferences/change_password.html:7
@@ -1866,11 +2120,11 @@ msgstr "Benutzer*inkonto löschen"
#: bookwyrm/templates/preferences/delete_user.html:12
msgid "Permanently delete account"
-msgstr "Account permanent löschen"
+msgstr "Benutzer*inkonto dauerhaft löschen"
#: bookwyrm/templates/preferences/delete_user.html:14
msgid "Deleting your account cannot be undone. The username will not be available to register in the future."
-msgstr "Das Löschen des Accounts kann nicht rückgängig gemacht werden. Der Username kann nicht erneut registriert werden."
+msgstr "Das Löschen des Benutzer*inkonto kann nicht rückgängig gemacht werden. Der Benutzer*inname kann nicht erneut registriert werden."
#: bookwyrm/templates/preferences/edit_user.html:4
#: bookwyrm/templates/preferences/edit_user.html:7
@@ -1896,7 +2150,7 @@ msgstr "Privatsphäre"
#: bookwyrm/templates/preferences/edit_user.html:72
msgid "Show reading goal prompt in feed:"
-msgstr "Zeige Leseziel-Abfrage im Feed:"
+msgstr "Frage Leseziel im Feed ab:"
#: bookwyrm/templates/preferences/edit_user.html:76
msgid "Show suggested users:"
@@ -1905,7 +2159,7 @@ msgstr "Zeige vorgeschlagene Benutzer*innen:"
#: bookwyrm/templates/preferences/edit_user.html:85
#, python-format
msgid "Your account will show up in the directory, and may be recommended to other BookWyrm users."
-msgstr "Dein Account wird im directory angezeigt und eventuell anderen Usern empfohlen."
+msgstr "Dein Benutzer*inkonto wird im Verzeichnis angezeigt und eventuell anderen Benutzer*innen empfohlen."
#: bookwyrm/templates/preferences/edit_user.html:89
msgid "Preferred Timezone: "
@@ -1926,17 +2180,17 @@ msgstr "Beziehungen"
#: bookwyrm/templates/reading_progress/finish.html:5
#, python-format
msgid "Finish \"%(book_title)s\""
-msgstr "\"%(book_title)s\" abschließen"
+msgstr "„%(book_title)s“ abschließen"
#: bookwyrm/templates/reading_progress/start.html:5
#, python-format
msgid "Start \"%(book_title)s\""
-msgstr "\"%(book_title)s\" beginnen"
+msgstr "„%(book_title)s“ beginnen"
#: bookwyrm/templates/reading_progress/want.html:5
#, python-format
msgid "Want to Read \"%(book_title)s\""
-msgstr "\"%(book_title)s\" auf Leseliste setzen"
+msgstr "„%(book_title)s“ auf Leseliste setzen"
#: bookwyrm/templates/search/book.html:47
#: bookwyrm/templates/settings/reports/reports.html:25
@@ -1958,7 +2212,7 @@ msgstr "Buch manuell hinzufügen"
#: bookwyrm/templates/search/book.html:116
msgid "Log in to import or add books."
-msgstr "Log dich ein, um Bücher zu importieren oder hinzuzufügen."
+msgstr "Melde dich an, um Bücher zu importieren oder hinzuzufügen."
#: bookwyrm/templates/search/layout.html:16
msgid "Search query"
@@ -2000,7 +2254,7 @@ msgstr "Ankündigung bearbeiten"
#: bookwyrm/templates/settings/announcements/announcement.html:35
msgid "Visible:"
-msgstr "Sichtbar"
+msgstr "Sichtbar:"
#: bookwyrm/templates/settings/announcements/announcement.html:38
msgid "True"
@@ -2067,15 +2321,6 @@ msgstr "Startdatum"
msgid "End date"
msgstr "Enddatum"
-#: bookwyrm/templates/settings/announcements/announcements.html:38
-#: bookwyrm/templates/settings/federation/instance_list.html:46
-#: bookwyrm/templates/settings/invites/manage_invite_requests.html:44
-#: bookwyrm/templates/settings/invites/status_filter.html:5
-#: bookwyrm/templates/settings/users/user_admin.html:34
-#: bookwyrm/templates/settings/users/user_info.html:20
-msgid "Status"
-msgstr "Status"
-
#: bookwyrm/templates/settings/announcements/announcements.html:48
msgid "active"
msgstr "aktiv"
@@ -2184,7 +2429,7 @@ msgstr "E-Mail-Sperrliste"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:18
msgid "When someone tries to register with an email from this domain, no account will be created. The registration process will appear to have worked."
-msgstr "Wenn sich jemand mit einer E-Mail-Adresse von dieser Domain zu registrieren versucht, wird kein Account erstellt. Die Registrierung wird so aussehen als hätte sie funktioniert."
+msgstr "Wenn sich jemand mit einer E-Mail-Adresse von dieser Domain zu registrieren versucht, wird kein Benutzer*inkonto erstellt. Es wird aber so aussehen, als ob die Registrierung funktioniert hätte."
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:25
msgid "Domain"
@@ -2257,7 +2502,7 @@ msgid "Details"
msgstr "Details"
#: bookwyrm/templates/settings/federation/instance.html:35
-#: bookwyrm/templates/user/layout.html:63
+#: bookwyrm/templates/user/layout.html:64
msgid "Activity"
msgstr "Aktivität"
@@ -2268,7 +2513,7 @@ msgstr "Benutzer*innen:"
#: bookwyrm/templates/settings/federation/instance.html:41
#: bookwyrm/templates/settings/federation/instance.html:47
msgid "View all"
-msgstr "Alle anzeigen"
+msgstr "Alle(s) anzeigen"
#: bookwyrm/templates/settings/federation/instance.html:44
#: bookwyrm/templates/settings/users/user_info.html:56
@@ -2281,7 +2526,7 @@ msgstr "Folgen wir:"
#: bookwyrm/templates/settings/federation/instance.html:55
msgid "Followed by them:"
-msgstr "Folgen:"
+msgstr "Folgen uns:"
#: bookwyrm/templates/settings/federation/instance.html:60
msgid "Blocked by us:"
@@ -2331,7 +2576,7 @@ msgstr "Sperrliste importieren"
#: bookwyrm/templates/settings/federation/instance_blocklist.html:26
#: bookwyrm/templates/snippets/goal_progress.html:7
msgid "Success!"
-msgstr "Erfolg!"
+msgstr "Hat funktioniert!"
#: bookwyrm/templates/settings/federation/instance_blocklist.html:30
msgid "Successfully blocked:"
@@ -2339,7 +2584,7 @@ msgstr "Erfolgreich gesperrt:"
#: bookwyrm/templates/settings/federation/instance_blocklist.html:32
msgid "Failed:"
-msgstr "Fehlgeschlagen"
+msgstr "Fehlgeschlagen:"
#: bookwyrm/templates/settings/federation/instance_list.html:3
#: bookwyrm/templates/settings/federation/instance_list.html:5
@@ -2420,11 +2665,11 @@ msgstr "Ignorieren"
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:97
msgid "Un-ignore"
-msgstr "Un-ignorieren"
+msgstr "Doch nicht ignorieren"
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:108
msgid "Back to pending requests"
-msgstr "Zurück zu ausstehenden Anfragen"
+msgstr "Zurück zu den ausstehenden Anfragen"
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:110
msgid "View ignored requests"
@@ -2436,11 +2681,11 @@ msgstr "Neue Einladung erzeugen"
#: bookwyrm/templates/settings/invites/manage_invites.html:27
msgid "Expiry:"
-msgstr "Ablaufen:"
+msgstr "Ablaufdatum:"
#: bookwyrm/templates/settings/invites/manage_invites.html:33
msgid "Use limit:"
-msgstr "Begrenzte Benutzung"
+msgstr "Verwendungslimit:"
#: bookwyrm/templates/settings/invites/manage_invites.html:40
msgid "Create Invite"
@@ -2452,15 +2697,15 @@ msgstr "Link"
#: bookwyrm/templates/settings/invites/manage_invites.html:48
msgid "Expires"
-msgstr "Läuft aus"
+msgstr "Läuft ab am"
#: bookwyrm/templates/settings/invites/manage_invites.html:49
msgid "Max uses"
-msgstr "Maximale Benutzungen"
+msgstr "Maximale Verwendungen"
#: bookwyrm/templates/settings/invites/manage_invites.html:50
msgid "Times used"
-msgstr "Mal benutzt"
+msgstr "Anzahl Verwendungen"
#: bookwyrm/templates/settings/invites/manage_invites.html:53
msgid "No active invites"
@@ -2487,7 +2732,7 @@ msgstr "IP-Addressen-Sperrliste"
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:18
msgid "Any traffic from this IP address will get a 404 response when trying to access any part of the application."
-msgstr "Jeder Datenverkehr von dieser IP-Adresse erhält eine 404-Antwort, wenn versucht wird, auf einen beliebigen Teil der Anwendung zuzugreifen."
+msgstr "Datenverkehr von dieser IP-Adresse erhält eine 404-Antwort, wenn versucht wird, auf einen beliebigen Teil der Anwendung zuzugreifen."
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:24
msgid "Address"
@@ -2499,7 +2744,7 @@ msgstr "Derzeit sind keine IP-Adressen gesperrt"
#: bookwyrm/templates/settings/ip_blocklist/ip_tooltip.html:6
msgid "You can block IP ranges using CIDR syntax."
-msgstr "Du kannst IP-Bereiche mittels CIDR-Syntax blockieren."
+msgstr "Du kannst IP-Bereiche mittels CIDR-Syntax sperren."
#: bookwyrm/templates/settings/layout.html:4
msgid "Administration"
@@ -2507,7 +2752,7 @@ msgstr "Administration"
#: bookwyrm/templates/settings/layout.html:29
msgid "Manage Users"
-msgstr "Nutzer*innen verwalten"
+msgstr "Benutzer*innen verwalten"
#: bookwyrm/templates/settings/layout.html:51
msgid "Moderation"
@@ -2542,7 +2787,7 @@ msgstr "Zurück zu den Meldungen"
#: bookwyrm/templates/settings/reports/report.html:23
msgid "Moderator Comments"
-msgstr "Moderator:innenkommentare"
+msgstr "Moderator*innenkommentare"
#: bookwyrm/templates/settings/reports/report.html:41
#: bookwyrm/templates/snippets/create_status.html:28
@@ -2555,7 +2800,7 @@ msgstr "Gemeldete Statusmeldungen"
#: bookwyrm/templates/settings/reports/report.html:48
msgid "No statuses reported"
-msgstr "Keine Beiträge gemeldet"
+msgstr "Keine Statusmeldungen gemeldet"
#: bookwyrm/templates/settings/reports/report.html:54
msgid "Status has been deleted"
@@ -2572,11 +2817,11 @@ msgstr "Gemeldet von %(username)s"
#: bookwyrm/templates/settings/reports/report_preview.html:30
msgid "Re-open"
-msgstr "Wiedereröffnen"
+msgstr "Erneut öffnen"
#: bookwyrm/templates/settings/reports/report_preview.html:32
msgid "Resolve"
-msgstr "Lösen"
+msgstr "Beheben"
#: bookwyrm/templates/settings/reports/reports.html:6
#, python-format
@@ -2609,7 +2854,7 @@ msgstr "Bilder"
#: bookwyrm/templates/settings/site.html:12
#: bookwyrm/templates/settings/site.html:74
msgid "Footer Content"
-msgstr "Inhalt des Footers"
+msgstr "Inhalt der Fußzeile"
#: bookwyrm/templates/settings/site.html:13
#: bookwyrm/templates/settings/site.html:98
@@ -2618,7 +2863,7 @@ msgstr "Registrierung"
#: bookwyrm/templates/settings/site.html:24
msgid "Instance Name:"
-msgstr "Instanzname"
+msgstr "Instanzname:"
#: bookwyrm/templates/settings/site.html:28
msgid "Tagline:"
@@ -2626,7 +2871,7 @@ msgstr "Motto:"
#: bookwyrm/templates/settings/site.html:32
msgid "Instance description:"
-msgstr "Instanzbeschreibung"
+msgstr "Instanzbeschreibung:"
#: bookwyrm/templates/settings/site.html:36
msgid "Short description:"
@@ -2642,7 +2887,7 @@ msgstr "Verhaltenskodex:"
#: bookwyrm/templates/settings/site.html:45
msgid "Privacy Policy:"
-msgstr "Datenschutzerklärung"
+msgstr "Datenschutzerklärung:"
#: bookwyrm/templates/settings/site.html:57
msgid "Logo:"
@@ -2650,7 +2895,7 @@ msgstr "Logo:"
#: bookwyrm/templates/settings/site.html:61
msgid "Logo small:"
-msgstr "Logo klein"
+msgstr "Kleines Logo:"
#: bookwyrm/templates/settings/site.html:65
msgid "Favicon:"
@@ -2658,11 +2903,11 @@ msgstr "Favicon:"
#: bookwyrm/templates/settings/site.html:77
msgid "Support link:"
-msgstr "Unterstützungslink"
+msgstr "Support-Link:"
#: bookwyrm/templates/settings/site.html:81
msgid "Support title:"
-msgstr "Unterstützungstitel"
+msgstr "Support-Titel:"
#: bookwyrm/templates/settings/site.html:85
msgid "Admin email:"
@@ -2670,7 +2915,7 @@ msgstr "E-Mail-Adresse des*r Administrator*in:"
#: bookwyrm/templates/settings/site.html:89
msgid "Additional info:"
-msgstr "Zusätzliche Info:"
+msgstr "Zusätzliche Angaben:"
#: bookwyrm/templates/settings/site.html:103
msgid "Allow registration"
@@ -2682,15 +2927,15 @@ msgstr "Einladungsanfragen zulassen"
#: bookwyrm/templates/settings/site.html:115
msgid "Require users to confirm email address"
-msgstr "User müssen ihre E-Mail-Adresse bestätigen"
+msgstr "Benutzer*innen müssen ihre E-Mail-Adresse bestätigen"
#: bookwyrm/templates/settings/site.html:117
msgid "(Recommended if registration is open)"
-msgstr "(Vorschlagen falls die Registrierung offen ist)"
+msgstr "(empfohlen, falls Selbstregistrierung zulässig ist)"
#: bookwyrm/templates/settings/site.html:120
msgid "Registration closed text:"
-msgstr "Registrierungen geschlossen text"
+msgstr "Hinweis, wenn Selbtregistrierung nicht erlaubt ist:"
#: bookwyrm/templates/settings/site.html:124
msgid "Invite request text:"
@@ -2699,12 +2944,12 @@ msgstr "Hinweis für Einladungsanfragen:"
#: bookwyrm/templates/settings/users/delete_user_form.html:5
#: bookwyrm/templates/settings/users/user_moderation_actions.html:31
msgid "Permanently delete user"
-msgstr "User permanent löschen"
+msgstr "Benutzer*in dauerhaft löschen"
#: bookwyrm/templates/settings/users/delete_user_form.html:12
#, python-format
msgid "Are you sure you want to delete %(username)s's account? This action cannot be undone. To proceed, please enter your password to confirm deletion."
-msgstr "Bist du sicher, dass du %(username)ss Account löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden. Zur Bestätigung gib bitte dein Passwort ein."
+msgstr "Bist du sicher, dass du das Benutzer*inkonto „%(username)s“ löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden. Zur Bestätigung gib bitte dein Passwort ein."
#: bookwyrm/templates/settings/users/delete_user_form.html:17
msgid "Your password:"
@@ -2712,7 +2957,7 @@ msgstr "Dein Passwort:"
#: bookwyrm/templates/settings/users/user.html:7
msgid "Back to users"
-msgstr "Zurück zu Benutzer*innen"
+msgstr "Zurück zu den Benutzer*innen"
#: bookwyrm/templates/settings/users/user_admin.html:7
#, python-format
@@ -2749,7 +2994,7 @@ msgstr "Inaktiv"
#: bookwyrm/templates/settings/users/user_admin.html:52
#: bookwyrm/templates/settings/users/user_info.html:120
msgid "Not set"
-msgstr "Nicht gesetzt"
+msgstr "Nicht festgelegt"
#: bookwyrm/templates/settings/users/user_info.html:16
msgid "View user profile"
@@ -2805,7 +3050,7 @@ msgstr "Instanz anzeigen"
#: bookwyrm/templates/settings/users/user_moderation_actions.html:5
msgid "Permanently deleted"
-msgstr "Permanent gelöscht"
+msgstr "Dauerhaft gelöscht"
#: bookwyrm/templates/settings/users/user_moderation_actions.html:13
#: bookwyrm/templates/snippets/status/status_options.html:32
@@ -2833,57 +3078,70 @@ msgstr "Regal erstellen"
msgid "Edit Shelf"
msgstr "Regal bearbeiten"
-#: bookwyrm/templates/shelf/shelf.html:28 bookwyrm/views/shelf.py:55
+#: bookwyrm/templates/shelf/shelf.html:28 bookwyrm/views/shelf/shelf.py:53
msgid "All books"
msgstr "Alle Bücher"
-#: bookwyrm/templates/shelf/shelf.html:55
+#: bookwyrm/templates/shelf/shelf.html:69
msgid "Create shelf"
msgstr "Regal erstellen"
-#: bookwyrm/templates/shelf/shelf.html:77
+#: bookwyrm/templates/shelf/shelf.html:90
#, python-format
msgid "%(formatted_count)s book"
msgid_plural "%(formatted_count)s books"
msgstr[0] "%(formatted_count)s Buch"
msgstr[1] "%(formatted_count)s Bücher"
-#: bookwyrm/templates/shelf/shelf.html:84
+#: bookwyrm/templates/shelf/shelf.html:97
#, python-format
msgid "(showing %(start)s-%(end)s)"
-msgstr "(zeige %(start)s-%(end)s)"
+msgstr "(Anzeige: %(start)s&endash;%(end)s)"
-#: bookwyrm/templates/shelf/shelf.html:96
+#: bookwyrm/templates/shelf/shelf.html:109
msgid "Edit shelf"
msgstr "Regal bearbeiten"
-#: bookwyrm/templates/shelf/shelf.html:104
+#: bookwyrm/templates/shelf/shelf.html:117
msgid "Delete shelf"
msgstr "Regal löschen"
-#: bookwyrm/templates/shelf/shelf.html:132
-#: bookwyrm/templates/shelf/shelf.html:158
+#: bookwyrm/templates/shelf/shelf.html:145
+#: bookwyrm/templates/shelf/shelf.html:171
msgid "Shelved"
msgstr "Ins Regal gestellt"
-#: bookwyrm/templates/shelf/shelf.html:133
-#: bookwyrm/templates/shelf/shelf.html:161
+#: bookwyrm/templates/shelf/shelf.html:146
+#: bookwyrm/templates/shelf/shelf.html:174
msgid "Started"
msgstr "Gestartet"
-#: bookwyrm/templates/shelf/shelf.html:134
-#: bookwyrm/templates/shelf/shelf.html:164
+#: bookwyrm/templates/shelf/shelf.html:147
+#: bookwyrm/templates/shelf/shelf.html:177
msgid "Finished"
msgstr "Abgeschlossen"
-#: bookwyrm/templates/shelf/shelf.html:190
+#: bookwyrm/templates/shelf/shelf.html:203
msgid "This shelf is empty."
msgstr "Dieses Regal ist leer."
+#: bookwyrm/templates/snippets/add_to_group_button.html:15
+msgid "Invite"
+msgstr "Einladen"
+
+#: bookwyrm/templates/snippets/add_to_group_button.html:24
+msgid "Uninvite"
+msgstr "Einladung stornieren"
+
+#: bookwyrm/templates/snippets/add_to_group_button.html:28
+#, python-format
+msgid "Remove @%(username)s"
+msgstr "@%(username)s entfernen"
+
#: bookwyrm/templates/snippets/announcement.html:31
#, python-format
msgid "Posted by %(username)s"
-msgstr "Von %(username)s veröffentlicht"
+msgstr "Veröffentlicht von %(username)s"
#: bookwyrm/templates/snippets/authors.html:22
#, python-format
@@ -2911,10 +3169,6 @@ msgstr "Teilen"
msgid "Un-boost"
msgstr "Teilen zurücknehmen"
-#: bookwyrm/templates/snippets/create_status.html:17
-msgid "Review"
-msgstr "Bewerten"
-
#: bookwyrm/templates/snippets/create_status.html:39
msgid "Quote"
msgstr "Zitieren"
@@ -2948,7 +3202,7 @@ msgstr "von %(pages)s Seiten"
#: bookwyrm/templates/snippets/status/layout.html:52
#: bookwyrm/templates/snippets/status/layout.html:53
msgid "Reply"
-msgstr "Antwort"
+msgstr "Antworten"
#: bookwyrm/templates/snippets/create_status/content_field.html:17
msgid "Content"
@@ -2975,12 +3229,13 @@ msgstr "Kommentar:"
#: bookwyrm/templates/snippets/privacy-icons.html:15
#: bookwyrm/templates/snippets/privacy-icons.html:16
#: bookwyrm/templates/snippets/privacy_select.html:20
+#: bookwyrm/templates/snippets/privacy_select_no_followers.html:17
msgid "Private"
msgstr "Privat"
#: bookwyrm/templates/snippets/create_status/post_options_block.html:21
msgid "Post"
-msgstr "Absenden"
+msgstr "Veröffentlichen"
#: bookwyrm/templates/snippets/create_status/quotation.html:17
msgid "Quote:"
@@ -3019,7 +3274,7 @@ msgstr "Diese Lesedaten löschen?"
#: bookwyrm/templates/snippets/delete_readthrough_modal.html:7
#, python-format
msgid "You are deleting this readthrough and its %(count)s associated progress updates."
-msgstr "Du löscht diesen Leseforschritt und %(count)s zugehörige Fortschrittsupdates."
+msgstr "Du löscht diesen Leseforschritt und %(count)s zugehörige Zwischenstände."
#: bookwyrm/templates/snippets/fav_button.html:16
#: bookwyrm/templates/snippets/fav_button.html:17
@@ -3070,13 +3325,14 @@ msgid "Unfollow"
msgstr "Entfolgen"
#: bookwyrm/templates/snippets/follow_request_buttons.html:7
+#: bookwyrm/templates/snippets/join_invitation_buttons.html:8
msgid "Accept"
msgstr "Annehmen"
#: bookwyrm/templates/snippets/form_rate_stars.html:20
#: bookwyrm/templates/snippets/stars.html:13
msgid "No rating"
-msgstr "Kein Rating"
+msgstr "Keine Bewertung"
#: bookwyrm/templates/snippets/form_rate_stars.html:28
#, python-format
@@ -3097,8 +3353,8 @@ msgstr[1] "%(rating)s Sterne"
#, python-format
msgid "set a goal to read %(counter)s book in %(year)s"
msgid_plural "set a goal to read %(counter)s books in %(year)s"
-msgstr[0] "Setze das Ziel, %(year)s %(counter)s Buch zu lesen"
-msgstr[1] "Setze das Ziel, %(year)s %(counter)s Bücher zu lesen"
+msgstr[0] "setze dir das Ziel, %(year)s %(counter)s Buch zu lesen"
+msgstr[1] "setze dir das Ziel, %(year)s %(counter)s Bücher zu lesen"
#: bookwyrm/templates/snippets/generated_status/rating.html:3
#, python-format
@@ -3117,12 +3373,12 @@ msgstr[1] "Besprechung von „%(book_title)s“ (%(display_rating)s Sterne): %(r
#: bookwyrm/templates/snippets/generated_status/review_pure_name.html:8
#, python-format
msgid "Review of \"%(book_title)s\": %(review_title)s"
-msgstr "Review von \"%(book_title)s\": %(review_title)s"
+msgstr "Besprechung von „%(book_title)s“: %(review_title)s"
#: bookwyrm/templates/snippets/goal_form.html:4
#, python-format
msgid "Set a goal for how many books you'll finish reading in %(year)s, and track your progress throughout the year."
-msgstr "Setze dir ein Ziel, wie viele Bücher du %(year)s lesen wirst und behalte deinen Fortschritt über's Jahr im Auge."
+msgstr "Setze dir ein Ziel, wie viele Bücher du %(year)s lesen willst und behalte deinen Fortschritt während des Jahrs im Blick."
#: bookwyrm/templates/snippets/goal_form.html:16
msgid "Reading goal:"
@@ -3134,12 +3390,12 @@ msgstr "Bücher"
#: bookwyrm/templates/snippets/goal_form.html:26
msgid "Goal privacy:"
-msgstr "Sichtbarkeit des Ziels"
+msgstr "Sichtbarkeit des Ziels:"
#: bookwyrm/templates/snippets/goal_form.html:33
#: bookwyrm/templates/snippets/reading_modals/layout.html:13
msgid "Post to feed"
-msgstr "Posten"
+msgstr "Im Feed veröffentlichen"
#: bookwyrm/templates/snippets/goal_form.html:37
msgid "Set goal"
@@ -3148,7 +3404,7 @@ msgstr "Ziel setzen"
#: bookwyrm/templates/snippets/goal_progress.html:9
#, python-format
msgid "%(percent)s%% complete!"
-msgstr "%(percent)s%% komplett!"
+msgstr "%(percent)s%% geschafft!"
#: bookwyrm/templates/snippets/goal_progress.html:12
#, python-format
@@ -3181,20 +3437,23 @@ msgstr "Weiter"
#: bookwyrm/templates/snippets/privacy-icons.html:3
#: bookwyrm/templates/snippets/privacy-icons.html:4
#: bookwyrm/templates/snippets/privacy_select.html:11
+#: bookwyrm/templates/snippets/privacy_select_no_followers.html:11
msgid "Public"
msgstr "Öffentlich"
#: bookwyrm/templates/snippets/privacy-icons.html:7
#: bookwyrm/templates/snippets/privacy-icons.html:8
#: bookwyrm/templates/snippets/privacy_select.html:14
+#: bookwyrm/templates/snippets/privacy_select_no_followers.html:14
msgid "Unlisted"
msgstr "Ungelistet"
#: bookwyrm/templates/snippets/privacy-icons.html:12
msgid "Followers-only"
-msgstr "Nur für Folgende"
+msgstr "Nur für Follower*innen"
#: bookwyrm/templates/snippets/privacy_select.html:6
+#: bookwyrm/templates/snippets/privacy_select_no_followers.html:6
msgid "Post privacy"
msgstr "Beitragssichtbarkeit"
@@ -3202,11 +3461,11 @@ msgstr "Beitragssichtbarkeit"
#: bookwyrm/templates/user/relationships/followers.html:6
#: bookwyrm/templates/user/relationships/layout.html:11
msgid "Followers"
-msgstr "Folgende"
+msgstr "Follower*innen"
#: bookwyrm/templates/snippets/rate_action.html:4
msgid "Leave a rating"
-msgstr "Raten"
+msgstr "Bewerten"
#: bookwyrm/templates/snippets/rate_action.html:19
msgid "Rate"
@@ -3215,7 +3474,7 @@ msgstr "Bewerten"
#: bookwyrm/templates/snippets/reading_modals/finish_reading_modal.html:6
#, python-format
msgid "Finish \"%(book_title)s\""
-msgstr "\"%(book_title)s\" abschließen"
+msgstr "„%(book_title)s“ abschließen"
#: bookwyrm/templates/snippets/reading_modals/finish_reading_modal.html:23
#: bookwyrm/templates/snippets/reading_modals/start_reading_modal.html:20
@@ -3226,7 +3485,7 @@ msgstr "Zu lesen angefangen"
#: bookwyrm/templates/snippets/reading_modals/finish_reading_modal.html:31
#: bookwyrm/templates/snippets/readthrough_form.html:20
msgid "Finished reading"
-msgstr "Zu Ende gelesen"
+msgstr "Lesen abgeschlossen"
#: bookwyrm/templates/snippets/reading_modals/form.html:9
msgid "(Optional)"
@@ -3235,17 +3494,17 @@ msgstr "(Optional)"
#: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:5
#: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:50
msgid "Update progress"
-msgstr "Update-Fortschritt"
+msgstr "Zwischenstand"
#: bookwyrm/templates/snippets/reading_modals/start_reading_modal.html:6
#, python-format
msgid "Start \"%(book_title)s\""
-msgstr "\"%(book_title)s\" beginnen"
+msgstr "„%(book_title)s“ beginnen"
#: bookwyrm/templates/snippets/reading_modals/want_to_read_modal.html:6
#, python-format
msgid "Want to Read \"%(book_title)s\""
-msgstr "\"%(book_title)s\" auf Leseliste setzen"
+msgstr "„%(book_title)s“ auf Leseliste setzen"
#: bookwyrm/templates/snippets/readthrough_form.html:14
msgid "Progress"
@@ -3267,11 +3526,11 @@ msgstr "@%(username)s melden"
#: bookwyrm/templates/snippets/report_modal.html:23
#, python-format
msgid "This report will be sent to %(site_name)s's moderators for review."
-msgstr "Diese Meldung wird an die Moderator:innen von %(site_name)s weitergeletiet."
+msgstr "Diese Meldung wird an die Moderato*innen von %(site_name)s weitergeleitet."
#: bookwyrm/templates/snippets/report_modal.html:24
msgid "More info about this report:"
-msgstr "Weitere Angeben zu dieser Meldung:"
+msgstr "Weitere Angaben zu dieser Meldung:"
#: bookwyrm/templates/snippets/shelf_selector.html:4
msgid "Move book"
@@ -3336,7 +3595,7 @@ msgstr "%(date)s bearbeitet"
msgid "commented on %(book)s"
msgstr "hat %(book)s kommentiert"
-#: bookwyrm/templates/snippets/status/headers/note.html:15
+#: bookwyrm/templates/snippets/status/headers/note.html:8
#, python-format
msgid "replied to %(username)s's status"
msgstr "hat auf die Statusmeldung von %(username)s geantwortet"
@@ -3354,7 +3613,7 @@ msgstr "hat %(book)s bewertet:"
#: bookwyrm/templates/snippets/status/headers/read.html:7
#, python-format
msgid "finished reading %(book)s"
-msgstr "hat %(book)s ausgelesen"
+msgstr "hat %(book)s abgeschlossen"
#: bookwyrm/templates/snippets/status/headers/reading.html:7
#, python-format
@@ -3374,7 +3633,7 @@ msgstr "%(username)s hat \n"
"Language-Team: English %(confirmation_code)s
\" at login."
+msgstr "Arba suveskite kodą \"%(confirmation_code)s
\" prisijungimo metu."
+
+#: bookwyrm/templates/email/confirm/subject.html:2
+msgid "Please confirm your email"
+msgstr "Patvirtinkite savo el. pašto adresą"
+
+#: bookwyrm/templates/email/confirm/text_content.html:10
+#, python-format
+msgid "Or enter the code \"%(confirmation_code)s\" at login."
+msgstr "Arba suveskite kodą \"%(confirmation_code)s\" prisijungimo metu."
+
+#: bookwyrm/templates/email/html_layout.html:15
+#: bookwyrm/templates/email/text_layout.html:2
+msgid "Hi there,"
+msgstr "Labas!"
+
+#: bookwyrm/templates/email/html_layout.html:21
+#, python-format
+msgid "BookWyrm hosted on %(site_name)s"
+msgstr "BookWyrm talpinamas %(site_name)s"
+
+#: bookwyrm/templates/email/html_layout.html:23
+msgid "Email preference"
+msgstr "El. pašto nustatymai"
+
+#: bookwyrm/templates/email/invite/html_content.html:6
+#: bookwyrm/templates/email/invite/subject.html:2
+#, python-format
+msgid "You're invited to join %(site_name)s!"
+msgstr "Esate pakviesti prisijungti prie %(site_name)s!"
+
+#: bookwyrm/templates/email/invite/html_content.html:9
+msgid "Join Now"
+msgstr "Prisijungti dabar"
+
+#: bookwyrm/templates/email/invite/html_content.html:15
+#, python-format
+msgid "Learn more about %(site_name)s."
+msgstr "Sužinoti daugiau apie %(site_name)s."
+
+#: bookwyrm/templates/email/invite/text_content.html:4
+#, python-format
+msgid "You're invited to join %(site_name)s! Click the link below to create an account."
+msgstr "Esate pakviesti prisijungti prie %(site_name)s! Spauskite nuorodą žemiau, kad sukurtumėte paskyrą."
+
+#: bookwyrm/templates/email/invite/text_content.html:8
+#, python-format
+msgid "Learn more about %(site_name)s:"
+msgstr "Sužinoti daugiau apie %(site_name)s:"
+
+#: bookwyrm/templates/email/password_reset/html_content.html:6
+#: bookwyrm/templates/email/password_reset/text_content.html:4
+#, python-format
+msgid "You requested to reset your %(site_name)s password. Click the link below to set a new password and log in to your account."
+msgstr "Prašėte pakeisti %(site_name)s slaptažodį. Spauskite žemiau, kad pakeisti slaptažodį ir prisijungti prie savo paskyros."
+
+#: bookwyrm/templates/email/password_reset/html_content.html:9
+#: bookwyrm/templates/landing/password_reset.html:4
+#: bookwyrm/templates/landing/password_reset.html:10
+#: bookwyrm/templates/landing/password_reset_request.html:4
+#: bookwyrm/templates/landing/password_reset_request.html:10
+msgid "Reset Password"
+msgstr "Atstatyti slaptažodį"
+
+#: bookwyrm/templates/email/password_reset/html_content.html:13
+#: bookwyrm/templates/email/password_reset/text_content.html:8
+msgid "If you didn't request to reset your password, you can ignore this email."
+msgstr "Jei nenorite pakeisti savo slaptažodžio - ignoruokite šį laišką."
+
+#: bookwyrm/templates/email/password_reset/subject.html:2
+#, python-format
+msgid "Reset your %(site_name)s password"
+msgstr "Keisti %(site_name)s slaptažodį"
+
+#: bookwyrm/templates/feed/direct_messages.html:8
+#, python-format
+msgid "Direct Messages with %(username)s"
+msgstr "Asmeninis susirašinėjimas su %(username)s"
+
+#: bookwyrm/templates/feed/direct_messages.html:10
+#: bookwyrm/templates/layout.html:111
+msgid "Direct Messages"
+msgstr "Asmeninės žinutės"
+
+#: bookwyrm/templates/feed/direct_messages.html:13
+msgid "All messages"
+msgstr "Visos žinutės"
+
+#: bookwyrm/templates/feed/direct_messages.html:22
+msgid "You have no messages right now."
+msgstr "Neturite žinučių."
+
+#: bookwyrm/templates/feed/feed.html:22
+#, python-format
+msgid "load 0 unread status(es)"
+msgstr "įkelti 0 neperskaitytų būsena"
+
+#: bookwyrm/templates/feed/feed.html:38
+msgid "There aren't any activities right now! Try following a user to get started"
+msgstr "Šiuo metu įrašų nėra. Norėdami matyti, sekite narį."
+
+#: bookwyrm/templates/feed/goal_card.html:6
+#: bookwyrm/templates/feed/layout.html:90
+#: bookwyrm/templates/user/goal_form.html:6
+#, python-format
+msgid "%(year)s Reading Goal"
+msgstr "%(year)s skaitymo tikslas"
+
+#: bookwyrm/templates/feed/goal_card.html:18
+#, python-format
+msgid "You can set or change your reading goal any time from your profile page"
+msgstr "Bet kuriuo metu galite pakeisti savo skaitymo tikslą savo paskyros puslapyje"
+
+#: bookwyrm/templates/feed/layout.html:5
+msgid "Updates"
+msgstr "Atnaujinimai"
+
+#: bookwyrm/templates/feed/layout.html:12 bookwyrm/templates/layout.html:106
+msgid "Your Books"
+msgstr "Jūsų knygos"
+
+#: bookwyrm/templates/feed/layout.html:14
+msgid "There are no books here right now! Try searching for a book to get started"
+msgstr "Knygų neturite. Raskite knygą ir pradėkite."
+
+#: bookwyrm/templates/feed/layout.html:25
+#: bookwyrm/templates/shelf/shelf.html:38
+#: bookwyrm/templates/user/books_header.html:4
+msgid "To Read"
+msgstr "Perskaityti"
+
+#: bookwyrm/templates/feed/layout.html:26
+#: bookwyrm/templates/shelf/shelf.html:40
+#: bookwyrm/templates/user/books_header.html:6
+msgid "Currently Reading"
+msgstr "Šiuo metu skaitoma"
+
+#: bookwyrm/templates/feed/layout.html:27
+#: bookwyrm/templates/shelf/shelf.html:42
+#: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:23
+#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:12
+#: bookwyrm/templates/user/books_header.html:8
+msgid "Read"
+msgstr "Perskaičiau"
+
+#: bookwyrm/templates/feed/suggested_users.html:5
+#: bookwyrm/templates/get_started/users.html:6
+msgid "Who to follow"
+msgstr "Ką sekti"
+
+#: bookwyrm/templates/feed/suggested_users.html:9
+msgid "Don't show suggested users"
+msgstr "Nerodyti siūlomų vartotojų"
+
+#: bookwyrm/templates/feed/suggested_users.html:14
+msgid "View directory"
+msgstr "Žiūrėti katalogą"
+
+#: bookwyrm/templates/get_started/book_preview.html:6
+#, python-format
+msgid "Have you read %(book_title)s?"
+msgstr "Ar skaitėte „%(book_title)s“?"
+
+#: bookwyrm/templates/get_started/books.html:6
+msgid "What are you reading?"
+msgstr "Ką skaitome?"
+
+#: bookwyrm/templates/get_started/books.html:9
+#: bookwyrm/templates/layout.html:45 bookwyrm/templates/lists/list.html:138
+msgid "Search for a book"
+msgstr "Ieškoti knygos"
+
+#: bookwyrm/templates/get_started/books.html:11
+#, python-format
+msgid "No books found for \"%(query)s\""
+msgstr "Pagal paiešką „%(query)s“ knygos nerasta"
+
+#: bookwyrm/templates/get_started/books.html:11
+#, python-format
+msgid "You can add books when you start using %(site_name)s."
+msgstr "Kai pradedate naudotis %(site_name)s, galite pridėti knygų."
+
+#: bookwyrm/templates/get_started/books.html:16
+#: bookwyrm/templates/get_started/books.html:17
+#: bookwyrm/templates/get_started/users.html:18
+#: bookwyrm/templates/get_started/users.html:19
+#: bookwyrm/templates/groups/group.html:19
+#: bookwyrm/templates/groups/group.html:20 bookwyrm/templates/layout.html:51
+#: bookwyrm/templates/layout.html:52 bookwyrm/templates/lists/list.html:142
+#: bookwyrm/templates/search/layout.html:4
+#: bookwyrm/templates/search/layout.html:9
+msgid "Search"
+msgstr "Paieška"
+
+#: bookwyrm/templates/get_started/books.html:27
+msgid "Suggested Books"
+msgstr "Siūlomos knygos"
+
+#: bookwyrm/templates/get_started/books.html:46
+#, python-format
+msgid "Popular on %(site_name)s"
+msgstr "%(site_name)s populiaru"
+
+#: bookwyrm/templates/get_started/books.html:58
+#: bookwyrm/templates/lists/list.html:155
+msgid "No books found"
+msgstr "Knygų nerasta"
+
+#: bookwyrm/templates/get_started/books.html:63
+#: bookwyrm/templates/get_started/profile.html:54
+msgid "Save & continue"
+msgstr "Išsaugoti ir tęsti"
+
+#: bookwyrm/templates/get_started/layout.html:5
+#: bookwyrm/templates/landing/layout.html:5
+msgid "Welcome"
+msgstr "Sveiki atvykę"
+
+#: bookwyrm/templates/get_started/layout.html:15
+#, python-format
+msgid "Welcome to %(site_name)s!"
+msgstr "Sveiki atvykę į %(site_name)s!"
+
+#: bookwyrm/templates/get_started/layout.html:17
+msgid "These are some first steps to get you started."
+msgstr "Pirmieji žingsniai, norint pradėti."
+
+#: bookwyrm/templates/get_started/layout.html:31
+#: bookwyrm/templates/get_started/profile.html:6
+msgid "Create your profile"
+msgstr "Susikurkite paskyrą"
+
+#: bookwyrm/templates/get_started/layout.html:35
+msgid "Add books"
+msgstr "Pridėti knygas"
+
+#: bookwyrm/templates/get_started/layout.html:39
+msgid "Find friends"
+msgstr "Rasti draugų"
+
+#: bookwyrm/templates/get_started/layout.html:45
+msgid "Skip this step"
+msgstr "Praleisti šį žingsnį"
+
+#: bookwyrm/templates/get_started/layout.html:49
+msgid "Finish"
+msgstr "Baigti"
+
+#: bookwyrm/templates/get_started/profile.html:15
+#: bookwyrm/templates/preferences/edit_user.html:42
+msgid "Display name:"
+msgstr "Rodyti vardą:"
+
+#: bookwyrm/templates/get_started/profile.html:22
+#: bookwyrm/templates/preferences/edit_user.html:49
+msgid "Summary:"
+msgstr "Santrauka:"
+
+#: bookwyrm/templates/get_started/profile.html:23
+msgid "A little bit about you"
+msgstr "Šiek tiek apie jus"
+
+#: bookwyrm/templates/get_started/profile.html:32
+#: bookwyrm/templates/preferences/edit_user.html:27
+msgid "Avatar:"
+msgstr "Avataras:"
+
+#: bookwyrm/templates/get_started/profile.html:42
+#: bookwyrm/templates/preferences/edit_user.html:110
+msgid "Manually approve followers:"
+msgstr "Noriu tvirtinti sekėjus:"
+
+#: bookwyrm/templates/get_started/profile.html:48
+#: bookwyrm/templates/preferences/edit_user.html:80
+msgid "Show this account in suggested users:"
+msgstr "Paskyrą įtraukti į siūlomus narius:"
+
+#: bookwyrm/templates/get_started/profile.html:52
+msgid "Your account will show up in the directory, and may be recommended to other BookWyrm users."
+msgstr "Jūsų paskyra atsiras kataloge ir gali būti rekomenduota kitiems „BookWyrm“ nariams."
+
+#: bookwyrm/templates/get_started/users.html:11
+msgid "Search for a user"
+msgstr "Ieškoti naudotojo"
+
+#: bookwyrm/templates/get_started/users.html:13
+#, python-format
+msgid "No users found for \"%(query)s\""
+msgstr "Pagal paiešką „%(query)s“ nieko nerasta"
+
+#: bookwyrm/templates/groups/create_form.html:5
+msgid "Create Group"
+msgstr "Sukurti grupę"
+
+#: bookwyrm/templates/groups/created_text.html:4
+#, python-format
+msgid "Managed by %(username)s"
+msgstr "Tvarko %(username)s"
+
+#: bookwyrm/templates/groups/delete_group_modal.html:4
+msgid "Delete this group?"
+msgstr "Ištrinti šią grupę?"
+
+#: bookwyrm/templates/groups/delete_group_modal.html:7
+#: bookwyrm/templates/lists/delete_list_modal.html:7
+msgid "This action cannot be un-done"
+msgstr "Nebegalite atšaukti šio veiksmo"
+
+#: bookwyrm/templates/groups/delete_group_modal.html:15
+#: bookwyrm/templates/lists/delete_list_modal.html:15
+#: bookwyrm/templates/settings/announcements/announcement.html:20
+#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:49
+#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:36
+#: bookwyrm/templates/snippets/delete_readthrough_modal.html:15
+#: bookwyrm/templates/snippets/follow_request_buttons.html:12
+#: bookwyrm/templates/snippets/join_invitation_buttons.html:13
+msgid "Delete"
+msgstr "Ištrinti"
+
+#: bookwyrm/templates/groups/edit_form.html:5
+msgid "Edit Group"
+msgstr "Redaguoti grupę"
+
+#: bookwyrm/templates/groups/find_users.html:6
+msgid "Add new members!"
+msgstr "Pridėkite naujų narių!"
+
+#: bookwyrm/templates/groups/form.html:8
+msgid "Group Name:"
+msgstr "Grupės pavadinimas:"
+
+#: bookwyrm/templates/groups/form.html:12
+msgid "Group Description:"
+msgstr "Grupės aprašymas:"
+
+#: bookwyrm/templates/groups/form.html:30
+msgid "Delete group"
+msgstr "Ištrinti grupę"
+
+#: bookwyrm/templates/groups/group.html:15
+msgid "Search to add a user"
+msgstr "Ieškokite, kad pridėtumėte naudotoją"
+
+#: bookwyrm/templates/groups/group.html:36
+msgid "This group has no lists"
+msgstr "Šioje grupėje nėra sąrašų"
+
+#: bookwyrm/templates/groups/layout.html:16
+msgid "Edit group"
+msgstr "Redaguoti grupę"
+
+#: bookwyrm/templates/groups/members.html:8
+msgid "Members can add and remove books on a group's book lists"
+msgstr "Nariai gali pridėti ir pašalinti knygas grupės knygų sąrašuose"
+
+#: bookwyrm/templates/groups/members.html:19
+msgid "Leave group"
+msgstr "Išeiti iš grupės"
+
+#: bookwyrm/templates/groups/members.html:41
+#: bookwyrm/templates/groups/suggested_users.html:32
+#: bookwyrm/templates/snippets/suggested_users.html:31
+#: bookwyrm/templates/user/user_preview.html:36
+msgid "Follows you"
+msgstr "Jus seka"
+
+#: bookwyrm/templates/groups/suggested_users.html:17
+#: bookwyrm/templates/snippets/suggested_users.html:16
+#, python-format
+msgid "%(mutuals)s follower you follow"
+msgid_plural "%(mutuals)s followers you follow"
+msgstr[0] "Sekate %(mutuals)s bendrą žmogų"
+msgstr[1] "Sekate %(mutuals)s bendrus žmones"
+msgstr[2] "Sekate %(mutuals)s bendrų žmonių"
+msgstr[3] "Sekate %(mutuals)s bendrų žmonių"
+
+#: bookwyrm/templates/groups/suggested_users.html:24
+#: bookwyrm/templates/snippets/suggested_users.html:23
+#, python-format
+msgid "%(shared_books)s book on your shelves"
+msgid_plural "%(shared_books)s books on your shelves"
+msgstr[0] "%(shared_books)s knyga jūsų lentynoje"
+msgstr[1] "%(shared_books)s knygos jūsų lentynose"
+msgstr[2] "%(shared_books)s knygų jūsų lentynose"
+msgstr[3] "%(shared_books)s knygų jūsų lentynose"
+
+#: bookwyrm/templates/groups/suggested_users.html:40
+#, python-format
+msgid "No potential members found for \"%(user_query)s\""
+msgstr "Užklausa „%(user_query)s“ nerasta potencialių narių"
+
+#: bookwyrm/templates/groups/user_groups.html:15
+msgid "Manager"
+msgstr "Vadovas"
+
+#: bookwyrm/templates/import/import.html:5
+#: bookwyrm/templates/import/import.html:9
+#: bookwyrm/templates/shelf/shelf.html:61
+msgid "Import Books"
+msgstr "Importuoti knygas"
+
+#: bookwyrm/templates/import/import.html:18
+msgid "Data source:"
+msgstr "Duomenų šaltinis:"
+
+#: bookwyrm/templates/import/import.html:37
+msgid "Data file:"
+msgstr "Duomenų failas:"
+
+#: bookwyrm/templates/import/import.html:45
+msgid "Include reviews"
+msgstr "Įtraukti atsiliepimus"
+
+#: bookwyrm/templates/import/import.html:50
+msgid "Privacy setting for imported reviews:"
+msgstr "Privatumo nustatymai svarbiems atsiliepimams:"
+
+#: bookwyrm/templates/import/import.html:56
+#: bookwyrm/templates/settings/federation/instance_blocklist.html:64
+msgid "Import"
+msgstr "Importuoti"
+
+#: bookwyrm/templates/import/import.html:61
+msgid "Recent Imports"
+msgstr "Pastaruoju metu importuota"
+
+#: bookwyrm/templates/import/import.html:63
+msgid "No recent imports"
+msgstr "Pastaruoju metu neimportuota"
+
+#: bookwyrm/templates/import/import_status.html:6
+#: bookwyrm/templates/import/import_status.html:15
+#: bookwyrm/templates/import/import_status.html:29
+msgid "Import Status"
+msgstr "Importavimo būsena"
+
+#: bookwyrm/templates/import/import_status.html:13
+#: bookwyrm/templates/import/import_status.html:27
+msgid "Retry Status"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:22
+msgid "Imports"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:39
+msgid "Import started:"
+msgstr "Importavimas prasidėjo:"
+
+#: bookwyrm/templates/import/import_status.html:48
+msgid "In progress"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:50
+msgid "Refresh"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:62
+#, python-format
+msgid "%(display_counter)s item needs manual approval."
+msgid_plural "%(display_counter)s items need manual approval."
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+#: bookwyrm/templates/import/import_status.html:67
+#: bookwyrm/templates/import/manual_review.html:8
+msgid "Review items"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:73
+#, python-format
+msgid "%(display_counter)s item failed to import."
+msgid_plural "%(display_counter)s items failed to import."
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+#: bookwyrm/templates/import/import_status.html:79
+msgid "View and troubleshoot failed items"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:91
+msgid "Row"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:94
+#: bookwyrm/templates/shelf/shelf.html:141
+#: bookwyrm/templates/shelf/shelf.html:163
+msgid "Title"
+msgstr "Pavadinimas"
+
+#: bookwyrm/templates/import/import_status.html:97
+msgid "ISBN"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:100
+#: bookwyrm/templates/shelf/shelf.html:142
+#: bookwyrm/templates/shelf/shelf.html:166
+msgid "Author"
+msgstr "Autorius"
+
+#: bookwyrm/templates/import/import_status.html:103
+msgid "Shelf"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:106
+#: bookwyrm/templates/import/manual_review.html:13
+#: bookwyrm/templates/snippets/create_status.html:17
+msgid "Review"
+msgstr "Peržiūra"
+
+#: bookwyrm/templates/import/import_status.html:110
+msgid "Book"
+msgstr "Knyga"
+
+#: bookwyrm/templates/import/import_status.html:113
+#: bookwyrm/templates/settings/announcements/announcements.html:38
+#: bookwyrm/templates/settings/federation/instance_list.html:46
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:44
+#: bookwyrm/templates/settings/invites/status_filter.html:5
+#: bookwyrm/templates/settings/users/user_admin.html:34
+#: bookwyrm/templates/settings/users/user_info.html:20
+msgid "Status"
+msgstr "Būsena"
+
+#: bookwyrm/templates/import/import_status.html:144
+msgid "View imported review"
+msgstr ""
+
+#: bookwyrm/templates/import/import_status.html:158
+msgid "Imported"
+msgstr "Importuota"
+
+#: bookwyrm/templates/import/import_status.html:164
+msgid "Needs manual review"
+msgstr ""
+
+#: bookwyrm/templates/import/manual_review.html:5
+#: bookwyrm/templates/import/troubleshoot.html:4
+msgid "Import Troubleshooting"
+msgstr ""
+
+#: bookwyrm/templates/import/manual_review.html:21
+msgid "Approving a suggestion will permanently add the suggested book to your shelves and associate your reading dates, reviews, and ratings with that book."
+msgstr ""
+
+#: bookwyrm/templates/import/manual_review.html:56
+#: bookwyrm/templates/lists/curate.html:57
+msgid "Approve"
+msgstr "Patvirtinti"
+
+#: bookwyrm/templates/import/manual_review.html:64
+msgid "Reject"
+msgstr ""
+
+#: bookwyrm/templates/import/tooltip.html:6
+msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account."
+msgstr "Galite atsisiųsti savo „Goodreads“ duomenis iš Importavimo ir eksportavimo puslapio, esančio jūsų „Goodreads“ paskyroje."
+
+#: bookwyrm/templates/import/troubleshoot.html:7
+msgid "Failed items"
+msgstr ""
+
+#: bookwyrm/templates/import/troubleshoot.html:12
+msgid "Troubleshooting"
+msgstr ""
+
+#: bookwyrm/templates/import/troubleshoot.html:20
+msgid "Re-trying an import can fix missing items in cases such as:"
+msgstr ""
+
+#: bookwyrm/templates/import/troubleshoot.html:23
+msgid "The book has been added to the instance since this import"
+msgstr ""
+
+#: bookwyrm/templates/import/troubleshoot.html:24
+msgid "A transient error or timeout caused the external data source to be unavailable."
+msgstr ""
+
+#: bookwyrm/templates/import/troubleshoot.html:25
+msgid "BookWyrm has been updated since this import with a bug fix"
+msgstr ""
+
+#: bookwyrm/templates/import/troubleshoot.html:28
+msgid "Contact your admin or open an issue if you are seeing unexpected failed items."
+msgstr ""
+
+#: bookwyrm/templates/landing/about.html:7 bookwyrm/templates/layout.html:230
+#, python-format
+msgid "About %(site_name)s"
+msgstr "Apie %(site_name)s"
+
+#: bookwyrm/templates/landing/about.html:10
+#: bookwyrm/templates/landing/about.html:20
+msgid "Code of Conduct"
+msgstr "Elgesio kodeksas"
+
+#: bookwyrm/templates/landing/about.html:13
+#: bookwyrm/templates/landing/about.html:29
+msgid "Privacy Policy"
+msgstr "Privatumo politika"
+
+#: bookwyrm/templates/landing/invite.html:4
+#: bookwyrm/templates/landing/invite.html:8
+#: bookwyrm/templates/landing/login.html:49
+msgid "Create an Account"
+msgstr "Kurti paskyrą"
+
+#: bookwyrm/templates/landing/invite.html:21
+msgid "Permission Denied"
+msgstr "Prieiga draudžiama"
+
+#: bookwyrm/templates/landing/invite.html:22
+msgid "Sorry! This invite code is no longer valid."
+msgstr "Deja, šis pakvietimo kodas nebegalioja."
+
+#: bookwyrm/templates/landing/landing.html:6
+msgid "Recent Books"
+msgstr "Naujos knygos"
+
+#: bookwyrm/templates/landing/layout.html:17
+msgid "Decentralized"
+msgstr "Decentralizuota"
+
+#: bookwyrm/templates/landing/layout.html:23
+msgid "Friendly"
+msgstr "Draugiškas"
+
+#: bookwyrm/templates/landing/layout.html:29
+msgid "Anti-Corporate"
+msgstr "Nekorporacinis"
+
+#: bookwyrm/templates/landing/layout.html:45
+#, python-format
+msgid "Join %(name)s"
+msgstr "Prisijunkite prie %(name)s"
+
+#: bookwyrm/templates/landing/layout.html:47
+msgid "Request an Invitation"
+msgstr "Prašyti kvietimo"
+
+#: bookwyrm/templates/landing/layout.html:49
+#, python-format
+msgid "%(name)s registration is closed"
+msgstr "%(name)s – registracija uždaryta"
+
+#: bookwyrm/templates/landing/layout.html:60
+msgid "Thank you! Your request has been received."
+msgstr "Dėkojame, jūsų prašymas gautas."
+
+#: bookwyrm/templates/landing/layout.html:82
+msgid "Your Account"
+msgstr "Jūsų paskyra"
+
+#: bookwyrm/templates/landing/login.html:4
+msgid "Login"
+msgstr "Prisijungti"
+
+#: bookwyrm/templates/landing/login.html:7
+#: bookwyrm/templates/landing/login.html:37 bookwyrm/templates/layout.html:179
+msgid "Log in"
+msgstr "Prisijunkite"
+
+#: bookwyrm/templates/landing/login.html:15
+msgid "Success! Email address confirmed."
+msgstr "Džiugu, el. pašto adresas patvirtintas."
+
+#: bookwyrm/templates/landing/login.html:21 bookwyrm/templates/layout.html:170
+#: bookwyrm/templates/snippets/register_form.html:4
+msgid "Username:"
+msgstr "Naudotojo vardas:"
+
+#: bookwyrm/templates/landing/login.html:27
+#: bookwyrm/templates/landing/password_reset.html:17
+#: bookwyrm/templates/layout.html:174
+#: bookwyrm/templates/snippets/register_form.html:22
+msgid "Password:"
+msgstr "Slaptažodis:"
+
+#: bookwyrm/templates/landing/login.html:40 bookwyrm/templates/layout.html:176
+msgid "Forgot your password?"
+msgstr "Pamiršote slaptažodį?"
+
+#: bookwyrm/templates/landing/login.html:62
+msgid "More about this site"
+msgstr "Daugiau apie šią svetainę"
+
+#: bookwyrm/templates/landing/password_reset.html:23
+#: bookwyrm/templates/preferences/change_password.html:18
+#: bookwyrm/templates/preferences/delete_user.html:20
+msgid "Confirm password:"
+msgstr "Patvirtinti slaptažodį:"
+
+#: bookwyrm/templates/landing/password_reset_request.html:14
+msgid "A link to reset your password will be sent to your email address"
+msgstr "Jūsų el. pašto adresu bus išsiųsta nuoroda pakeisti slaptažodį"
+
+#: bookwyrm/templates/landing/password_reset_request.html:28
+msgid "Reset password"
+msgstr "Atstatyti slaptažodį"
+
+#: bookwyrm/templates/layout.html:13
+#, python-format
+msgid "%(site_name)s search"
+msgstr "%(site_name)s paieška"
+
+#: bookwyrm/templates/layout.html:43
+msgid "Search for a book, user, or list"
+msgstr "Ieškoti knygos, naudotojo arba sąrašo"
+
+#: bookwyrm/templates/layout.html:61 bookwyrm/templates/layout.html:62
+msgid "Main navigation menu"
+msgstr "Pagrindinis navigacijos meniu"
+
+#: bookwyrm/templates/layout.html:72
+msgid "Feed"
+msgstr "Srautas"
+
+#: bookwyrm/templates/layout.html:116
+msgid "Settings"
+msgstr "Nustatymai"
+
+#: bookwyrm/templates/layout.html:125
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:15
+#: bookwyrm/templates/settings/invites/manage_invites.html:3
+#: bookwyrm/templates/settings/invites/manage_invites.html:15
+#: bookwyrm/templates/settings/layout.html:40
+msgid "Invites"
+msgstr "Pakvietimai"
+
+#: bookwyrm/templates/layout.html:132
+msgid "Admin"
+msgstr "Administratorius"
+
+#: bookwyrm/templates/layout.html:139
+msgid "Log out"
+msgstr "Atsijungti"
+
+#: bookwyrm/templates/layout.html:147 bookwyrm/templates/layout.html:148
+#: bookwyrm/templates/notifications/notifications_page.html:5
+#: bookwyrm/templates/notifications/notifications_page.html:10
+msgid "Notifications"
+msgstr "Pranešimai"
+
+#: bookwyrm/templates/layout.html:175
+msgid "password"
+msgstr "slaptažodis"
+
+#: bookwyrm/templates/layout.html:187
+msgid "Join"
+msgstr "Prisijungti"
+
+#: bookwyrm/templates/layout.html:221
+msgid "Successfully posted status"
+msgstr "Būsena publikuota sėkmingai"
+
+#: bookwyrm/templates/layout.html:222
+msgid "Error posting status"
+msgstr "Klaida, publikuojant būseną"
+
+#: bookwyrm/templates/layout.html:234
+msgid "Contact site admin"
+msgstr "Puslapio administratorius"
+
+#: bookwyrm/templates/layout.html:238
+msgid "Documentation"
+msgstr "Dokumentacija"
+
+#: bookwyrm/templates/layout.html:245
+#, python-format
+msgid "Support %(site_name)s on %(support_title)s"
+msgstr "Paremkite %(site_name)s per %(support_title)s"
+
+#: bookwyrm/templates/layout.html:249
+msgid "BookWyrm's source code is freely available. You can contribute or report issues on GitHub."
+msgstr "„BookWyrm“ šaltinio kodas yra laisvai prieinamas. Galite prisidėti arba pranešti apie klaidas per GitHub."
+
+#: bookwyrm/templates/lists/bookmark_button.html:30
+msgid "Un-save"
+msgstr "Nebesaugoti"
+
+#: bookwyrm/templates/lists/create_form.html:5
+#: bookwyrm/templates/lists/lists.html:20
+msgid "Create List"
+msgstr "Sukurti sąrašą"
+
+#: bookwyrm/templates/lists/created_text.html:5
+#, python-format
+msgid "Created by %(username)s and managed by %(groupname)s"
+msgstr "Sukūrė %(username)s, tvarko %(groupname)s"
+
+#: bookwyrm/templates/lists/created_text.html:7
+#, python-format
+msgid "Created and curated by %(username)s"
+msgstr "Sukūrė ir kuruoja %(username)s"
+
+#: bookwyrm/templates/lists/created_text.html:9
+#, python-format
+msgid "Created by %(username)s"
+msgstr "Sukūrė %(username)s"
+
+#: bookwyrm/templates/lists/curate.html:8
+msgid "Pending Books"
+msgstr "Patvirtinimo laukiančios knygos"
+
+#: bookwyrm/templates/lists/curate.html:11
+msgid "Go to list"
+msgstr "Eiti į sąrašą"
+
+#: bookwyrm/templates/lists/curate.html:15
+msgid "You're all set!"
+msgstr "Viskas atlikta!"
+
+#: bookwyrm/templates/lists/curate.html:45
+msgid "Suggested by"
+msgstr "Pasiūlė"
+
+#: bookwyrm/templates/lists/curate.html:63
+msgid "Discard"
+msgstr "Atmesti"
+
+#: bookwyrm/templates/lists/delete_list_modal.html:4
+msgid "Delete this list?"
+msgstr "Ištrinti šį sąrašą?"
+
+#: bookwyrm/templates/lists/edit_form.html:5
+#: bookwyrm/templates/lists/layout.html:16
+msgid "Edit List"
+msgstr "Redaguoti sąrašą"
+
+#: bookwyrm/templates/lists/form.html:19
+msgid "List curation:"
+msgstr "Sąrašo kuravimas:"
+
+#: bookwyrm/templates/lists/form.html:22
+msgid "Closed"
+msgstr "Uždaryta"
+
+#: bookwyrm/templates/lists/form.html:23
+msgid "Only you can add and remove books to this list"
+msgstr "Tik jūs galite pridėti ar pašalinti knygas iš šio sąrašo"
+
+#: bookwyrm/templates/lists/form.html:27
+msgid "Curated"
+msgstr "Kuruojama"
+
+#: bookwyrm/templates/lists/form.html:28
+msgid "Anyone can suggest books, subject to your approval"
+msgstr "Knygas gali siūlyti visi, tačiau jūs turėsite patvirtinti"
+
+#: bookwyrm/templates/lists/form.html:32
+msgctxt "curation type"
+msgid "Open"
+msgstr "Atidaryti"
+
+#: bookwyrm/templates/lists/form.html:33
+msgid "Anyone can add books to this list"
+msgstr "Visi gali pridėti knygų į sąrašą"
+
+#: bookwyrm/templates/lists/form.html:37
+msgid "Group"
+msgstr "Grupė"
+
+#: bookwyrm/templates/lists/form.html:38
+msgid "Group members can add to and remove from this list"
+msgstr "Grupės nariai gali pridėti ir išimti iš sąrašo"
+
+#: bookwyrm/templates/lists/form.html:41
+msgid "Select Group"
+msgstr "Pasirinkti grupę"
+
+#: bookwyrm/templates/lists/form.html:45
+msgid "Select a group"
+msgstr "Pasirinkite grupę"
+
+#: bookwyrm/templates/lists/form.html:56
+msgid "You don't have any Groups yet!"
+msgstr "Dar neturite grupių!"
+
+#: bookwyrm/templates/lists/form.html:58
+msgid "Create a Group"
+msgstr "Sukurti grupę"
+
+#: bookwyrm/templates/lists/form.html:81
+msgid "Delete list"
+msgstr "Ištrinti sąrašą"
+
+#: bookwyrm/templates/lists/list.html:21
+msgid "You successfully suggested a book for this list!"
+msgstr "Sėkmingai pasiūlėte knygą šiam sąrašui!"
+
+#: bookwyrm/templates/lists/list.html:23
+msgid "You successfully added a book to this list!"
+msgstr "Sėkmingai pridėjote knygą į šį sąrašą!"
+
+#: bookwyrm/templates/lists/list.html:29
+msgid "This list is currently empty"
+msgstr "Šiuo metu sąrašas tuščias"
+
+#: bookwyrm/templates/lists/list.html:67
+#, python-format
+msgid "Added by %(username)s"
+msgstr "Pridėjo %(username)s"
+
+#: bookwyrm/templates/lists/list.html:76
+msgid "List position"
+msgstr "Sąrašo pozicija"
+
+#: bookwyrm/templates/lists/list.html:82
+msgid "Set"
+msgstr "Nustatyti"
+
+#: bookwyrm/templates/lists/list.html:92
+#: bookwyrm/templates/snippets/remove_from_group_button.html:19
+#: bookwyrm/templates/snippets/shelf_selector.html:26
+msgid "Remove"
+msgstr "Pašalinti"
+
+#: bookwyrm/templates/lists/list.html:106
+#: bookwyrm/templates/lists/list.html:123
+msgid "Sort List"
+msgstr "Rūšiuoti sąrašą"
+
+#: bookwyrm/templates/lists/list.html:116
+msgid "Direction"
+msgstr "Kryptis"
+
+#: bookwyrm/templates/lists/list.html:130
+msgid "Add Books"
+msgstr "Pridėti knygų"
+
+#: bookwyrm/templates/lists/list.html:132
+msgid "Suggest Books"
+msgstr "Siūlyti knygų"
+
+#: bookwyrm/templates/lists/list.html:143
+msgid "search"
+msgstr "paieška"
+
+#: bookwyrm/templates/lists/list.html:149
+msgid "Clear search"
+msgstr "Išvalyti paiešką"
+
+#: bookwyrm/templates/lists/list.html:154
+#, python-format
+msgid "No books found matching the query \"%(query)s\""
+msgstr "Pagal paiešką „%(query)s“ knygų nerasta"
+
+#: bookwyrm/templates/lists/list.html:182
+msgid "Suggest"
+msgstr "Siūlyti"
+
+#: bookwyrm/templates/lists/list_items.html:15
+msgid "Saved"
+msgstr "Išsaugota"
+
+#: bookwyrm/templates/lists/lists.html:14 bookwyrm/templates/user/lists.html:9
+msgid "Your Lists"
+msgstr "Jūsų sąrašai"
+
+#: bookwyrm/templates/lists/lists.html:36
+msgid "All Lists"
+msgstr "Visi sąrašai"
+
+#: bookwyrm/templates/lists/lists.html:40
+msgid "Saved Lists"
+msgstr "Išsaugoti sąrašai"
+
+#: bookwyrm/templates/notifications/items/accept.html:16
+#, python-format
+msgid "accepted your invitation to join group \"%(group_name)s\""
+msgstr "priėmė jūsų kvietimą prisijungti prie grupės „%(group_name)s“"
+
+#: bookwyrm/templates/notifications/items/add.html:24
+#, python-format
+msgid "added %(book_title)s to your list \"%(list_name)s\""
+msgstr "į jūsų sąrašą „%(list_name)s“ pridėta %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/add.html:31
+#, python-format
+msgid "suggested adding %(book_title)s to your list \"%(list_name)s\""
+msgstr "į sąrašą „%(list_name)s\" patariama pridėti %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/boost.html:19
+#, python-format
+msgid "boosted your review of %(book_title)s"
+msgstr "populiarėja jūsų atsiliepimas apie %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/boost.html:25
+#, python-format
+msgid "boosted your comment on%(book_title)s"
+msgstr "populiarėja jūsų komentaras apie %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/boost.html:31
+#, python-format
+msgid "boosted your quote from %(book_title)s"
+msgstr "populiarėja jūsų citata iš %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/boost.html:37
+#, python-format
+msgid "boosted your status"
+msgstr "populiarėja jūsų būsena"
+
+#: bookwyrm/templates/notifications/items/fav.html:19
+#, python-format
+msgid "liked your review of %(book_title)s"
+msgstr "patiko jūsų atsiliepimas apie %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/fav.html:25
+#, python-format
+msgid "liked your comment on %(book_title)s"
+msgstr "patiko jūsų komentaras apie %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/fav.html:31
+#, python-format
+msgid "liked your quote from %(book_title)s"
+msgstr "patiko jūsų citata iš %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/fav.html:37
+#, python-format
+msgid "liked your status"
+msgstr "patiko jūsų būsena"
+
+#: bookwyrm/templates/notifications/items/follow.html:15
+msgid "followed you"
+msgstr "pradėjo jus sekti"
+
+#: bookwyrm/templates/notifications/items/follow_request.html:11
+msgid "sent you a follow request"
+msgstr "nori jus sekti"
+
+#: bookwyrm/templates/notifications/items/import.html:14
+#, python-format
+msgid "Your import completed."
+msgstr "Jūsų importas baigtas."
+
+#: bookwyrm/templates/notifications/items/invite.html:15
+#, python-format
+msgid "invited you to join the group \"%(group_name)s\""
+msgstr "jus pakvietė prisijungti prie grupės „%(group_name)s“"
+
+#: bookwyrm/templates/notifications/items/join.html:16
+#, python-format
+msgid "has joined your group \"%(group_name)s\""
+msgstr "prisijungė prie jūsų grupės „%(group_name)s“"
+
+#: bookwyrm/templates/notifications/items/leave.html:16
+#, python-format
+msgid "has left your group \"%(group_name)s\""
+msgstr "paliko jūsų grupę „%(group_name)s“"
+
+#: bookwyrm/templates/notifications/items/mention.html:20
+#, python-format
+msgid "mentioned you in a review of %(book_title)s"
+msgstr "paminėjo jus atsiliepime apie %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/mention.html:26
+#, python-format
+msgid "mentioned you in a comment on %(book_title)s"
+msgstr "paminėjo jus komentare apie %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/mention.html:32
+#, python-format
+msgid "mentioned you in a quote from %(book_title)s"
+msgstr "paminėjo jus citatoje iš %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/mention.html:38
+#, python-format
+msgid "mentioned you in a status"
+msgstr "paminėjo jus būsenoje"
+
+#: bookwyrm/templates/notifications/items/remove.html:17
+#, python-format
+msgid "has been removed from your group \"%(group_name)s\""
+msgstr "buvo pašalintas iš jūsų grupės „%(group_name)s“"
+
+#: bookwyrm/templates/notifications/items/remove.html:23
+#, python-format
+msgid "You have been removed from the \"%(group_name)s\" group"
+msgstr "Buvote pašalintas iš grupės „%(group_name)s“"
+
+#: bookwyrm/templates/notifications/items/reply.html:21
+#, python-format
+msgid "replied to your review of %(book_title)s"
+msgstr "atsakė į jūsų atsiliepimą apie %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/reply.html:27
+#, python-format
+msgid "replied to your comment on %(book_title)s"
+msgstr "atsakė į jūsų komentarą apie %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/reply.html:33
+#, python-format
+msgid "replied to your quote from %(book_title)s"
+msgstr "atsakė į jūsų citatą iš %(book_title)s"
+
+#: bookwyrm/templates/notifications/items/reply.html:39
+#, python-format
+msgid "replied to your status"
+msgstr "atsakė į jūsų būseną"
+
+#: bookwyrm/templates/notifications/items/report.html:15
+#, python-format
+msgid "A new report needs moderation."
+msgstr "Reikia moderuoti pranešimą."
+
+#: bookwyrm/templates/notifications/items/update.html:16
+#, python-format
+msgid "has changed the privacy level for %(group_name)s"
+msgstr "pakeitė privatumo lygį grupei %(group_name)s"
+
+#: bookwyrm/templates/notifications/items/update.html:20
+#, python-format
+msgid "has changed the name of %(group_name)s"
+msgstr "pakeitė %(group_name)s pavadinimą"
+
+#: bookwyrm/templates/notifications/items/update.html:24
+#, python-format
+msgid "has changed the description of %(group_name)s"
+msgstr "pakeitė %(group_name)s aprašymą"
+
+#: bookwyrm/templates/notifications/notifications_page.html:18
+msgid "Delete notifications"
+msgstr "Ištrinti pranešimus"
+
+#: bookwyrm/templates/notifications/notifications_page.html:29
+msgid "All"
+msgstr "Visi"
+
+#: bookwyrm/templates/notifications/notifications_page.html:33
+msgid "Mentions"
+msgstr "Paminėjimai"
+
+#: bookwyrm/templates/notifications/notifications_page.html:45
+msgid "You're all caught up!"
+msgstr "Viską peržiūrėjote!"
+
+#: bookwyrm/templates/preferences/blocks.html:4
+#: bookwyrm/templates/preferences/blocks.html:7
+#: bookwyrm/templates/preferences/layout.html:31
+msgid "Blocked Users"
+msgstr "Blokuoti nariai"
+
+#: bookwyrm/templates/preferences/blocks.html:12
+msgid "No users currently blocked."
+msgstr "Blokuotų narių nėra."
+
+#: bookwyrm/templates/preferences/change_password.html:4
+#: bookwyrm/templates/preferences/change_password.html:7
+#: bookwyrm/templates/preferences/change_password.html:21
+#: bookwyrm/templates/preferences/layout.html:20
+msgid "Change Password"
+msgstr "Keisti slaptažodį"
+
+#: bookwyrm/templates/preferences/change_password.html:14
+msgid "New password:"
+msgstr "Naujas slaptažodis:"
+
+#: bookwyrm/templates/preferences/delete_user.html:4
+#: bookwyrm/templates/preferences/delete_user.html:7
+#: bookwyrm/templates/preferences/delete_user.html:26
+#: bookwyrm/templates/preferences/layout.html:24
+#: bookwyrm/templates/settings/users/delete_user_form.html:23
+msgid "Delete Account"
+msgstr "Pašalinti paskyrą"
+
+#: bookwyrm/templates/preferences/delete_user.html:12
+msgid "Permanently delete account"
+msgstr "Visam laikui ištrinti paskyrą"
+
+#: bookwyrm/templates/preferences/delete_user.html:14
+msgid "Deleting your account cannot be undone. The username will not be available to register in the future."
+msgstr "Nebegalėsite atstatyti ištrintos paskyros. Ateityje nebegalėsite naudoti šio naudotojo vardo."
+
+#: bookwyrm/templates/preferences/edit_user.html:4
+#: bookwyrm/templates/preferences/edit_user.html:7
+#: bookwyrm/templates/preferences/layout.html:15
+msgid "Edit Profile"
+msgstr "Redaguoti profilį"
+
+#: bookwyrm/templates/preferences/edit_user.html:12
+#: bookwyrm/templates/preferences/edit_user.html:25
+#: bookwyrm/templates/settings/users/user_info.html:7
+msgid "Profile"
+msgstr "Profilis"
+
+#: bookwyrm/templates/preferences/edit_user.html:13
+#: bookwyrm/templates/preferences/edit_user.html:68
+msgid "Display preferences"
+msgstr "Vaizdo nustatymai"
+
+#: bookwyrm/templates/preferences/edit_user.html:14
+#: bookwyrm/templates/preferences/edit_user.html:106
+msgid "Privacy"
+msgstr "Privatumas"
+
+#: bookwyrm/templates/preferences/edit_user.html:72
+msgid "Show reading goal prompt in feed:"
+msgstr "Rodyti skaitymo tikslą sienoje:"
+
+#: bookwyrm/templates/preferences/edit_user.html:76
+msgid "Show suggested users:"
+msgstr "Rodyti siūlomus narius:"
+
+#: bookwyrm/templates/preferences/edit_user.html:85
+#, python-format
+msgid "Your account will show up in the directory, and may be recommended to other BookWyrm users."
+msgstr "Jūsų paskyra atsiras kataloge ir gali būti rekomenduota kitiems „BookWyrm“ nariams."
+
+#: bookwyrm/templates/preferences/edit_user.html:89
+msgid "Preferred Timezone: "
+msgstr "Laiko juosta: "
+
+#: bookwyrm/templates/preferences/edit_user.html:116
+msgid "Default post privacy:"
+msgstr "Numatytasis įrašo privatumas:"
+
+#: bookwyrm/templates/preferences/layout.html:11
+msgid "Account"
+msgstr "Paskyra"
+
+#: bookwyrm/templates/preferences/layout.html:27
+msgid "Relationships"
+msgstr "Sąsajos"
+
+#: bookwyrm/templates/reading_progress/finish.html:5
+#, python-format
+msgid "Finish \"%(book_title)s\""
+msgstr "Užbaigti „%(book_title)s“"
+
+#: bookwyrm/templates/reading_progress/start.html:5
+#, python-format
+msgid "Start \"%(book_title)s\""
+msgstr "Pradėti „%(book_title)s“"
+
+#: bookwyrm/templates/reading_progress/want.html:5
+#, python-format
+msgid "Want to Read \"%(book_title)s\""
+msgstr "Noriu perskaityti „%(book_title)s“"
+
+#: bookwyrm/templates/search/book.html:47
+#: bookwyrm/templates/settings/reports/reports.html:25
+#: bookwyrm/templates/snippets/announcement.html:16
+msgid "Open"
+msgstr "Atidaryti"
+
+#: bookwyrm/templates/search/book.html:85
+msgid "Import book"
+msgstr "Importuoti knygą"
+
+#: bookwyrm/templates/search/book.html:107
+msgid "Load results from other catalogues"
+msgstr "Įkelti rezultatus iš kitų katalogų"
+
+#: bookwyrm/templates/search/book.html:111
+msgid "Manually add book"
+msgstr "Pridėti knygą"
+
+#: bookwyrm/templates/search/book.html:116
+msgid "Log in to import or add books."
+msgstr "Prisijunkite, kad importuotumėte arba pridėtumėte knygas."
+
+#: bookwyrm/templates/search/layout.html:16
+msgid "Search query"
+msgstr "Paieškos užklausa"
+
+#: bookwyrm/templates/search/layout.html:19
+msgid "Search type"
+msgstr "Paieškos tipas"
+
+#: bookwyrm/templates/search/layout.html:23
+#: bookwyrm/templates/search/layout.html:46
+#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:27
+#: bookwyrm/templates/settings/federation/instance_list.html:44
+#: bookwyrm/templates/settings/layout.html:34
+#: bookwyrm/templates/settings/users/user_admin.html:3
+#: bookwyrm/templates/settings/users/user_admin.html:10
+msgid "Users"
+msgstr "Nariai"
+
+#: bookwyrm/templates/search/layout.html:58
+#, python-format
+msgid "No results found for \"%(query)s\""
+msgstr "Pagal paiešką „%(query)s“ nieko nerasta"
+
+#: bookwyrm/templates/settings/announcements/announcement.html:3
+#: bookwyrm/templates/settings/announcements/announcement.html:6
+msgid "Announcement"
+msgstr "Pranešimas"
+
+#: bookwyrm/templates/settings/announcements/announcement.html:7
+#: bookwyrm/templates/settings/federation/instance.html:13
+msgid "Back to list"
+msgstr "Atgal į sąrašą"
+
+#: bookwyrm/templates/settings/announcements/announcement.html:11
+#: bookwyrm/templates/settings/announcements/announcement_form.html:6
+msgid "Edit Announcement"
+msgstr "Redaguoti pranešimą"
+
+#: bookwyrm/templates/settings/announcements/announcement.html:35
+msgid "Visible:"
+msgstr "Matoma:"
+
+#: bookwyrm/templates/settings/announcements/announcement.html:38
+msgid "True"
+msgstr "Tiesa"
+
+#: bookwyrm/templates/settings/announcements/announcement.html:40
+msgid "False"
+msgstr "Netiesa"
+
+#: bookwyrm/templates/settings/announcements/announcement.html:47
+#: bookwyrm/templates/settings/announcements/announcement_form.html:40
+#: bookwyrm/templates/settings/dashboard/dashboard.html:71
+msgid "Start date:"
+msgstr "Pradžios data:"
+
+#: bookwyrm/templates/settings/announcements/announcement.html:54
+#: bookwyrm/templates/settings/announcements/announcement_form.html:49
+#: bookwyrm/templates/settings/dashboard/dashboard.html:77
+msgid "End date:"
+msgstr "Pabaigos data:"
+
+#: bookwyrm/templates/settings/announcements/announcement.html:60
+#: bookwyrm/templates/settings/announcements/announcement_form.html:58
+msgid "Active:"
+msgstr "Aktyvu:"
+
+#: bookwyrm/templates/settings/announcements/announcement_form.html:8
+#: bookwyrm/templates/settings/announcements/announcements.html:8
+msgid "Create Announcement"
+msgstr "Sukurti pranešimą"
+
+#: bookwyrm/templates/settings/announcements/announcement_form.html:16
+msgid "Preview:"
+msgstr "Peržiūra:"
+
+#: bookwyrm/templates/settings/announcements/announcement_form.html:23
+msgid "Content:"
+msgstr "Turinys:"
+
+#: bookwyrm/templates/settings/announcements/announcement_form.html:30
+msgid "Event date:"
+msgstr "Įvykio data:"
+
+#: bookwyrm/templates/settings/announcements/announcements.html:3
+#: bookwyrm/templates/settings/announcements/announcements.html:5
+#: bookwyrm/templates/settings/layout.html:72
+msgid "Announcements"
+msgstr "Pranešimai"
+
+#: bookwyrm/templates/settings/announcements/announcements.html:22
+#: bookwyrm/templates/settings/federation/instance_list.html:36
+msgid "Date added"
+msgstr "Pridėjimo data"
+
+#: bookwyrm/templates/settings/announcements/announcements.html:26
+msgid "Preview"
+msgstr "Peržiūrėti"
+
+#: bookwyrm/templates/settings/announcements/announcements.html:30
+msgid "Start date"
+msgstr "Pradžios data"
+
+#: bookwyrm/templates/settings/announcements/announcements.html:34
+msgid "End date"
+msgstr "Pabaigos data"
+
+#: bookwyrm/templates/settings/announcements/announcements.html:48
+msgid "active"
+msgstr "aktyvus"
+
+#: bookwyrm/templates/settings/announcements/announcements.html:48
+msgid "inactive"
+msgstr "neaktyvus"
+
+#: bookwyrm/templates/settings/announcements/announcements.html:52
+msgid "No announcements found"
+msgstr "Pranešimų nerasta"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:6
+#: bookwyrm/templates/settings/dashboard/dashboard.html:8
+#: bookwyrm/templates/settings/layout.html:26
+msgid "Dashboard"
+msgstr "Suvestinė"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:15
+#: bookwyrm/templates/settings/dashboard/dashboard.html:100
+msgid "Total users"
+msgstr "Iš viso naudotojų"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:21
+#: bookwyrm/templates/settings/dashboard/user_chart.html:16
+msgid "Active this month"
+msgstr "Aktyvūs šį mėnesį"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:27
+msgid "Statuses"
+msgstr "Būsenos"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:33
+#: bookwyrm/templates/settings/dashboard/works_chart.html:11
+msgid "Works"
+msgstr "Darbai"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:43
+#, python-format
+msgid "%(display_count)s open report"
+msgid_plural "%(display_count)s open reports"
+msgstr[0] "%(display_count)s atvira ataskaita"
+msgstr[1] "%(display_count)s atviros ataskaitos"
+msgstr[2] "%(display_count)s atviros ataskaitos"
+msgstr[3] "%(display_count)s atvirų ataskaitų"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:54
+#, python-format
+msgid "%(display_count)s invite request"
+msgid_plural "%(display_count)s invite requests"
+msgstr[0] "%(display_count)s prašymas pakviesti"
+msgstr[1] "%(display_count)s prašymai pakviesti"
+msgstr[2] "%(display_count)s prašymų pakviesti"
+msgstr[3] "%(display_count)s prašymai pakviesti"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:65
+msgid "Instance Activity"
+msgstr "Pavyzdinė veikla"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:83
+msgid "Interval:"
+msgstr "Intervalas:"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:87
+msgid "Days"
+msgstr "Dienos"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:88
+msgid "Weeks"
+msgstr "Savaitės"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:106
+msgid "User signup activity"
+msgstr "Naudotojo prisijungimo veikla"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:112
+msgid "Status activity"
+msgstr "Būsenos veikla"
+
+#: bookwyrm/templates/settings/dashboard/dashboard.html:118
+msgid "Works created"
+msgstr "Darbai sukurti"
+
+#: bookwyrm/templates/settings/dashboard/registration_chart.html:10
+msgid "Registrations"
+msgstr "Registracijos"
+
+#: bookwyrm/templates/settings/dashboard/status_chart.html:11
+msgid "Statuses posted"
+msgstr "Būsenos publikuotos"
+
+#: bookwyrm/templates/settings/dashboard/user_chart.html:11
+msgid "Total"
+msgstr "Iš viso"
+
+#: bookwyrm/templates/settings/email_blocklist/domain_form.html:5
+#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:10
+msgid "Add domain"
+msgstr "Pridėti domeną"
+
+#: bookwyrm/templates/settings/email_blocklist/domain_form.html:11
+msgid "Domain:"
+msgstr "Domenas:"
+
+#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:5
+#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:7
+#: bookwyrm/templates/settings/layout.html:59
+msgid "Email Blocklist"
+msgstr "El. pašto blokavimo sąrašas"
+
+#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:18
+msgid "When someone tries to register with an email from this domain, no account will be created. The registration process will appear to have worked."
+msgstr "Jei kažkas bandys registruotis prie šio domeno šiuo el. pašto adresu, paskyra nebus sukurta. Registracijos pricesas bus suveikęs."
+
+#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:25
+msgid "Domain"
+msgstr "Domenas"
+
+#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:29
+#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:27
+msgid "Options"
+msgstr "Parinktys"
+
+#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:38
+#, python-format
+msgid "%(display_count)s user"
+msgid_plural "%(display_count)s users"
+msgstr[0] "%(display_count)s narys"
+msgstr[1] "%(display_count)s nariai"
+msgstr[2] "%(display_count)s narių"
+msgstr[3] "%(display_count)s nariai"
+
+#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:59
+msgid "No email domains currently blocked"
+msgstr "Šiuo metu neblokuojamas nė vienas el. pašto domenas"
+
+#: bookwyrm/templates/settings/federation/edit_instance.html:3
+#: bookwyrm/templates/settings/federation/edit_instance.html:6
+#: bookwyrm/templates/settings/federation/edit_instance.html:20
+#: bookwyrm/templates/settings/federation/instance_blocklist.html:3
+#: bookwyrm/templates/settings/federation/instance_blocklist.html:20
+#: bookwyrm/templates/settings/federation/instance_list.html:9
+#: bookwyrm/templates/settings/federation/instance_list.html:10
+msgid "Add instance"
+msgstr "Pridėti serverį"
+
+#: bookwyrm/templates/settings/federation/edit_instance.html:7
+#: bookwyrm/templates/settings/federation/instance_blocklist.html:7
+msgid "Back to instance list"
+msgstr "Grįžti į serverių sąrašą"
+
+#: bookwyrm/templates/settings/federation/edit_instance.html:16
+#: bookwyrm/templates/settings/federation/instance_blocklist.html:16
+msgid "Import block list"
+msgstr "Importuoti blokuojamų sąrašą"
+
+#: bookwyrm/templates/settings/federation/edit_instance.html:30
+msgid "Instance:"
+msgstr "Serveris:"
+
+#: bookwyrm/templates/settings/federation/edit_instance.html:39
+#: bookwyrm/templates/settings/federation/instance.html:28
+#: bookwyrm/templates/settings/users/user_info.html:106
+msgid "Status:"
+msgstr "Būsena:"
+
+#: bookwyrm/templates/settings/federation/edit_instance.html:52
+#: bookwyrm/templates/settings/federation/instance.html:22
+#: bookwyrm/templates/settings/users/user_info.html:100
+msgid "Software:"
+msgstr "Programinė įranga:"
+
+#: bookwyrm/templates/settings/federation/edit_instance.html:61
+#: bookwyrm/templates/settings/federation/instance.html:25
+#: bookwyrm/templates/settings/users/user_info.html:103
+msgid "Version:"
+msgstr "Versija:"
+
+#: bookwyrm/templates/settings/federation/edit_instance.html:70
+msgid "Notes:"
+msgstr "Užrašai:"
+
+#: bookwyrm/templates/settings/federation/instance.html:19
+msgid "Details"
+msgstr "Išsami informacija"
+
+#: bookwyrm/templates/settings/federation/instance.html:35
+#: bookwyrm/templates/user/layout.html:64
+msgid "Activity"
+msgstr "Veikla"
+
+#: bookwyrm/templates/settings/federation/instance.html:38
+msgid "Users:"
+msgstr "Nariai:"
+
+#: bookwyrm/templates/settings/federation/instance.html:41
+#: bookwyrm/templates/settings/federation/instance.html:47
+msgid "View all"
+msgstr "Žiūrėti viską"
+
+#: bookwyrm/templates/settings/federation/instance.html:44
+#: bookwyrm/templates/settings/users/user_info.html:56
+msgid "Reports:"
+msgstr "Pranešimai:"
+
+#: bookwyrm/templates/settings/federation/instance.html:50
+msgid "Followed by us:"
+msgstr "Sekame:"
+
+#: bookwyrm/templates/settings/federation/instance.html:55
+msgid "Followed by them:"
+msgstr "Seka:"
+
+#: bookwyrm/templates/settings/federation/instance.html:60
+msgid "Blocked by us:"
+msgstr "Blokuojame:"
+
+#: bookwyrm/templates/settings/federation/instance.html:72
+#: bookwyrm/templates/settings/users/user_info.html:110
+msgid "Notes"
+msgstr "Užrašai"
+
+#: bookwyrm/templates/settings/federation/instance.html:75
+#: bookwyrm/templates/snippets/status/status_options.html:24
+msgid "Edit"
+msgstr "Redaguoti"
+
+#: bookwyrm/templates/settings/federation/instance.html:79
+msgid "No notes"
+msgstr "Užrašų nėra"
+
+#: bookwyrm/templates/settings/federation/instance.html:94
+#: bookwyrm/templates/settings/users/user_moderation_actions.html:8
+msgid "Actions"
+msgstr "Veiksmai"
+
+#: bookwyrm/templates/settings/federation/instance.html:98
+#: bookwyrm/templates/snippets/block_button.html:5
+msgid "Block"
+msgstr "Blokuoti"
+
+#: bookwyrm/templates/settings/federation/instance.html:99
+msgid "All users from this instance will be deactivated."
+msgstr "Visi šio serverio nariai bus deaktyvuoti."
+
+#: bookwyrm/templates/settings/federation/instance.html:104
+#: bookwyrm/templates/snippets/block_button.html:10
+msgid "Un-block"
+msgstr "Atblokuoti"
+
+#: bookwyrm/templates/settings/federation/instance.html:105
+msgid "All users from this instance will be re-activated."
+msgstr "Visi šio serverio nariai bus vėl aktyvuoti."
+
+#: bookwyrm/templates/settings/federation/instance_blocklist.html:6
+msgid "Import Blocklist"
+msgstr "Importuoti blokuojamų sąrašą"
+
+#: bookwyrm/templates/settings/federation/instance_blocklist.html:26
+#: bookwyrm/templates/snippets/goal_progress.html:7
+msgid "Success!"
+msgstr "Valio!"
+
+#: bookwyrm/templates/settings/federation/instance_blocklist.html:30
+msgid "Successfully blocked:"
+msgstr "Sėkmingai užblokuota:"
+
+#: bookwyrm/templates/settings/federation/instance_blocklist.html:32
+msgid "Failed:"
+msgstr "Nepavyko:"
+
+#: bookwyrm/templates/settings/federation/instance_list.html:3
+#: bookwyrm/templates/settings/federation/instance_list.html:5
+#: bookwyrm/templates/settings/layout.html:45
+msgid "Federated Instances"
+msgstr "Susijungę serveriai"
+
+#: bookwyrm/templates/settings/federation/instance_list.html:32
+#: bookwyrm/templates/settings/users/server_filter.html:5
+msgid "Instance name"
+msgstr "Serverio pavadinimas"
+
+#: bookwyrm/templates/settings/federation/instance_list.html:40
+msgid "Software"
+msgstr "Programinė įranga"
+
+#: bookwyrm/templates/settings/federation/instance_list.html:63
+msgid "No instances found"
+msgstr "Serverių nerasta"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:4
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:11
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:25
+#: bookwyrm/templates/settings/invites/manage_invites.html:11
+msgid "Invite Requests"
+msgstr "Kvietimo prašymai"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:23
+msgid "Ignored Invite Requests"
+msgstr "Ignoruoti kvietimo prašymai"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:35
+msgid "Date requested"
+msgstr "Prašymo data"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:39
+msgid "Date accepted"
+msgstr "Priėmimo data"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:42
+msgid "Email"
+msgstr "El. paštas"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:47
+msgid "Action"
+msgstr "Veiksmas"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:50
+msgid "No requests"
+msgstr "Prašymų nėra"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:59
+#: bookwyrm/templates/settings/invites/status_filter.html:16
+msgid "Accepted"
+msgstr "Priimta"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:61
+#: bookwyrm/templates/settings/invites/status_filter.html:12
+msgid "Sent"
+msgstr "Išsiųsta"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:63
+#: bookwyrm/templates/settings/invites/status_filter.html:8
+msgid "Requested"
+msgstr "Užklausta"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:73
+msgid "Send invite"
+msgstr "Siųsti pakvietimą"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:75
+msgid "Re-send invite"
+msgstr "Pakartotinai siųsti pakvietimą"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:95
+msgid "Ignore"
+msgstr "Ignoruoti"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:97
+msgid "Un-ignore"
+msgstr "Nebeignoruoti"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:108
+msgid "Back to pending requests"
+msgstr "Grįžti į laukiančius prašymus"
+
+#: bookwyrm/templates/settings/invites/manage_invite_requests.html:110
+msgid "View ignored requests"
+msgstr "Žiūrėti ignoruotus prašymus"
+
+#: bookwyrm/templates/settings/invites/manage_invites.html:21
+msgid "Generate New Invite"
+msgstr "Sugeneruoti naują pakvietimą"
+
+#: bookwyrm/templates/settings/invites/manage_invites.html:27
+msgid "Expiry:"
+msgstr "Galiojimo pabaiga:"
+
+#: bookwyrm/templates/settings/invites/manage_invites.html:33
+msgid "Use limit:"
+msgstr "Naudojimo limitas:"
+
+#: bookwyrm/templates/settings/invites/manage_invites.html:40
+msgid "Create Invite"
+msgstr "Sukurti pakvietimą"
+
+#: bookwyrm/templates/settings/invites/manage_invites.html:47
+msgid "Link"
+msgstr "Nuoroda"
+
+#: bookwyrm/templates/settings/invites/manage_invites.html:48
+msgid "Expires"
+msgstr "Baigia galioti"
+
+#: bookwyrm/templates/settings/invites/manage_invites.html:49
+msgid "Max uses"
+msgstr "Maks. naudojimų"
+
+#: bookwyrm/templates/settings/invites/manage_invites.html:50
+msgid "Times used"
+msgstr "Kartų naudota"
+
+#: bookwyrm/templates/settings/invites/manage_invites.html:53
+msgid "No active invites"
+msgstr "Nėra aktyvių pakvietimų"
+
+#: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:5
+#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:10
+msgid "Add IP address"
+msgstr "Pridėti IP adresą"
+
+#: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:11
+msgid "Use IP address blocks with caution, and consider using blocks only temporarily, as IP addresses are often shared or change hands. If you block your own IP, you will not be able to access this page."
+msgstr "Atsargiai naudokite IP adresų blokus. Rekomenduojame juos naudoti tik laikinai, nes IP adresai dažnu atveju yra bendrinami arba pereina kitiems. Jei užblokuosite savo IP, nebegalėsite pasiekti šio puslapio."
+
+#: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:18
+msgid "IP Address:"
+msgstr "IP adresas:"
+
+#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:5
+#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:7
+#: bookwyrm/templates/settings/layout.html:63
+msgid "IP Address Blocklist"
+msgstr "Juodasis IP adresų sąrašas"
+
+#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:18
+msgid "Any traffic from this IP address will get a 404 response when trying to access any part of the application."
+msgstr "Bandant pasiekti bet kurią programėlės dalį, šiam IP adresui visada matysis 404 klaidos kodas."
+
+#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:24
+msgid "Address"
+msgstr "Adresas"
+
+#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:46
+msgid "No IP addresses currently blocked"
+msgstr "Šiuo metu neblokuojamas joks IP adresas"
+
+#: bookwyrm/templates/settings/ip_blocklist/ip_tooltip.html:6
+msgid "You can block IP ranges using CIDR syntax."
+msgstr "IP rėžius galite blokuoti naudodami CIDR sintaksę."
+
+#: bookwyrm/templates/settings/layout.html:4
+msgid "Administration"
+msgstr "Administravimas"
+
+#: bookwyrm/templates/settings/layout.html:29
+msgid "Manage Users"
+msgstr "Tvarkyti naudotojus"
+
+#: bookwyrm/templates/settings/layout.html:51
+msgid "Moderation"
+msgstr "Moderavimas"
+
+#: bookwyrm/templates/settings/layout.html:55
+#: bookwyrm/templates/settings/reports/reports.html:8
+#: bookwyrm/templates/settings/reports/reports.html:17
+msgid "Reports"
+msgstr "Pranešimai"
+
+#: bookwyrm/templates/settings/layout.html:68
+msgid "Instance Settings"
+msgstr "Serverio nustatymai"
+
+#: bookwyrm/templates/settings/layout.html:76
+#: bookwyrm/templates/settings/site.html:4
+#: bookwyrm/templates/settings/site.html:6
+msgid "Site Settings"
+msgstr "Puslapio nustatymai"
+
+#: bookwyrm/templates/settings/reports/report.html:5
+#: bookwyrm/templates/settings/reports/report.html:8
+#: bookwyrm/templates/settings/reports/report_preview.html:6
+#, python-format
+msgid "Report #%(report_id)s: %(username)s"
+msgstr "Pranešti apie #%(report_id)s: %(username)s"
+
+#: bookwyrm/templates/settings/reports/report.html:9
+msgid "Back to reports"
+msgstr "Atgal į pranešimus"
+
+#: bookwyrm/templates/settings/reports/report.html:23
+msgid "Moderator Comments"
+msgstr "Moderatoriaus komentarai"
+
+#: bookwyrm/templates/settings/reports/report.html:41
+#: bookwyrm/templates/snippets/create_status.html:28
+msgid "Comment"
+msgstr "Komentuoti"
+
+#: bookwyrm/templates/settings/reports/report.html:46
+msgid "Reported statuses"
+msgstr "Praneštos būsenos"
+
+#: bookwyrm/templates/settings/reports/report.html:48
+msgid "No statuses reported"
+msgstr "Nepranešta apie būsenas"
+
+#: bookwyrm/templates/settings/reports/report.html:54
+msgid "Status has been deleted"
+msgstr "Būsena ištrinta"
+
+#: bookwyrm/templates/settings/reports/report_preview.html:13
+msgid "No notes provided"
+msgstr "Užrašų nepateikta"
+
+#: bookwyrm/templates/settings/reports/report_preview.html:20
+#, python-format
+msgid "Reported by %(username)s"
+msgstr "Pranešė %(username)s"
+
+#: bookwyrm/templates/settings/reports/report_preview.html:30
+msgid "Re-open"
+msgstr "Atidaryti pakartotinai"
+
+#: bookwyrm/templates/settings/reports/report_preview.html:32
+msgid "Resolve"
+msgstr "Išspręsti"
+
+#: bookwyrm/templates/settings/reports/reports.html:6
+#, python-format
+msgid "Reports: %(instance_name)s"
+msgstr "Pranešimai: %(instance_name)s"
+
+#: bookwyrm/templates/settings/reports/reports.html:14
+#, python-format
+msgid "Reports: %(instance_name)s"
+msgstr "Pranešimai: %(instance_name)s"
+
+#: bookwyrm/templates/settings/reports/reports.html:28
+msgid "Resolved"
+msgstr "Išspręsta"
+
+#: bookwyrm/templates/settings/reports/reports.html:37
+msgid "No reports found."
+msgstr "Pranešimų nerasta."
+
+#: bookwyrm/templates/settings/site.html:10
+#: bookwyrm/templates/settings/site.html:21
+msgid "Instance Info"
+msgstr "Serverio informacija"
+
+#: bookwyrm/templates/settings/site.html:11
+#: bookwyrm/templates/settings/site.html:54
+msgid "Images"
+msgstr "Paveikslėliai"
+
+#: bookwyrm/templates/settings/site.html:12
+#: bookwyrm/templates/settings/site.html:74
+msgid "Footer Content"
+msgstr "Poraštės turinys"
+
+#: bookwyrm/templates/settings/site.html:13
+#: bookwyrm/templates/settings/site.html:98
+msgid "Registration"
+msgstr "Registracija"
+
+#: bookwyrm/templates/settings/site.html:24
+msgid "Instance Name:"
+msgstr "Serverio pavadinimas:"
+
+#: bookwyrm/templates/settings/site.html:28
+msgid "Tagline:"
+msgstr "Žymos linija:"
+
+#: bookwyrm/templates/settings/site.html:32
+msgid "Instance description:"
+msgstr "Serverio aprašymas:"
+
+#: bookwyrm/templates/settings/site.html:36
+msgid "Short description:"
+msgstr "Trumpas aprašymas:"
+
+#: bookwyrm/templates/settings/site.html:37
+msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support HTML or Markdown."
+msgstr "Naudota, kai turinys buvo peržiūrimas per joinbookwyrm.com. Nepalaiko HTML arba „Markdown“."
+
+#: bookwyrm/templates/settings/site.html:41
+msgid "Code of conduct:"
+msgstr "Elgesio kodeksas:"
+
+#: bookwyrm/templates/settings/site.html:45
+msgid "Privacy Policy:"
+msgstr "Privatumo politika:"
+
+#: bookwyrm/templates/settings/site.html:57
+msgid "Logo:"
+msgstr "Logotipas:"
+
+#: bookwyrm/templates/settings/site.html:61
+msgid "Logo small:"
+msgstr "Mažas logotipas:"
+
+#: bookwyrm/templates/settings/site.html:65
+msgid "Favicon:"
+msgstr "Puslapio ikonėlė:"
+
+#: bookwyrm/templates/settings/site.html:77
+msgid "Support link:"
+msgstr "Paramos nuoroda:"
+
+#: bookwyrm/templates/settings/site.html:81
+msgid "Support title:"
+msgstr "Paramos pavadinimas:"
+
+#: bookwyrm/templates/settings/site.html:85
+msgid "Admin email:"
+msgstr "Administratoriaus el. paštas:"
+
+#: bookwyrm/templates/settings/site.html:89
+msgid "Additional info:"
+msgstr "Papildoma informacija:"
+
+#: bookwyrm/templates/settings/site.html:103
+msgid "Allow registration"
+msgstr "Leisti registruotis"
+
+#: bookwyrm/templates/settings/site.html:109
+msgid "Allow invite requests"
+msgstr "Leisti prašyti kvietimų"
+
+#: bookwyrm/templates/settings/site.html:115
+msgid "Require users to confirm email address"
+msgstr "Reikalauti el. pašto patvirtinimo"
+
+#: bookwyrm/templates/settings/site.html:117
+msgid "(Recommended if registration is open)"
+msgstr "(Rekomenduojama, jei leidžiama registruotis)"
+
+#: bookwyrm/templates/settings/site.html:120
+msgid "Registration closed text:"
+msgstr "Užrakintos registracijos tekstas:"
+
+#: bookwyrm/templates/settings/site.html:124
+msgid "Invite request text:"
+msgstr "Kvietimo prašymo tekstas:"
+
+#: bookwyrm/templates/settings/users/delete_user_form.html:5
+#: bookwyrm/templates/settings/users/user_moderation_actions.html:31
+msgid "Permanently delete user"
+msgstr "Visam laikui ištrinti vartotoją"
+
+#: bookwyrm/templates/settings/users/delete_user_form.html:12
+#, python-format
+msgid "Are you sure you want to delete %(username)s's account? This action cannot be undone. To proceed, please enter your password to confirm deletion."
+msgstr "Ar tikrai norite ištrinti %(username)s paskyrą? To negalėsite atšaukti. Norėdami tęsti, įveskite savo slaptažodį, kad patvirtintumėte sprendimą trinti."
+
+#: bookwyrm/templates/settings/users/delete_user_form.html:17
+msgid "Your password:"
+msgstr "Jūsų slaptažodis:"
+
+#: bookwyrm/templates/settings/users/user.html:7
+msgid "Back to users"
+msgstr "Atgal į vartotojų sąrašą"
+
+#: bookwyrm/templates/settings/users/user_admin.html:7
+#, python-format
+msgid "Users: %(instance_name)s"
+msgstr "Vartotojai: %(instance_name)s"
+
+#: bookwyrm/templates/settings/users/user_admin.html:22
+#: bookwyrm/templates/settings/users/username_filter.html:5
+msgid "Username"
+msgstr "Vartotojo vardas"
+
+#: bookwyrm/templates/settings/users/user_admin.html:26
+msgid "Date Added"
+msgstr "Pridėjimo data"
+
+#: bookwyrm/templates/settings/users/user_admin.html:30
+msgid "Last Active"
+msgstr "Paskutinį kartą aktyvus"
+
+#: bookwyrm/templates/settings/users/user_admin.html:38
+msgid "Remote instance"
+msgstr "Nutolęs serveris"
+
+#: bookwyrm/templates/settings/users/user_admin.html:47
+#: bookwyrm/templates/settings/users/user_info.html:24
+msgid "Active"
+msgstr "Aktyvus"
+
+#: bookwyrm/templates/settings/users/user_admin.html:47
+#: bookwyrm/templates/settings/users/user_info.html:28
+msgid "Inactive"
+msgstr "Neaktyvus"
+
+#: bookwyrm/templates/settings/users/user_admin.html:52
+#: bookwyrm/templates/settings/users/user_info.html:120
+msgid "Not set"
+msgstr "Nenustatytas"
+
+#: bookwyrm/templates/settings/users/user_info.html:16
+msgid "View user profile"
+msgstr "Peržiūrėti vartotojo profilį"
+
+#: bookwyrm/templates/settings/users/user_info.html:36
+msgid "Local"
+msgstr "Vietinis"
+
+#: bookwyrm/templates/settings/users/user_info.html:38
+msgid "Remote"
+msgstr "Nutolęs"
+
+#: bookwyrm/templates/settings/users/user_info.html:47
+msgid "User details"
+msgstr "Vartotojo duomenys"
+
+#: bookwyrm/templates/settings/users/user_info.html:51
+msgid "Email:"
+msgstr "El. paštas:"
+
+#: bookwyrm/templates/settings/users/user_info.html:61
+msgid "(View reports)"
+msgstr "(Peržiūrėti ataskaitas)"
+
+#: bookwyrm/templates/settings/users/user_info.html:67
+msgid "Blocked by count:"
+msgstr "Užblokavę:"
+
+#: bookwyrm/templates/settings/users/user_info.html:70
+msgid "Last active date:"
+msgstr "Paskutinį kartą aktyvus:"
+
+#: bookwyrm/templates/settings/users/user_info.html:73
+msgid "Manually approved followers:"
+msgstr "Patvirtinti sekėjai:"
+
+#: bookwyrm/templates/settings/users/user_info.html:76
+msgid "Discoverable:"
+msgstr "Aptinkama:"
+
+#: bookwyrm/templates/settings/users/user_info.html:80
+msgid "Deactivation reason:"
+msgstr "Išjungimo priežastis:"
+
+#: bookwyrm/templates/settings/users/user_info.html:95
+msgid "Instance details"
+msgstr "Serverio informacija"
+
+#: bookwyrm/templates/settings/users/user_info.html:117
+msgid "View instance"
+msgstr "Peržiūrėti serverį"
+
+#: bookwyrm/templates/settings/users/user_moderation_actions.html:5
+msgid "Permanently deleted"
+msgstr "Visam laikui ištrintas"
+
+#: bookwyrm/templates/settings/users/user_moderation_actions.html:13
+#: bookwyrm/templates/snippets/status/status_options.html:32
+#: bookwyrm/templates/snippets/user_options.html:13
+msgid "Send direct message"
+msgstr "Siųsti asmeninę žinutę"
+
+#: bookwyrm/templates/settings/users/user_moderation_actions.html:20
+msgid "Suspend user"
+msgstr "Laikinai išjungti vartotoją"
+
+#: bookwyrm/templates/settings/users/user_moderation_actions.html:25
+msgid "Un-suspend user"
+msgstr "Atblokuoti narį"
+
+#: bookwyrm/templates/settings/users/user_moderation_actions.html:47
+msgid "Access level:"
+msgstr "Priėjimo lygis:"
+
+#: bookwyrm/templates/shelf/create_shelf_form.html:5
+msgid "Create Shelf"
+msgstr "Sukurti lentyną"
+
+#: bookwyrm/templates/shelf/edit_shelf_form.html:5
+msgid "Edit Shelf"
+msgstr "Redaguoti lentyną"
+
+#: bookwyrm/templates/shelf/shelf.html:28 bookwyrm/views/shelf/shelf.py:53
+msgid "All books"
+msgstr "Visos knygos"
+
+#: bookwyrm/templates/shelf/shelf.html:69
+msgid "Create shelf"
+msgstr "Sukurti lentyną"
+
+#: bookwyrm/templates/shelf/shelf.html:90
+#, python-format
+msgid "%(formatted_count)s book"
+msgid_plural "%(formatted_count)s books"
+msgstr[0] "%(formatted_count)s knyga"
+msgstr[1] "%(formatted_count)s knygos"
+msgstr[2] "%(formatted_count)s knygų"
+msgstr[3] "%(formatted_count)s knygos"
+
+#: bookwyrm/templates/shelf/shelf.html:97
+#, python-format
+msgid "(showing %(start)s-%(end)s)"
+msgstr "(rodoma %(start)s–%(end)s)"
+
+#: bookwyrm/templates/shelf/shelf.html:109
+msgid "Edit shelf"
+msgstr "Redaguoti lentyną"
+
+#: bookwyrm/templates/shelf/shelf.html:117
+msgid "Delete shelf"
+msgstr "Ištrinti lentyną"
+
+#: bookwyrm/templates/shelf/shelf.html:145
+#: bookwyrm/templates/shelf/shelf.html:171
+msgid "Shelved"
+msgstr "Sudėta į lentynas"
+
+#: bookwyrm/templates/shelf/shelf.html:146
+#: bookwyrm/templates/shelf/shelf.html:174
+msgid "Started"
+msgstr "Pradėta"
+
+#: bookwyrm/templates/shelf/shelf.html:147
+#: bookwyrm/templates/shelf/shelf.html:177
+msgid "Finished"
+msgstr "Baigta"
+
+#: bookwyrm/templates/shelf/shelf.html:203
+msgid "This shelf is empty."
+msgstr "Ši lentyna tuščia."
+
+#: bookwyrm/templates/snippets/add_to_group_button.html:15
+msgid "Invite"
+msgstr "Pakviesti"
+
+#: bookwyrm/templates/snippets/add_to_group_button.html:24
+msgid "Uninvite"
+msgstr "Atšaukti kvietimą"
+
+#: bookwyrm/templates/snippets/add_to_group_button.html:28
+#, python-format
+msgid "Remove @%(username)s"
+msgstr "Pašalinti @%(username)s"
+
+#: bookwyrm/templates/snippets/announcement.html:31
+#, python-format
+msgid "Posted by %(username)s"
+msgstr "Publikavo %(username)s"
+
+#: bookwyrm/templates/snippets/authors.html:22
+#, python-format
+msgid "and %(remainder_count_display)s other"
+msgid_plural "and %(remainder_count_display)s others"
+msgstr[0] "ir %(remainder_count_display)s kitas"
+msgstr[1] "ir %(remainder_count_display)s kiti"
+msgstr[2] "ir %(remainder_count_display)s kitų"
+msgstr[3] "ir %(remainder_count_display)s kitų"
+
+#: bookwyrm/templates/snippets/book_cover.html:61
+msgid "No cover"
+msgstr "Nėra viršelio"
+
+#: bookwyrm/templates/snippets/book_titleby.html:6
+#, python-format
+msgid "%(title)s by"
+msgstr "%(title)s"
+
+#: bookwyrm/templates/snippets/boost_button.html:20
+#: bookwyrm/templates/snippets/boost_button.html:21
+msgid "Boost"
+msgstr "Populiarinti"
+
+#: bookwyrm/templates/snippets/boost_button.html:33
+#: bookwyrm/templates/snippets/boost_button.html:34
+msgid "Un-boost"
+msgstr "Nepopuliarinti"
+
+#: bookwyrm/templates/snippets/create_status.html:39
+msgid "Quote"
+msgstr "Citata"
+
+#: bookwyrm/templates/snippets/create_status/comment.html:15
+msgid "Some thoughts on the book"
+msgstr "Mintys apie knygą"
+
+#: bookwyrm/templates/snippets/create_status/comment.html:27
+#: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:15
+msgid "Progress:"
+msgstr "Progresas:"
+
+#: bookwyrm/templates/snippets/create_status/comment.html:53
+#: bookwyrm/templates/snippets/progress_field.html:18
+msgid "pages"
+msgstr "puslapiai"
+
+#: bookwyrm/templates/snippets/create_status/comment.html:59
+#: bookwyrm/templates/snippets/progress_field.html:23
+msgid "percent"
+msgstr "procentai"
+
+#: bookwyrm/templates/snippets/create_status/comment.html:66
+#, python-format
+msgid "of %(pages)s pages"
+msgstr "iš %(pages)s psl."
+
+#: bookwyrm/templates/snippets/create_status/content_field.html:17
+#: bookwyrm/templates/snippets/status/layout.html:34
+#: bookwyrm/templates/snippets/status/layout.html:52
+#: bookwyrm/templates/snippets/status/layout.html:53
+msgid "Reply"
+msgstr "Atsakyti"
+
+#: bookwyrm/templates/snippets/create_status/content_field.html:17
+msgid "Content"
+msgstr "Turinys"
+
+#: bookwyrm/templates/snippets/create_status/content_warning_field.html:10
+msgid "Content warning:"
+msgstr "Įspėjimas dėl turinio:"
+
+#: bookwyrm/templates/snippets/create_status/content_warning_field.html:18
+msgid "Spoilers ahead!"
+msgstr "Galimas turinio atskleidimas!"
+
+#: bookwyrm/templates/snippets/create_status/content_warning_toggle.html:13
+msgid "Include spoiler alert"
+msgstr "Įdėti įspėjimą apie turinio atskleidimą"
+
+#: bookwyrm/templates/snippets/create_status/layout.html:48
+#: bookwyrm/templates/snippets/reading_modals/form.html:7
+msgid "Comment:"
+msgstr "Komentuoti:"
+
+#: bookwyrm/templates/snippets/create_status/post_options_block.html:8
+#: bookwyrm/templates/snippets/privacy-icons.html:15
+#: bookwyrm/templates/snippets/privacy-icons.html:16
+#: bookwyrm/templates/snippets/privacy_select.html:20
+#: bookwyrm/templates/snippets/privacy_select_no_followers.html:17
+msgid "Private"
+msgstr "Privatu"
+
+#: bookwyrm/templates/snippets/create_status/post_options_block.html:21
+msgid "Post"
+msgstr "Publikuoti"
+
+#: bookwyrm/templates/snippets/create_status/quotation.html:17
+msgid "Quote:"
+msgstr "Citata:"
+
+#: bookwyrm/templates/snippets/create_status/quotation.html:25
+#, python-format
+msgid "An excerpt from '%(book_title)s'"
+msgstr "Ištrauka iš „%(book_title)s“"
+
+#: bookwyrm/templates/snippets/create_status/quotation.html:32
+msgid "Position:"
+msgstr "Pozicija:"
+
+#: bookwyrm/templates/snippets/create_status/quotation.html:45
+msgid "On page:"
+msgstr "Puslapyje:"
+
+#: bookwyrm/templates/snippets/create_status/quotation.html:51
+msgid "At percent:"
+msgstr "Proc.:"
+
+#: bookwyrm/templates/snippets/create_status/review.html:25
+#, python-format
+msgid "Your review of '%(book_title)s'"
+msgstr "Jūsų apžvalga apie „%(book_title)s“"
+
+#: bookwyrm/templates/snippets/create_status/review.html:40
+msgid "Review:"
+msgstr "Atsiliepimas:"
+
+#: bookwyrm/templates/snippets/delete_readthrough_modal.html:4
+msgid "Delete these read dates?"
+msgstr "Ištrinti šias skaitymo datas?"
+
+#: bookwyrm/templates/snippets/delete_readthrough_modal.html:7
+#, python-format
+msgid "You are deleting this readthrough and its %(count)s associated progress updates."
+msgstr "Trinate tai, kas perskaityta ir %(count)s susietų progreso naujinių."
+
+#: bookwyrm/templates/snippets/fav_button.html:16
+#: bookwyrm/templates/snippets/fav_button.html:17
+msgid "Like"
+msgstr "Mėgti"
+
+#: bookwyrm/templates/snippets/fav_button.html:30
+#: bookwyrm/templates/snippets/fav_button.html:31
+msgid "Un-like"
+msgstr "Nebemėgti"
+
+#: bookwyrm/templates/snippets/filters_panel/filters_panel.html:7
+msgid "Show filters"
+msgstr "Rodyti filtrus"
+
+#: bookwyrm/templates/snippets/filters_panel/filters_panel.html:9
+msgid "Hide filters"
+msgstr "Slėpti filtrus"
+
+#: bookwyrm/templates/snippets/filters_panel/filters_panel.html:22
+msgid "Apply filters"
+msgstr "Taikyti filtrus"
+
+#: bookwyrm/templates/snippets/filters_panel/filters_panel.html:26
+msgid "Clear filters"
+msgstr "Valyti filtrus"
+
+#: bookwyrm/templates/snippets/follow_button.html:14
+#, python-format
+msgid "Follow @%(username)s"
+msgstr "Sekti @%(username)s"
+
+#: bookwyrm/templates/snippets/follow_button.html:16
+msgid "Follow"
+msgstr "Sekti"
+
+#: bookwyrm/templates/snippets/follow_button.html:25
+msgid "Undo follow request"
+msgstr "Atšaukti prašymus sekti"
+
+#: bookwyrm/templates/snippets/follow_button.html:30
+#, python-format
+msgid "Unfollow @%(username)s"
+msgstr "Nebesekti @%(username)s"
+
+#: bookwyrm/templates/snippets/follow_button.html:32
+msgid "Unfollow"
+msgstr "Nebesekti"
+
+#: bookwyrm/templates/snippets/follow_request_buttons.html:7
+#: bookwyrm/templates/snippets/join_invitation_buttons.html:8
+msgid "Accept"
+msgstr "Sutikti"
+
+#: bookwyrm/templates/snippets/form_rate_stars.html:20
+#: bookwyrm/templates/snippets/stars.html:13
+msgid "No rating"
+msgstr "Įvertinimų nėra"
+
+#: bookwyrm/templates/snippets/form_rate_stars.html:28
+#, python-format
+msgid "%(half_rating)s star"
+msgid_plural "%(half_rating)s stars"
+msgstr[0] "%(half_rating)s žvaigždutė"
+msgstr[1] "%(half_rating)s žvaigždutės"
+msgstr[2] "%(half_rating)s žvaigždutės"
+msgstr[3] "%(half_rating)s žvaigždučių"
+
+#: bookwyrm/templates/snippets/form_rate_stars.html:64
+#: bookwyrm/templates/snippets/stars.html:7
+#, python-format
+msgid "%(rating)s star"
+msgid_plural "%(rating)s stars"
+msgstr[0] "%(rating)s žvaigždutė"
+msgstr[1] "%(rating)s žvaigždutės"
+msgstr[2] "%(rating)s žvaigždutės"
+msgstr[3] "%(rating)s žvaigždučių"
+
+#: bookwyrm/templates/snippets/generated_status/goal.html:2
+#, python-format
+msgid "set a goal to read %(counter)s book in %(year)s"
+msgid_plural "set a goal to read %(counter)s books in %(year)s"
+msgstr[0] "nustatė tikslą perskaityti %(counter)s knygą %(year)s m."
+msgstr[1] "nustatė tikslą perskaityti %(counter)s knygas %(year)s m."
+msgstr[2] "nustatė tikslą perskaityti %(counter)s knygų %(year)s m."
+msgstr[3] "nustatė tikslą perskaityti %(counter)s knygas %(year)s m."
+
+#: bookwyrm/templates/snippets/generated_status/rating.html:3
+#, python-format
+msgid "rated %(title)s: %(display_rating)s star"
+msgid_plural "rated %(title)s: %(display_rating)s stars"
+msgstr[0] "įvertinta %(title)s: %(display_rating)s žvaigždute"
+msgstr[1] "įvertinta %(title)s: %(display_rating)s žvaigždutėmis"
+msgstr[2] "įvertinta %(title)s: %(display_rating)s žvaigždutėmis"
+msgstr[3] "įvertinta %(title)s: %(display_rating)s žvaigždutėmis"
+
+#: bookwyrm/templates/snippets/generated_status/review_pure_name.html:4
+#, python-format
+msgid "Review of \"%(book_title)s\" (%(display_rating)s star): %(review_title)s"
+msgid_plural "Review of \"%(book_title)s\" (%(display_rating)s stars): %(review_title)s"
+msgstr[0] "Knygos „%(book_title)s“ (%(display_rating)s žvaigždutė) apžvalga: %(review_title)s"
+msgstr[1] "Knygos „%(book_title)s“ (%(display_rating)s žvaigždutės) apžvalga: %(review_title)s"
+msgstr[2] "Knygos „%(book_title)s“ (%(display_rating)s žvaigždutės) apžvalga: %(review_title)s"
+msgstr[3] "Knygos „%(book_title)s“ (%(display_rating)s žvaigždutės) apžvalga: %(review_title)s"
+
+#: bookwyrm/templates/snippets/generated_status/review_pure_name.html:8
+#, python-format
+msgid "Review of \"%(book_title)s\": %(review_title)s"
+msgstr "Knygos „%(book_title)s“ apžvalga: %(review_title)s"
+
+#: bookwyrm/templates/snippets/goal_form.html:4
+#, python-format
+msgid "Set a goal for how many books you'll finish reading in %(year)s, and track your progress throughout the year."
+msgstr "Nusistatykite tikslą, kiek knygų perskaitysite %(year)s m. ir metų eigoje sekite savo progresą."
+
+#: bookwyrm/templates/snippets/goal_form.html:16
+msgid "Reading goal:"
+msgstr "Skaitymo tikslai:"
+
+#: bookwyrm/templates/snippets/goal_form.html:21
+msgid "books"
+msgstr "knygos"
+
+#: bookwyrm/templates/snippets/goal_form.html:26
+msgid "Goal privacy:"
+msgstr "Tikslo privatumas:"
+
+#: bookwyrm/templates/snippets/goal_form.html:33
+#: bookwyrm/templates/snippets/reading_modals/layout.html:13
+msgid "Post to feed"
+msgstr "Skelbti"
+
+#: bookwyrm/templates/snippets/goal_form.html:37
+msgid "Set goal"
+msgstr "Nustatyti tikslą"
+
+#: bookwyrm/templates/snippets/goal_progress.html:9
+#, python-format
+msgid "%(percent)s%% complete!"
+msgstr "%(percent)s%% baigta!"
+
+#: bookwyrm/templates/snippets/goal_progress.html:12
+#, python-format
+msgid "You've read %(read_count)s of %(goal_count)s books."
+msgstr "Perskaitėte %(read_count)s iš %(goal_count)s knygų."
+
+#: bookwyrm/templates/snippets/goal_progress.html:14
+#, python-format
+msgid "%(username)s has read %(read_count)s of %(goal_count)s books."
+msgstr "%(username)s perskaitė %(read_count)s iš %(goal_count)s knygų."
+
+#: bookwyrm/templates/snippets/page_text.html:8
+#, python-format
+msgid "page %(page)s of %(total_pages)s"
+msgstr "%(page)s psl. iš %(total_pages)s"
+
+#: bookwyrm/templates/snippets/page_text.html:14
+#, python-format
+msgid "page %(page)s"
+msgstr "%(page)s psl."
+
+#: bookwyrm/templates/snippets/pagination.html:12
+msgid "Previous"
+msgstr "Ankstesnis"
+
+#: bookwyrm/templates/snippets/pagination.html:23
+msgid "Next"
+msgstr "Kitas"
+
+#: bookwyrm/templates/snippets/privacy-icons.html:3
+#: bookwyrm/templates/snippets/privacy-icons.html:4
+#: bookwyrm/templates/snippets/privacy_select.html:11
+#: bookwyrm/templates/snippets/privacy_select_no_followers.html:11
+msgid "Public"
+msgstr "Viešas"
+
+#: bookwyrm/templates/snippets/privacy-icons.html:7
+#: bookwyrm/templates/snippets/privacy-icons.html:8
+#: bookwyrm/templates/snippets/privacy_select.html:14
+#: bookwyrm/templates/snippets/privacy_select_no_followers.html:14
+msgid "Unlisted"
+msgstr "Nėra sąraše"
+
+#: bookwyrm/templates/snippets/privacy-icons.html:12
+msgid "Followers-only"
+msgstr "Tik sekėjai"
+
+#: bookwyrm/templates/snippets/privacy_select.html:6
+#: bookwyrm/templates/snippets/privacy_select_no_followers.html:6
+msgid "Post privacy"
+msgstr "Įrašo privatumas"
+
+#: bookwyrm/templates/snippets/privacy_select.html:17
+#: bookwyrm/templates/user/relationships/followers.html:6
+#: bookwyrm/templates/user/relationships/layout.html:11
+msgid "Followers"
+msgstr "Sekėjai"
+
+#: bookwyrm/templates/snippets/rate_action.html:4
+msgid "Leave a rating"
+msgstr "Palikti įvertinimą"
+
+#: bookwyrm/templates/snippets/rate_action.html:19
+msgid "Rate"
+msgstr "Įvertinti"
+
+#: bookwyrm/templates/snippets/reading_modals/finish_reading_modal.html:6
+#, python-format
+msgid "Finish \"%(book_title)s\""
+msgstr "Užbaigti „%(book_title)s“"
+
+#: bookwyrm/templates/snippets/reading_modals/finish_reading_modal.html:23
+#: bookwyrm/templates/snippets/reading_modals/start_reading_modal.html:20
+#: bookwyrm/templates/snippets/readthrough_form.html:7
+msgid "Started reading"
+msgstr "Pradėta skaityti"
+
+#: bookwyrm/templates/snippets/reading_modals/finish_reading_modal.html:31
+#: bookwyrm/templates/snippets/readthrough_form.html:20
+msgid "Finished reading"
+msgstr "Baigta skaityti"
+
+#: bookwyrm/templates/snippets/reading_modals/form.html:9
+msgid "(Optional)"
+msgstr "(Nebūtina)"
+
+#: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:5
+#: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:50
+msgid "Update progress"
+msgstr "Atnaujinti progresą"
+
+#: bookwyrm/templates/snippets/reading_modals/start_reading_modal.html:6
+#, python-format
+msgid "Start \"%(book_title)s\""
+msgstr "Pradėti „%(book_title)s“"
+
+#: bookwyrm/templates/snippets/reading_modals/want_to_read_modal.html:6
+#, python-format
+msgid "Want to Read \"%(book_title)s\""
+msgstr "Noriu perskaityti „%(book_title)s“"
+
+#: bookwyrm/templates/snippets/readthrough_form.html:14
+msgid "Progress"
+msgstr "Progresas"
+
+#: bookwyrm/templates/snippets/register_form.html:32
+msgid "Sign Up"
+msgstr "Registruotis"
+
+#: bookwyrm/templates/snippets/report_button.html:6
+msgid "Report"
+msgstr "Pranešti"
+
+#: bookwyrm/templates/snippets/report_modal.html:6
+#, python-format
+msgid "Report @%(username)s"
+msgstr "Pranešti apie @%(username)s"
+
+#: bookwyrm/templates/snippets/report_modal.html:23
+#, python-format
+msgid "This report will be sent to %(site_name)s's moderators for review."
+msgstr "Šis pranešimas bus nusiųstas peržiūrėti %(site_name)s puslapio moderatoriams."
+
+#: bookwyrm/templates/snippets/report_modal.html:24
+msgid "More info about this report:"
+msgstr "Daugiau informacijos apie šį pranešimą:"
+
+#: bookwyrm/templates/snippets/shelf_selector.html:4
+msgid "Move book"
+msgstr "Perkelti knygą"
+
+#: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown.html:5
+msgid "More shelves"
+msgstr "Daugiau lentynų"
+
+#: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:17
+#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:24
+msgid "Start reading"
+msgstr "Pradėti skaityti"
+
+#: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:29
+#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:36
+msgid "Want to read"
+msgstr "Noriu perskaityti"
+
+#: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:62
+#, python-format
+msgid "Remove from %(name)s"
+msgstr "Pašalinti iš %(name)s"
+
+#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:30
+msgid "Finish reading"
+msgstr "Baigti skaityti"
+
+#: bookwyrm/templates/snippets/status/content_status.html:72
+msgid "Content warning"
+msgstr "Įspėjimas dėl turinio"
+
+#: bookwyrm/templates/snippets/status/content_status.html:79
+msgid "Show status"
+msgstr "Rodyti būseną"
+
+#: bookwyrm/templates/snippets/status/content_status.html:101
+#, python-format
+msgid "(Page %(page)s)"
+msgstr "(Psl. %(page)s)"
+
+#: bookwyrm/templates/snippets/status/content_status.html:103
+#, python-format
+msgid "(%(percent)s%%)"
+msgstr "(%(percent)s%%)"
+
+#: bookwyrm/templates/snippets/status/content_status.html:125
+msgid "Open image in new window"
+msgstr "Atidaryti paveikslėlį naujame lange"
+
+#: bookwyrm/templates/snippets/status/content_status.html:144
+msgid "Hide status"
+msgstr "Slėpti būseną"
+
+#: bookwyrm/templates/snippets/status/header.html:45
+#, python-format
+msgid "edited %(date)s"
+msgstr "redaguota %(date)s"
+
+#: bookwyrm/templates/snippets/status/headers/comment.html:2
+#, python-format
+msgid "commented on %(book)s"
+msgstr "komentuota %(book)s"
+
+#: bookwyrm/templates/snippets/status/headers/note.html:8
+#, python-format
+msgid "replied to %(username)s's status"
+msgstr "atsakyta į %(username)s būseną"
+
+#: bookwyrm/templates/snippets/status/headers/quotation.html:2
+#, python-format
+msgid "quoted %(book)s"
+msgstr "pacitavo %(book)s"
+
+#: bookwyrm/templates/snippets/status/headers/rating.html:3
+#, python-format
+msgid "rated %(book)s:"
+msgstr "įvertinta %(book)s:"
+
+#: bookwyrm/templates/snippets/status/headers/read.html:7
+#, python-format
+msgid "finished reading %(book)s"
+msgstr "baigė skaityti %(book)s"
+
+#: bookwyrm/templates/snippets/status/headers/reading.html:7
+#, python-format
+msgid "started reading %(book)s"
+msgstr "pradėjo skaityti %(book)s"
+
+#: bookwyrm/templates/snippets/status/headers/review.html:3
+#, python-format
+msgid "reviewed %(book)s"
+msgstr "apžvelgė %(book)s"
+
+#: bookwyrm/templates/snippets/status/headers/to_read.html:7
+#, python-format
+msgid "%(username)s wants to read %(book)s"
+msgstr "%(username)s nori perskaityti %(book)s"
+
+#: bookwyrm/templates/snippets/status/layout.html:24
+#: bookwyrm/templates/snippets/status/status_options.html:17
+msgid "Delete status"
+msgstr "Ištrinti įrašą"
+
+#: bookwyrm/templates/snippets/status/layout.html:56
+#: bookwyrm/templates/snippets/status/layout.html:57
+msgid "Boost status"
+msgstr "Pagreitinti būseną"
+
+#: bookwyrm/templates/snippets/status/layout.html:60
+#: bookwyrm/templates/snippets/status/layout.html:61
+msgid "Like status"
+msgstr "Mėgti būseną"
+
+#: bookwyrm/templates/snippets/status/status.html:10
+msgid "boosted"
+msgstr "iškėlė"
+
+#: bookwyrm/templates/snippets/status/status_options.html:7
+#: bookwyrm/templates/snippets/user_options.html:7
+msgid "More options"
+msgstr "Daugiau parinkčių"
+
+#: bookwyrm/templates/snippets/switch_edition_button.html:5
+msgid "Switch to this edition"
+msgstr "Perjungti į šį leidimą"
+
+#: bookwyrm/templates/snippets/table-sort-header.html:6
+msgid "Sorted ascending"
+msgstr "Surūšiuota didėjimo tvarka"
+
+#: bookwyrm/templates/snippets/table-sort-header.html:10
+msgid "Sorted descending"
+msgstr "Surūšiuota mažėjimo tvarka"
+
+#: bookwyrm/templates/snippets/trimmed_text.html:17
+msgid "Show more"
+msgstr "Rodyti daugiau"
+
+#: bookwyrm/templates/snippets/trimmed_text.html:35
+msgid "Show less"
+msgstr "Rodyti mažiau"
+
+#: bookwyrm/templates/user/books_header.html:10
+msgid "Your books"
+msgstr "Jūsų knygos"
+
+#: bookwyrm/templates/user/books_header.html:15
+#, python-format
+msgid "%(username)s's books"
+msgstr "%(username)s – knygos"
+
+#: bookwyrm/templates/user/goal.html:8
+#, python-format
+msgid "%(year)s Reading Progress"
+msgstr "%(year)s m. skaitymo progresas"
+
+#: bookwyrm/templates/user/goal.html:12
+msgid "Edit Goal"
+msgstr "Redaguoti tikslą"
+
+#: bookwyrm/templates/user/goal.html:28
+#, python-format
+msgid "%(name)s hasn't set a reading goal for %(year)s."
+msgstr "%(name)s nenustatė %(year)s m. skaitymo tikslo."
+
+#: bookwyrm/templates/user/goal.html:40
+#, python-format
+msgid "Your %(year)s Books"
+msgstr "Jūsų %(year)s m. knygos"
+
+#: bookwyrm/templates/user/goal.html:42
+#, python-format
+msgid "%(username)s's %(year)s Books"
+msgstr "%(username)s – %(year)s m. knygos"
+
+#: bookwyrm/templates/user/groups.html:9
+msgid "Your Groups"
+msgstr "Jūsų grupės"
+
+#: bookwyrm/templates/user/groups.html:11
+#, python-format
+msgid "Groups: %(username)s"
+msgstr "Grupės: %(username)s"
+
+#: bookwyrm/templates/user/groups.html:17
+msgid "Create group"
+msgstr "Sukurti grupę"
+
+#: bookwyrm/templates/user/layout.html:19 bookwyrm/templates/user/user.html:10
+msgid "User Profile"
+msgstr "Naudotojo paskyra"
+
+#: bookwyrm/templates/user/layout.html:45
+msgid "Follow Requests"
+msgstr "Sekti prašymus"
+
+#: bookwyrm/templates/user/layout.html:70
+msgid "Reading Goal"
+msgstr "Skaitymo tikslas"
+
+#: bookwyrm/templates/user/layout.html:76
+msgid "Groups"
+msgstr "Grupės"
+
+#: bookwyrm/templates/user/lists.html:11
+#, python-format
+msgid "Lists: %(username)s"
+msgstr "Sąrašai: %(username)s"
+
+#: bookwyrm/templates/user/lists.html:17 bookwyrm/templates/user/lists.html:29
+msgid "Create list"
+msgstr "Sukurti sąrašą"
+
+#: bookwyrm/templates/user/relationships/followers.html:12
+#, python-format
+msgid "%(username)s has no followers"
+msgstr "%(username)s neturi sekėjų"
+
+#: bookwyrm/templates/user/relationships/following.html:6
+#: bookwyrm/templates/user/relationships/layout.html:15
+msgid "Following"
+msgstr "Sekama"
+
+#: bookwyrm/templates/user/relationships/following.html:12
+#, python-format
+msgid "%(username)s isn't following any users"
+msgstr "%(username)s nieko neseka"
+
+#: bookwyrm/templates/user/user.html:16
+msgid "Edit profile"
+msgstr "Redaguoti paskyrą"
+
+#: bookwyrm/templates/user/user.html:33
+#, python-format
+msgid "View all %(size)s"
+msgstr "Žiūrėti visus %(size)s"
+
+#: bookwyrm/templates/user/user.html:46
+msgid "View all books"
+msgstr "Žiūrėti visas knygas"
+
+#: bookwyrm/templates/user/user.html:59
+msgid "User Activity"
+msgstr "Naudotojo aktyvumas"
+
+#: bookwyrm/templates/user/user.html:63
+msgid "RSS feed"
+msgstr "RSS srautas"
+
+#: bookwyrm/templates/user/user.html:74
+msgid "No activities yet!"
+msgstr "Įrašų dar nėra"
+
+#: bookwyrm/templates/user/user_preview.html:22
+#, python-format
+msgid "Joined %(date)s"
+msgstr "Joined %(date)s"
+
+#: bookwyrm/templates/user/user_preview.html:26
+#, python-format
+msgid "%(counter)s follower"
+msgid_plural "%(counter)s followers"
+msgstr[0] "%(counter)s sekėjas"
+msgstr[1] "%(counter)s sekėjai"
+msgstr[2] "%(counter)s sekėjų"
+msgstr[3] "%(counter)s sekėjai"
+
+#: bookwyrm/templates/user/user_preview.html:27
+#, python-format
+msgid "%(counter)s following"
+msgstr "%(counter)s seka"
+
+#: bookwyrm/templates/user/user_preview.html:34
+#, python-format
+msgid "%(mutuals_display)s follower you follow"
+msgid_plural "%(mutuals_display)s followers you follow"
+msgstr[0] "%(mutuals_display)s sekėjas, kurį sekate jūs"
+msgstr[1] "%(mutuals_display)s sekėjai, kuriuos sekate jūs"
+msgstr[2] "%(mutuals_display)s sekėjai, kuriuos sekate jūs"
+msgstr[3] "%(mutuals_display)s sekėjai, kuriuos sekate jūs"
+
+#: bookwyrm/templates/user/user_preview.html:38
+msgid "No followers you follow"
+msgstr "Jūs nieko nesekate"
+
+#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:28
+msgid "File exceeds maximum size: 10MB"
+msgstr "Failas viršijo maksimalų dydį: 10 MB"
+
+#: bookwyrm/templatetags/utilities.py:31
+#, python-format
+msgid "%(title)s: %(subtitle)s"
+msgstr "%(title)s: %(subtitle)s"
+
+#: bookwyrm/views/imports/import_data.py:64
+msgid "Not a valid csv file"
+msgstr "Netinkamas csv failas"
+
+#: bookwyrm/views/landing/login.py:69
+msgid "Username or password are incorrect"
+msgstr "Naudotojo vardas arba slaptažodis neteisingi"
+
+#: bookwyrm/views/landing/password.py:32
+msgid "No user with that email address was found."
+msgstr "Šiuo el. pašto adresu nerastas nei vienas narys."
+
+#: bookwyrm/views/landing/password.py:43
+#, python-brace-format
+msgid "A password reset link was sent to {email}"
+msgstr "Slaptažodžio atstatymo nuoroda išsiųsta į {email}"
+
+#: bookwyrm/views/rss_feed.py:35
+#, python-brace-format
+msgid "Status updates from {obj.display_name}"
+msgstr "Būsenos atnaujinimai iš {obj.display_name}"
+
diff --git a/locale/pt_BR/LC_MESSAGES/django.mo b/locale/pt_BR/LC_MESSAGES/django.mo
index 1ebe5280..dd430b3a 100644
Binary files a/locale/pt_BR/LC_MESSAGES/django.mo and b/locale/pt_BR/LC_MESSAGES/django.mo differ
diff --git a/locale/pt_BR/LC_MESSAGES/django.po b/locale/pt_BR/LC_MESSAGES/django.po
index 2e729a2f..a7ea1a86 100644
--- a/locale/pt_BR/LC_MESSAGES/django.po
+++ b/locale/pt_BR/LC_MESSAGES/django.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: bookwyrm\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-10-15 22:03+0000\n"
-"PO-Revision-Date: 2021-10-22 13:31\n"
+"POT-Creation-Date: 2021-11-14 15:08+0000\n"
+"PO-Revision-Date: 2021-11-16 00:36\n"
"Last-Translator: Mouse Reeve