diff --git a/FEDERATION.md b/FEDERATION.md index dd0c917e2..d80e98bd3 100644 --- a/FEDERATION.md +++ b/FEDERATION.md @@ -13,14 +13,15 @@ User relationship interactions follow the standard ActivityPub spec. - `Block`: prevent users from seeing one another's statuses, and prevents the blocked user from viewing the actor's profile - `Update`: updates a user's profile and settings - `Delete`: deactivates a user -- `Undo`: reverses a `Follow` or `Block` +- `Undo`: reverses a `Block` or `Follow` ### Activities - `Create/Status`: saves a new status in the database. - `Delete/Status`: Removes a status - `Like/Status`: Creates a favorite on the status - `Announce/Status`: Boosts the status into the actor's timeline -- `Undo/*`,: Reverses a `Like` or `Announce` +- `Undo/*`,: Reverses an `Announce`, `Like`, or `Move` +- `Move/User`: Moves a user from one ActivityPub id to another. ### Collections User's books and lists are represented by [`OrderedCollection`](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection) diff --git a/VERSION b/VERSION new file mode 100644 index 000000000..faef31a43 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.7.0 diff --git a/bookwyrm/activitypub/__init__.py b/bookwyrm/activitypub/__init__.py index 2697620f0..41decd68a 100644 --- a/bookwyrm/activitypub/__init__.py +++ b/bookwyrm/activitypub/__init__.py @@ -23,6 +23,7 @@ from .verbs import Create, Delete, Undo, Update from .verbs import Follow, Accept, Reject, Block from .verbs import Add, Remove from .verbs import Announce, Like +from .verbs import Move # this creates a list of all the Activity types that we can serialize, # so when an Activity comes in from outside, we can check if it's known diff --git a/bookwyrm/activitypub/book.py b/bookwyrm/activitypub/book.py index 5db0dc3ac..a53222053 100644 --- a/bookwyrm/activitypub/book.py +++ b/bookwyrm/activitypub/book.py @@ -22,8 +22,6 @@ class BookData(ActivityObject): aasin: Optional[str] = None isfdb: Optional[str] = None lastEditedBy: Optional[str] = None - links: list[str] = field(default_factory=list) - fileLinks: list[str] = field(default_factory=list) # pylint: disable=invalid-name @@ -45,6 +43,8 @@ class Book(BookData): firstPublishedDate: str = "" publishedDate: str = "" + fileLinks: list[str] = field(default_factory=list) + cover: Optional[Document] = None type: str = "Book" diff --git a/bookwyrm/activitypub/person.py b/bookwyrm/activitypub/person.py index 61c15a579..85cf44409 100644 --- a/bookwyrm/activitypub/person.py +++ b/bookwyrm/activitypub/person.py @@ -40,4 +40,6 @@ class Person(ActivityObject): manuallyApprovesFollowers: str = False discoverable: str = False hideFollows: str = False + movedTo: str = None + alsoKnownAs: dict[str] = None type: str = "Person" diff --git a/bookwyrm/activitypub/verbs.py b/bookwyrm/activitypub/verbs.py index 4b7514b5a..00c9524fe 100644 --- a/bookwyrm/activitypub/verbs.py +++ b/bookwyrm/activitypub/verbs.py @@ -231,3 +231,30 @@ class Announce(Verb): def action(self, allow_external_connections=True): """boost""" self.to_model(allow_external_connections=allow_external_connections) + + +@dataclass(init=False) +class Move(Verb): + """a user moving an object""" + + object: str + type: str = "Move" + origin: str = None + target: str = None + + def action(self, allow_external_connections=True): + """move""" + + object_is_user = resolve_remote_id(remote_id=self.object, model="User") + + if object_is_user: + model = apps.get_model("bookwyrm.MoveUser") + + self.to_model( + model=model, + save=True, + allow_external_connections=allow_external_connections, + ) + else: + # we might do something with this to move other objects at some point + pass diff --git a/bookwyrm/forms/edit_user.py b/bookwyrm/forms/edit_user.py index ce7bb6d07..9024972c3 100644 --- a/bookwyrm/forms/edit_user.py +++ b/bookwyrm/forms/edit_user.py @@ -70,6 +70,22 @@ class DeleteUserForm(CustomForm): fields = ["password"] +class MoveUserForm(CustomForm): + target = forms.CharField(widget=forms.TextInput) + + class Meta: + model = models.User + fields = ["password"] + + +class AliasUserForm(CustomForm): + username = forms.CharField(widget=forms.TextInput) + + class Meta: + model = models.User + fields = ["password"] + + class ChangePasswordForm(CustomForm): current_password = forms.CharField(widget=forms.PasswordInput) confirm_password = forms.CharField(widget=forms.PasswordInput) diff --git a/bookwyrm/isbn/isbn.py b/bookwyrm/isbn/isbn.py index 4cc7f47dd..56062ff7b 100644 --- a/bookwyrm/isbn/isbn.py +++ b/bookwyrm/isbn/isbn.py @@ -40,7 +40,12 @@ class IsbnHyphenator: self.__element_tree = ElementTree.parse(self.__range_file_path) gs1_prefix = isbn_13[:3] - reg_group = self.__find_reg_group(isbn_13, gs1_prefix) + try: + reg_group = self.__find_reg_group(isbn_13, gs1_prefix) + except ValueError: + # if the reg groups are invalid, just return the original isbn + return isbn_13 + if reg_group is None: return isbn_13 # failed to hyphenate diff --git a/bookwyrm/migrations/0179_populate_sort_title.py b/bookwyrm/migrations/0179_populate_sort_title.py index e238bca1d..a149a68a7 100644 --- a/bookwyrm/migrations/0179_populate_sort_title.py +++ b/bookwyrm/migrations/0179_populate_sort_title.py @@ -45,5 +45,7 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(populate_sort_title), + migrations.RunPython( + populate_sort_title, reverse_code=migrations.RunPython.noop + ), ] diff --git a/bookwyrm/migrations/0182_auto_20231027_1122.py b/bookwyrm/migrations/0182_auto_20231027_1122.py new file mode 100644 index 000000000..ab57907a9 --- /dev/null +++ b/bookwyrm/migrations/0182_auto_20231027_1122.py @@ -0,0 +1,130 @@ +# Generated by Django 3.2.20 on 2023-10-27 11:22 + +import bookwyrm.models.activitypub_mixin +import bookwyrm.models.fields +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0181_merge_20230806_2302"), + ] + + operations = [ + migrations.AddField( + model_name="user", + name="also_known_as", + field=bookwyrm.models.fields.ManyToManyField(to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="user", + name="moved_to", + field=bookwyrm.models.fields.RemoteIdField( + max_length=255, + null=True, + validators=[bookwyrm.models.fields.validate_remote_id], + ), + ), + migrations.AlterField( + model_name="notification", + name="notification_type", + field=models.CharField( + choices=[ + ("FAVORITE", "Favorite"), + ("REPLY", "Reply"), + ("MENTION", "Mention"), + ("TAG", "Tag"), + ("FOLLOW", "Follow"), + ("FOLLOW_REQUEST", "Follow Request"), + ("BOOST", "Boost"), + ("IMPORT", "Import"), + ("ADD", "Add"), + ("REPORT", "Report"), + ("LINK_DOMAIN", "Link Domain"), + ("INVITE", "Invite"), + ("ACCEPT", "Accept"), + ("JOIN", "Join"), + ("LEAVE", "Leave"), + ("REMOVE", "Remove"), + ("GROUP_PRIVACY", "Group Privacy"), + ("GROUP_NAME", "Group Name"), + ("GROUP_DESCRIPTION", "Group Description"), + ("MOVE", "Move"), + ], + max_length=255, + ), + ), + migrations.CreateModel( + name="Move", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created_date", models.DateTimeField(auto_now_add=True)), + ("updated_date", models.DateTimeField(auto_now=True)), + ( + "remote_id", + bookwyrm.models.fields.RemoteIdField( + max_length=255, + null=True, + validators=[bookwyrm.models.fields.validate_remote_id], + ), + ), + ("object", bookwyrm.models.fields.CharField(max_length=255)), + ( + "origin", + bookwyrm.models.fields.CharField( + blank=True, default="", max_length=255, null=True + ), + ), + ( + "user", + bookwyrm.models.fields.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "abstract": False, + }, + bases=(bookwyrm.models.activitypub_mixin.ActivityMixin, models.Model), + ), + migrations.CreateModel( + name="MoveUser", + fields=[ + ( + "move_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="bookwyrm.move", + ), + ), + ( + "target", + bookwyrm.models.fields.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="move_target", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "abstract": False, + }, + bases=("bookwyrm.move",), + ), + ] diff --git a/bookwyrm/migrations/0183_auto_20231105_1607.py b/bookwyrm/migrations/0183_auto_20231105_1607.py new file mode 100644 index 000000000..0c8376adc --- /dev/null +++ b/bookwyrm/migrations/0183_auto_20231105_1607.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.20 on 2023-11-05 16:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0182_auto_20231027_1122"), + ] + + operations = [ + migrations.AddField( + model_name="user", + name="is_deleted", + field=models.BooleanField(default=False), + ), + ] diff --git a/bookwyrm/migrations/0184_auto_20231106_0421.py b/bookwyrm/migrations/0184_auto_20231106_0421.py new file mode 100644 index 000000000..e8197dea1 --- /dev/null +++ b/bookwyrm/migrations/0184_auto_20231106_0421.py @@ -0,0 +1,49 @@ +# Generated by Django 3.2.20 on 2023-11-06 04:21 + +from django.db import migrations +from bookwyrm.models import User + + +def update_deleted_users(apps, schema_editor): + """Find all the users who are deleted, not just inactive, and set deleted""" + users = apps.get_model("bookwyrm", "User") + db_alias = schema_editor.connection.alias + users.objects.using(db_alias).filter( + is_active=False, + deactivation_reason__in=[ + "self_deletion", + "moderator_deletion", + ], + ).update(is_deleted=True) + + # differente rules for remote users + users.objects.using(db_alias).filter(is_active=False, local=False,).exclude( + deactivation_reason="moderator_deactivation", + ).update(is_deleted=True) + + +def erase_deleted_user_data(apps, schema_editor): + """Retroactively clear user data""" + for user in User.objects.filter(is_deleted=True): + user.erase_user_data() + user.save( + broadcast=False, + update_fields=["email", "avatar", "preview_image", "summary", "name"], + ) + user.erase_user_statuses(broadcast=False) + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0183_auto_20231105_1607"), + ] + + operations = [ + migrations.RunPython( + update_deleted_users, reverse_code=migrations.RunPython.noop + ), + migrations.RunPython( + erase_deleted_user_data, reverse_code=migrations.RunPython.noop + ), + ] diff --git a/bookwyrm/models/__init__.py b/bookwyrm/models/__init__.py index 7b779190b..c455c751f 100644 --- a/bookwyrm/models/__init__.py +++ b/bookwyrm/models/__init__.py @@ -27,6 +27,8 @@ from .group import Group, GroupMember, GroupMemberInvitation from .import_job import ImportJob, ImportItem +from .move import MoveUser + from .site import SiteSettings, Theme, SiteInvite from .site import PasswordReset, InviteRequest from .announcement import Announcement diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index f0a524774..6893b9da1 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -366,9 +366,9 @@ class Edition(Book): # normalize isbn format if self.isbn_10: - self.isbn_10 = re.sub(r"[^0-9X]", "", self.isbn_10) + self.isbn_10 = normalize_isbn(self.isbn_10) if self.isbn_13: - self.isbn_13 = re.sub(r"[^0-9X]", "", self.isbn_13) + self.isbn_13 = normalize_isbn(self.isbn_13) # set rank self.edition_rank = self.get_rank() @@ -463,6 +463,11 @@ def isbn_13_to_10(isbn_13): return converted + str(checkdigit) +def normalize_isbn(isbn): + """Remove unexpected characters from ISBN 10 or 13""" + return re.sub(r"[^0-9X]", "", isbn) + + # pylint: disable=unused-argument @receiver(models.signals.post_save, sender=Edition) def preview_image(instance, *args, **kwargs): diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 85ee654e3..d51a9efe6 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -488,10 +488,12 @@ class ImageField(ActivitypubFieldMixin, models.ImageField): image_slug = value # when it's an inline image (User avatar/icon, Book cover), it's a json # blob, but when it's an attached image, it's just a url - if hasattr(image_slug, "url"): - url = image_slug.url - elif isinstance(image_slug, str): + if isinstance(image_slug, str): url = image_slug + elif isinstance(image_slug, dict): + url = image_slug.get("url") + elif hasattr(image_slug, "url"): # Serialized to Image/Document object? + url = image_slug.url else: return None diff --git a/bookwyrm/models/move.py b/bookwyrm/models/move.py new file mode 100644 index 000000000..a5bf9d76d --- /dev/null +++ b/bookwyrm/models/move.py @@ -0,0 +1,72 @@ +""" move an object including migrating a user account """ +from django.core.exceptions import PermissionDenied +from django.db import models + +from bookwyrm import activitypub +from .activitypub_mixin import ActivityMixin +from .base_model import BookWyrmModel +from . import fields +from .notification import Notification + + +class Move(ActivityMixin, BookWyrmModel): + """migrating an activitypub user account""" + + user = fields.ForeignKey( + "User", on_delete=models.PROTECT, activitypub_field="actor" + ) + + object = fields.CharField( + max_length=255, + blank=False, + null=False, + activitypub_field="object", + ) + + origin = fields.CharField( + max_length=255, + blank=True, + null=True, + default="", + activitypub_field="origin", + ) + + activity_serializer = activitypub.Move + + +class MoveUser(Move): + """migrating an activitypub user account""" + + target = fields.ForeignKey( + "User", + on_delete=models.PROTECT, + related_name="move_target", + activitypub_field="target", + ) + + def save(self, *args, **kwargs): + """update user info and broadcast it""" + + # only allow if the source is listed in the target's alsoKnownAs + if self.user in self.target.also_known_as.all(): + + self.user.also_known_as.add(self.target.id) + self.user.update_active_date() + self.user.moved_to = self.target.remote_id + self.user.save(update_fields=["moved_to"]) + + if self.user.local: + kwargs[ + "broadcast" + ] = True # Only broadcast if we are initiating the Move + + super().save(*args, **kwargs) + + for follower in self.user.followers.all(): + if follower.local: + Notification.notify( + follower, self.user, notification_type=Notification.MOVE + ) + + else: + raise PermissionDenied() diff --git a/bookwyrm/models/notification.py b/bookwyrm/models/notification.py index 522038f9a..093c25c65 100644 --- a/bookwyrm/models/notification.py +++ b/bookwyrm/models/notification.py @@ -40,11 +40,14 @@ class Notification(BookWyrmModel): GROUP_NAME = "GROUP_NAME" GROUP_DESCRIPTION = "GROUP_DESCRIPTION" + # Migrations + MOVE = "MOVE" + # pylint: disable=line-too-long NotificationType = models.TextChoices( # there has got be a better way to do this "NotificationType", - f"{FAVORITE} {REPLY} {MENTION} {TAG} {FOLLOW} {FOLLOW_REQUEST} {BOOST} {IMPORT} {ADD} {REPORT} {LINK_DOMAIN} {INVITE} {ACCEPT} {JOIN} {LEAVE} {REMOVE} {GROUP_PRIVACY} {GROUP_NAME} {GROUP_DESCRIPTION}", + f"{FAVORITE} {REPLY} {MENTION} {TAG} {FOLLOW} {FOLLOW_REQUEST} {BOOST} {IMPORT} {ADD} {REPORT} {LINK_DOMAIN} {INVITE} {ACCEPT} {JOIN} {LEAVE} {REMOVE} {GROUP_PRIVACY} {GROUP_NAME} {GROUP_DESCRIPTION} {MOVE}", ) user = models.ForeignKey("User", on_delete=models.CASCADE) diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 11646431b..cc44fe2bf 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -102,7 +102,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): if hasattr(self, "quotation"): self.quotation = None # pylint: disable=attribute-defined-outside-init self.deleted_date = timezone.now() - self.save() + self.save(*args, **kwargs) @property def recipients(self): diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 6e0912aec..75ca1d527 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -1,13 +1,14 @@ """ database schema for user data """ import re from urllib.parse import urlparse +from uuid import uuid4 from django.apps import apps from django.contrib.auth.models import AbstractUser from django.contrib.postgres.fields import ArrayField, CICharField from django.core.exceptions import PermissionDenied, ObjectDoesNotExist from django.dispatch import receiver -from django.db import models, transaction +from django.db import models, transaction, IntegrityError from django.utils import timezone from django.utils.translation import gettext_lazy as _ from model_utils import FieldTracker @@ -53,6 +54,7 @@ class User(OrderedCollectionPageMixin, AbstractUser): username = fields.UsernameField() email = models.EmailField(unique=True, null=True) + is_deleted = models.BooleanField(default=False) key_pair = fields.OneToOneField( "KeyPair", @@ -140,6 +142,19 @@ class User(OrderedCollectionPageMixin, AbstractUser): theme = models.ForeignKey("Theme", null=True, blank=True, on_delete=models.SET_NULL) hide_follows = fields.BooleanField(default=False) + # migration fields + + moved_to = fields.RemoteIdField( + null=True, unique=False, activitypub_field="movedTo", deduplication_field=False + ) + also_known_as = fields.ManyToManyField( + "self", + symmetrical=False, + unique=False, + activitypub_field="alsoKnownAs", + deduplication_field=False, + ) + # options to turn features on and off show_goal = models.BooleanField(default=True) show_suggested_users = models.BooleanField(default=True) @@ -314,6 +329,8 @@ class User(OrderedCollectionPageMixin, AbstractUser): "schema": "http://schema.org#", "PropertyValue": "schema:PropertyValue", "value": "schema:value", + "alsoKnownAs": {"@id": "as:alsoKnownAs", "@type": "@id"}, + "movedTo": {"@id": "as:movedTo", "@type": "@id"}, }, ] return activity_object @@ -379,9 +396,44 @@ class User(OrderedCollectionPageMixin, AbstractUser): """We don't actually delete the database entry""" # pylint: disable=attribute-defined-outside-init self.is_active = False - self.avatar = "" + self.allow_reactivation = False + self.is_deleted = True + + self.erase_user_data() + self.erase_user_statuses() + # skip the logic in this class's save() - super().save(*args, **kwargs) + super().save( + *args, + **kwargs, + ) + + def erase_user_data(self): + """Wipe a user's custom data""" + if not self.is_deleted: + raise IntegrityError( + "Trying to erase user data on user that is not deleted" + ) + + # mangle email address + self.email = f"{uuid4()}@deleted.user" + + # erase data fields + self.avatar = "" + self.preview_image = "" + self.summary = None + self.name = None + self.favorites.set([]) + + def erase_user_statuses(self, broadcast=True): + """Wipe the data on all the user's statuses""" + if not self.is_deleted: + raise IntegrityError( + "Trying to erase user data on user that is not deleted" + ) + + for status in self.status_set.all(): + status.delete(broadcast=broadcast) def deactivate(self): """Disable the user but allow them to reactivate""" diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 94ec761db..4cecc4df6 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -4,6 +4,7 @@ from typing import AnyStr from environs import Env + import requests from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ImproperlyConfigured @@ -14,7 +15,13 @@ from django.core.exceptions import ImproperlyConfigured env = Env() env.read_env() DOMAIN = env("DOMAIN") -VERSION = "0.6.6" + +with open("VERSION", encoding="utf-8") as f: + version = f.read() + version = version.replace("\n", "") +f.close() + +VERSION = version RELEASE_API = env( "RELEASE_API", @@ -359,9 +366,9 @@ if USE_S3: AWS_ACCESS_KEY_ID = env("AWS_ACCESS_KEY_ID") AWS_SECRET_ACCESS_KEY = env("AWS_SECRET_ACCESS_KEY") AWS_STORAGE_BUCKET_NAME = env("AWS_STORAGE_BUCKET_NAME") - AWS_S3_CUSTOM_DOMAIN = env("AWS_S3_CUSTOM_DOMAIN") + AWS_S3_CUSTOM_DOMAIN = env("AWS_S3_CUSTOM_DOMAIN", None) AWS_S3_REGION_NAME = env("AWS_S3_REGION_NAME", "") - AWS_S3_ENDPOINT_URL = env("AWS_S3_ENDPOINT_URL") + AWS_S3_ENDPOINT_URL = env("AWS_S3_ENDPOINT_URL", None) AWS_DEFAULT_ACL = "public-read" AWS_S3_OBJECT_PARAMETERS = {"CacheControl": "max-age=86400"} # S3 Static settings diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 9083f9bdc..8e76fb014 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -44,16 +44,18 @@ {% endif %} {% if book.series %} - - - + + {% if book.authors.exists %} - + {% endif %} + {% endif %}

{% endif %} @@ -186,8 +188,6 @@ itemtype="https://schema.org/AggregateRating" > - {# @todo Is it possible to not hard-code the value? #} - diff --git a/bookwyrm/templates/book/cover_add_modal.html b/bookwyrm/templates/book/cover_add_modal.html index 8ca5bf2a8..89d870cd0 100644 --- a/bookwyrm/templates/book/cover_add_modal.html +++ b/bookwyrm/templates/book/cover_add_modal.html @@ -20,7 +20,7 @@
diff --git a/bookwyrm/templates/book/edit/edit_book_form.html b/bookwyrm/templates/book/edit/edit_book_form.html index 4cc3965e7..30fb00049 100644 --- a/bookwyrm/templates/book/edit/edit_book_form.html +++ b/bookwyrm/templates/book/edit/edit_book_form.html @@ -247,7 +247,7 @@
diff --git a/bookwyrm/templates/book/rating.html b/bookwyrm/templates/book/rating.html index c0af67fab..9998a49dc 100644 --- a/bookwyrm/templates/book/rating.html +++ b/bookwyrm/templates/book/rating.html @@ -5,13 +5,18 @@ {% include 'snippets/avatar.html' with user=user %} -
-
- {{ user.display_name }} +
+ -
+
+

{% trans "rated it" %}

- {% include 'snippets/stars.html' with rating=rating.rating %}
diff --git a/bookwyrm/templates/book/series.html b/bookwyrm/templates/book/series.html index dc8113813..8b945452f 100644 --- a/bookwyrm/templates/book/series.html +++ b/bookwyrm/templates/book/series.html @@ -5,15 +5,15 @@ {% block title %}{{ series_name }}{% endblock %} {% block content %} -
-

{{ series_name }}

+
+

{{ series_name }}

{% trans "Series by" %} @@ -22,6 +22,7 @@
{% for book in books %} {% with book=book %} + {# @todo Set `hasPart` property in some meaningful way #}
{% if book.series_number %}{% blocktrans with series_number=book.series_number %}Book {{ series_number }}{% endblocktrans %}{% else %}{% trans 'Unsorted Book' %}{% endif %} diff --git a/bookwyrm/templates/guided_tour/home.html b/bookwyrm/templates/guided_tour/home.html index be8d095af..a464206ef 100644 --- a/bookwyrm/templates/guided_tour/home.html +++ b/bookwyrm/templates/guided_tour/home.html @@ -99,7 +99,7 @@ homeTour.addSteps([ ], }, { - text: "{% trans 'Use the Feed, Lists and Discover links to discover the latest news from your feed, lists of books by topic, and the latest happenings on this Bookwyrm server!' %}", + text: "{% trans 'Use the Lists, Discover, and Your Books links to discover reading suggestions and the latest happenings on this server, or to see your catalogued books!' %}", title: "{% trans 'Navigation Bar' %}", attachTo: { element: checkResponsiveState('#tour-navbar-start'), @@ -197,7 +197,7 @@ homeTour.addSteps([ ], }, { - text: `{% trans "Your profile, books, direct messages, and settings can be accessed by clicking on your name in the menu here." %}

{% trans "Try selecting Profile from the drop down menu to continue the tour." %}

`, + text: `{% trans "Your profile, user directory, direct messages, and settings can be accessed by clicking on your name in the menu here." %}

{% trans "Try selecting Profile from the drop down menu to continue the tour." %}

`, title: "{% trans 'Profile and settings menu' %}", attachTo: { element: checkResponsiveState('#navbar-dropdown'), diff --git a/bookwyrm/templates/import/import.html b/bookwyrm/templates/import/import.html index ad857fb2e..2c3be9e07 100644 --- a/bookwyrm/templates/import/import.html +++ b/bookwyrm/templates/import/import.html @@ -21,7 +21,7 @@ {% blocktrans trimmed count days=import_limit_reset with display_size=import_size_limit|intcomma %} Currently, you are allowed to import {{ display_size }} books every {{ import_limit_reset }} day. {% plural %} - Currently, you are allowed to import {{ import_size_limit }} books every {{ import_limit_reset }} days. + Currently, you are allowed to import {{ display_size }} books every {{ import_limit_reset }} days. {% endblocktrans %}

{% blocktrans with display_left=allowed_imports|intcomma %}You have {{ display_left }} left.{% endblocktrans %}

diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index b8459856c..6283e61c4 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -27,6 +27,7 @@ @@ -173,11 +180,15 @@
- {# almost every view needs to know the user shelves #} - {% with request.user.shelf_set.all as user_shelves %} - {% block content %} - {% endblock %} - {% endwith %} + {% if request.user.moved_to %} + {% include "moved.html" %} + {% else %} + {# almost every view needs to know the user shelves #} + {% with request.user.shelf_set.all as user_shelves %} + {% block content %} + {% endblock %} + {% endwith %} + {% endif %}
diff --git a/bookwyrm/templates/moved.html b/bookwyrm/templates/moved.html new file mode 100644 index 000000000..545fc3d87 --- /dev/null +++ b/bookwyrm/templates/moved.html @@ -0,0 +1,52 @@ +{% load i18n %} +{% load static %} +{% load utilities %} + +
+
+
+
+
+
+ {{ request.user.alt_text }} +
+
+
+

{{ request.user.display_name }}

+

{{request.user.username}}

+
+
+ +
+

+ {% id_to_username request.user.moved_to as username %} + {% blocktrans trimmed with moved_to=user.moved_to %} + You have moved your account to {{ username }} + {% endblocktrans %} +

+

+ {% trans "You can undo the move to restore full functionality, but some followers may have already unfollowed this account." %} +

+
+
+
+
+
+ + {% csrf_token %} + + + +
+ {% csrf_token %} + +
+
+
+
+
+
diff --git a/bookwyrm/templates/notifications/item.html b/bookwyrm/templates/notifications/item.html index b53abe3d1..7e7f0da27 100644 --- a/bookwyrm/templates/notifications/item.html +++ b/bookwyrm/templates/notifications/item.html @@ -10,7 +10,9 @@ {% elif notification.notification_type == 'FOLLOW' %} {% include 'notifications/items/follow.html' %} {% elif notification.notification_type == 'FOLLOW_REQUEST' %} - {% include 'notifications/items/follow_request.html' %} + {% if notification.related_users.0.is_active %} + {% include 'notifications/items/follow_request.html' %} + {% endif %} {% elif notification.notification_type == 'IMPORT' %} {% include 'notifications/items/import.html' %} {% elif notification.notification_type == 'ADD' %} @@ -35,4 +37,6 @@ {% include 'notifications/items/update.html' %} {% elif notification.notification_type == 'GROUP_DESCRIPTION' %} {% include 'notifications/items/update.html' %} +{% elif notification.notification_type == 'MOVE' %} + {% include 'notifications/items/move_user.html' %} {% endif %} diff --git a/bookwyrm/templates/notifications/items/layout.html b/bookwyrm/templates/notifications/items/layout.html index 8acbb9fec..41353abcf 100644 --- a/bookwyrm/templates/notifications/items/layout.html +++ b/bookwyrm/templates/notifications/items/layout.html @@ -39,6 +39,8 @@ {% with related_user=related_users.0.display_name %} {% with related_user_link=related_users.0.local_path %} + {% with related_user_moved_to=related_users.0.moved_to %} + {% with related_user_username=related_users.0.username %} {% with second_user=related_users.1.display_name %} {% with second_user_link=related_users.1.local_path %} {% with other_user_count=related_user_count|add:"-1" %} @@ -50,6 +52,8 @@ {% endwith %} {% endwith %} {% endwith %} + {% endwith %} + {% endwith %}
{% if related_status %} diff --git a/bookwyrm/templates/notifications/items/move_user.html b/bookwyrm/templates/notifications/items/move_user.html new file mode 100644 index 000000000..b94d96dc4 --- /dev/null +++ b/bookwyrm/templates/notifications/items/move_user.html @@ -0,0 +1,29 @@ +{% extends 'notifications/items/layout.html' %} + +{% load i18n %} +{% load utilities %} +{% load user_page_tags %} + +{% block primary_link %}{% spaceless %} + {{ notification.related_object.local_path }} +{% endspaceless %}{% endblock %} + +{% block icon %} + +{% endblock %} + +{% block description %} + {% if related_user_moved_to %} + {% id_to_username request.user.moved_to as username %} + {% blocktrans trimmed %} + {{ related_user }} has moved to {{ username }} + {% endblocktrans %} +
+ {% include 'snippets/move_user_buttons.html' with group=notification.related_group %} +
+ {% else %} + {% blocktrans trimmed %} + {{ related_user }} has undone their move + {% endblocktrans %} + {% endif %} +{% endblock %} diff --git a/bookwyrm/templates/preferences/alias_user.html b/bookwyrm/templates/preferences/alias_user.html new file mode 100644 index 000000000..e1e468208 --- /dev/null +++ b/bookwyrm/templates/preferences/alias_user.html @@ -0,0 +1,59 @@ +{% extends 'preferences/layout.html' %} +{% load i18n %} + +{% block title %}{% trans "Move Account" %}{% endblock %} + +{% block header %} +{% trans "Create Alias" %} +{% endblock %} + +{% block panel %} +
+

{% trans "Add another account as an alias" %}

+
+
+

+ {% trans "Marking another account as an alias is required if you want to move that account to this one." %} +

+

+ {% trans "This is a reversable action and will not change the functionality of this account." %} +

+
+
+ {% csrf_token %} +
+ + + {% include 'snippets/form_errors.html' with errors_list=form.username.errors id="desc_username" %} +
+
+ + + {% include 'snippets/form_errors.html' with errors_list=form.password.errors id="desc_password" %} +
+ +
+
+ {% if user.also_known_as.all.0 %} +
+

{% trans "Aliases" %}

+
+ + {% for alias in user.also_known_as.all %} + + + + + {% endfor %} +
{{ alias.username }} +
+ {% csrf_token %} + + +
+
+
+
+ {% endif %} +
+{% endblock %} diff --git a/bookwyrm/templates/preferences/layout.html b/bookwyrm/templates/preferences/layout.html index ca63ec93d..fb0b6fba6 100644 --- a/bookwyrm/templates/preferences/layout.html +++ b/bookwyrm/templates/preferences/layout.html @@ -23,6 +23,14 @@ {% url 'prefs-2fa' as url %} {% trans "Two Factor Authentication" %} +
  • + {% url 'prefs-alias' as url %} + {% trans "Aliases" %} +
  • +
  • + {% url 'prefs-move' as url %} + {% trans "Move Account" %} +
  • {% url 'prefs-delete' as url %} {% trans "Delete Account" %} diff --git a/bookwyrm/templates/preferences/move_user.html b/bookwyrm/templates/preferences/move_user.html new file mode 100644 index 000000000..47b370e82 --- /dev/null +++ b/bookwyrm/templates/preferences/move_user.html @@ -0,0 +1,43 @@ +{% extends 'preferences/layout.html' %} +{% load i18n %} + +{% block title %}{% trans "Move Account" %}{% endblock %} + +{% block header %} +{% trans "Move Account" %} +{% endblock %} + +{% block panel %} +
    +

    {% trans "Migrate account to another server" %}

    +
    +
    +

    + {% trans "Moving your account will notify all your followers and direct them to follow the new account." %} +

    +

    + {% blocktrans %} + {{ user }} will be marked as moved and will not be discoverable or usable unless you undo the move. + {% endblocktrans %} +

    +
    +
    +

    {% trans "Remember to add this user as an alias of the target account before you try to move." %}

    +
    +
    + {% csrf_token %} +
    + + + {% include 'snippets/form_errors.html' with errors_list=form.target.errors id="desc_target" %} +
    +
    + + + {% include 'snippets/form_errors.html' with errors_list=form.password.errors id="desc_password" %} +
    + +
    +
    +
    +{% endblock %} diff --git a/bookwyrm/templates/settings/celery.html b/bookwyrm/templates/settings/celery.html index 2f4a36ce9..b224e20cc 100644 --- a/bookwyrm/templates/settings/celery.html +++ b/bookwyrm/templates/settings/celery.html @@ -29,7 +29,7 @@
  • -

    {% trans "Broadcasts" %}

    +

    {% trans "Broadcast" %}

    {{ queues.broadcast|intcomma }}

    diff --git a/bookwyrm/templates/settings/users/user_admin.html b/bookwyrm/templates/settings/users/user_admin.html index 9bc5805b1..cc5c51ba7 100644 --- a/bookwyrm/templates/settings/users/user_admin.html +++ b/bookwyrm/templates/settings/users/user_admin.html @@ -74,24 +74,7 @@ {{ user.created_date }} {{ user.last_active_date }} - {% if user.is_active %} - - {% trans "Active" %} - {% elif user.deactivation_reason == "moderator_deletion" or user.deactivation_reason == "self_deletion" %} - - {% trans "Deleted" %} - ({{ user.get_deactivation_reason_display }}) - {% else %} - - {% trans "Inactive" %} - ({{ user.get_deactivation_reason_display }}) - {% endif %} + {% include "snippets/user_active_tag.html" with user=user %} {% if status == "federated" %} diff --git a/bookwyrm/templates/settings/users/user_info.html b/bookwyrm/templates/settings/users/user_info.html index a1725ae36..f35c60db9 100644 --- a/bookwyrm/templates/settings/users/user_info.html +++ b/bookwyrm/templates/settings/users/user_info.html @@ -23,18 +23,7 @@

    {% trans "Status" %}

    - {% if user.is_active %} -

    - {% trans "Active" %} -

    - {% else %} -

    - {% trans "Inactive" %} - {% if user.deactivation_reason %} - ({% trans user.get_deactivation_reason_display %}) - {% endif %} -

    - {% endif %} + {% include "snippets/user_active_tag.html" with large=True %}

    {% if user.local %} {% trans "Local" %} diff --git a/bookwyrm/templates/shelf/shelf.html b/bookwyrm/templates/shelf/shelf.html index 7d0035ed3..a2410ef95 100644 --- a/bookwyrm/templates/shelf/shelf.html +++ b/bookwyrm/templates/shelf/shelf.html @@ -18,7 +18,22 @@ {% include 'user/books_header.html' %} - +{% if user.moved_to %} +

    +
    +

    + {% trans "You have have moved to" %} + {% id_to_username user.moved_to %} +

    +

    {% trans "You can undo this move to restore full functionality, but some followers may have already unfollowed this account." %}

    +
    + {% csrf_token %} + + +
    +
    +
    +{% else %}
    {% endwith %} diff --git a/bookwyrm/templates/snippets/status/headers/rating.html b/bookwyrm/templates/snippets/status/headers/rating.html index bc40c04c8..fcef7eee7 100644 --- a/bookwyrm/templates/snippets/status/headers/rating.html +++ b/bookwyrm/templates/snippets/status/headers/rating.html @@ -16,9 +16,6 @@ > diff --git a/bookwyrm/templates/snippets/user_active_tag.html b/bookwyrm/templates/snippets/user_active_tag.html new file mode 100644 index 000000000..1d85ae68b --- /dev/null +++ b/bookwyrm/templates/snippets/user_active_tag.html @@ -0,0 +1,17 @@ +{% load i18n %} + +{% if user.is_active %} + {% if user.moved_to %} + {% trans "Moved" as text %} + {% include "snippets/user_active_tag_item.html" with icon="x" text=text level="info" %} + {% else %} + {% trans "Active" as text %} + {% include "snippets/user_active_tag_item.html" with icon="check" text=text level="success" %} + {% endif %} +{% elif user.is_deleted %} + {% trans "Deleted" as text %} + {% include "snippets/user_active_tag_item.html" with icon="x" text=text level="danger" deactivation_reason=user.get_deactivation_reason_display %} +{% else %} + {% trans "Inactive" as text %} + {% include "snippets/user_active_tag_item.html" with icon="x" text=text level="warning" deactivation_reason=user.get_deactivation_reason_display %} +{% endif %} diff --git a/bookwyrm/templates/snippets/user_active_tag_item.html b/bookwyrm/templates/snippets/user_active_tag_item.html new file mode 100644 index 000000000..e722150f2 --- /dev/null +++ b/bookwyrm/templates/snippets/user_active_tag_item.html @@ -0,0 +1,19 @@ +{% if large %} + +

    + + {{ text }} + {% if deactivation_reason %} + ({{ deactivation_reason }}) + {% endif %} +

    + +{% else %} + + +{{ text }} + +{% endif %} + diff --git a/bookwyrm/templates/user/layout.html b/bookwyrm/templates/user/layout.html index 4c7031ba5..57d25120d 100755 --- a/bookwyrm/templates/user/layout.html +++ b/bookwyrm/templates/user/layout.html @@ -5,6 +5,7 @@ {% load markdown %} {% load layout %} {% load group_tags %} +{% load user_page_tags %} {% block title %}{{ user.display_name }}{% endblock %} @@ -27,7 +28,11 @@
    - {% include 'user/user_preview.html' with user=user %} + {% if user.moved_to %} + {% include 'user/moved.html' with user=user %} + {% else %} + {% include 'user/user_preview.html' with user=user %} + {% endif %}
    {% if user.summary %} @@ -38,70 +43,83 @@ {% endspaceless %} {% endif %}
    - {% if not is_self and request.user.is_authenticated %} - {% include 'snippets/follow_button.html' with user=user %} - {% endif %} - {% if not is_self %} - {% include 'ostatus/remote_follow_button.html' with user=user %} - {% endif %} - - {% if is_self and user.active_follower_requests.all %} - -{% block tabs %} -{% with user|username as username %} - -{% endwith %} -{% endblock %} - -{% block panel %}{% endblock %} - + {% if not user.moved_to %} + {% block panel %}{% endblock %} + {% endif %} {% endblock %} diff --git a/bookwyrm/templates/user/moved.html b/bookwyrm/templates/user/moved.html new file mode 100644 index 000000000..45a4bb2e5 --- /dev/null +++ b/bookwyrm/templates/user/moved.html @@ -0,0 +1,27 @@ +{% load i18n %} +{% load humanize %} +{% load utilities %} +{% load markdown %} +{% load layout %} +{% load group_tags %} + + +
    + +
    +

    + {% if user.name %}{{ user.name }}{% else %}{{ user.localname }}{% endif %} + {% if user.manually_approves_followers %} + + {% trans "Locked account" %} + + {% endif %} +

    +

    {{ user.username }}

    +

    {% blocktrans with date=user.created_date|naturaltime %}Joined {{ date }}{% endblocktrans %}

    +
    +
    diff --git a/bookwyrm/templates/user_menu.html b/bookwyrm/templates/user_menu.html index 5473b9da2..ad6f4fab2 100644 --- a/bookwyrm/templates/user_menu.html +++ b/bookwyrm/templates/user_menu.html @@ -34,11 +34,6 @@ {% trans "Directory" %} -
  • - - {% trans 'Your Books' %} - -
  • {% trans "Direct Messages" %} diff --git a/bookwyrm/templatetags/utilities.py b/bookwyrm/templatetags/utilities.py index 4aaf6b8a7..42e67990f 100644 --- a/bookwyrm/templatetags/utilities.py +++ b/bookwyrm/templatetags/utilities.py @@ -2,11 +2,13 @@ import os import re from uuid import uuid4 +from urllib.parse import urlparse from django import template from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ from django.templatetags.static import static +from bookwyrm.models import User register = template.Library() @@ -29,6 +31,13 @@ def get_user_identifier(user): return user.localname if user.localname else user.username +@register.filter(name="user_from_remote_id") +def get_user_identifier_from_remote_id(remote_id): + """get the local user id from their remote id""" + user = User.objects.get(remote_id=remote_id) + return user if user else None + + @register.filter(name="book_title") def get_title(book, too_short=5): """display the subtitle if the title is short""" @@ -103,3 +112,16 @@ def get_isni(existing, author, autoescape=True): f'' ) return "" + + +@register.simple_tag(takes_context=False) +def id_to_username(user_id): + """given an arbitrary remote id, return the username""" + if user_id: + url = urlparse(user_id) + domain = url.netloc + parts = url.path.split("/") + name = parts[-1] + value = f"{name}@{domain}" + + return value diff --git a/bookwyrm/tests/migrations/test_0184.py b/bookwyrm/tests/migrations/test_0184.py new file mode 100644 index 000000000..4bf1b66c9 --- /dev/null +++ b/bookwyrm/tests/migrations/test_0184.py @@ -0,0 +1,121 @@ +""" testing migrations """ +from unittest.mock import patch + +from django.test import TestCase +from django.db.migrations.executor import MigrationExecutor +from django.db import connection + +from bookwyrm import models +from bookwyrm.management.commands import initdb +from bookwyrm.settings import DOMAIN + +# pylint: disable=missing-class-docstring +# pylint: disable=missing-function-docstring +class EraseDeletedUserDataMigration(TestCase): + + migrate_from = "0183_auto_20231105_1607" + migrate_to = "0184_auto_20231106_0421" + + # pylint: disable=invalid-name + def setUp(self): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + self.active_user = models.User.objects.create_user( + f"activeuser@{DOMAIN}", + "activeuser@activeuser.activeuser", + "activeuserword", + local=True, + localname="active", + name="a name", + ) + self.inactive_user = models.User.objects.create_user( + f"inactiveuser@{DOMAIN}", + "inactiveuser@inactiveuser.inactiveuser", + "inactiveuserword", + local=True, + localname="inactive", + is_active=False, + deactivation_reason="self_deactivation", + name="name name", + ) + self.deleted_user = models.User.objects.create_user( + f"deleteduser@{DOMAIN}", + "deleteduser@deleteduser.deleteduser", + "deleteduserword", + local=True, + localname="deleted", + is_active=False, + deactivation_reason="self_deletion", + name="cool name", + ) + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ), patch("bookwyrm.activitystreams.add_status_task.delay"): + self.active_status = models.Status.objects.create( + user=self.active_user, content="don't delete me" + ) + self.inactive_status = models.Status.objects.create( + user=self.inactive_user, content="also don't delete me" + ) + self.deleted_status = models.Status.objects.create( + user=self.deleted_user, content="yes, delete me" + ) + + initdb.init_groups() + initdb.init_permissions() + + self.migrate_from = [("bookwyrm", self.migrate_from)] + self.migrate_to = [("bookwyrm", self.migrate_to)] + executor = MigrationExecutor(connection) + old_apps = executor.loader.project_state(self.migrate_from).apps + + # Reverse to the original migration + executor.migrate(self.migrate_from) + + self.setUpBeforeMigration(old_apps) + + # Run the migration to test + executor = MigrationExecutor(connection) + executor.loader.build_graph() # reload. + with patch("bookwyrm.activitystreams.remove_status_task.delay"): + executor.migrate(self.migrate_to) + + self.apps = executor.loader.project_state(self.migrate_to).apps + + def setUpBeforeMigration(self, apps): + pass + + def test_user_data_deleted(self): + """Make sure that only the right data was deleted""" + self.active_user.refresh_from_db() + self.inactive_user.refresh_from_db() + self.deleted_user.refresh_from_db() + self.active_status.refresh_from_db() + self.inactive_status.refresh_from_db() + self.deleted_status.refresh_from_db() + + self.assertTrue(self.active_user.is_active) + self.assertFalse(self.active_user.is_deleted) + self.assertEqual(self.active_user.name, "a name") + self.assertNotEqual(self.deleted_user.email, "activeuser@activeuser.activeuser") + self.assertFalse(self.active_status.deleted) + self.assertEqual(self.active_status.content, "don't delete me") + + self.assertFalse(self.inactive_user.is_active) + self.assertFalse(self.inactive_user.is_deleted) + self.assertEqual(self.inactive_user.name, "name name") + self.assertNotEqual( + self.deleted_user.email, "inactiveuser@inactiveuser.inactiveuser" + ) + self.assertFalse(self.inactive_status.deleted) + self.assertEqual(self.inactive_status.content, "also don't delete me") + + self.assertFalse(self.deleted_user.is_active) + self.assertTrue(self.deleted_user.is_deleted) + self.assertIsNone(self.deleted_user.name) + self.assertNotEqual( + self.deleted_user.email, "deleteduser@deleteduser.deleteduser" + ) + self.assertTrue(self.deleted_status.deleted) + self.assertIsNone(self.deleted_status.content) diff --git a/bookwyrm/tests/models/test_activitypub_mixin.py b/bookwyrm/tests/models/test_activitypub_mixin.py index a465c2c12..645a6546b 100644 --- a/bookwyrm/tests/models/test_activitypub_mixin.py +++ b/bookwyrm/tests/models/test_activitypub_mixin.py @@ -119,6 +119,25 @@ class ActivitypubMixins(TestCase): result = models.Edition.find_existing({"openlibraryKey": "OL1234"}) self.assertEqual(result, book) + def test_find_existing_with_id(self, *_): + """make sure that an "id" field won't produce a match""" + book = models.Edition.objects.create(title="Test edition") + + result = models.Edition.find_existing({"id": book.id}) + self.assertIsNone(result) + + def test_find_existing_with_id_and_match(self, *_): + """make sure that an "id" field won't produce a match""" + book = models.Edition.objects.create(title="Test edition") + matching_book = models.Edition.objects.create( + title="Another test edition", openlibrary_key="OL1234" + ) + + result = models.Edition.find_existing( + {"id": book.id, "openlibraryKey": "OL1234"} + ) + self.assertEqual(result, matching_book) + def test_get_recipients_public_object(self, *_): """determines the recipients for an object's broadcast""" MockSelf = namedtuple("Self", ("privacy")) diff --git a/bookwyrm/tests/models/test_book_model.py b/bookwyrm/tests/models/test_book_model.py index 8122e9505..4347efcb6 100644 --- a/bookwyrm/tests/models/test_book_model.py +++ b/bookwyrm/tests/models/test_book_model.py @@ -11,7 +11,7 @@ from django.test import TestCase from django.utils import timezone from bookwyrm import models, settings -from bookwyrm.models.book import isbn_10_to_13, isbn_13_to_10 +from bookwyrm.models.book import isbn_10_to_13, isbn_13_to_10, normalize_isbn from bookwyrm.settings import ENABLE_THUMBNAIL_GENERATION @@ -72,6 +72,10 @@ class Book(TestCase): isbn_10 = isbn_13_to_10(isbn_13) self.assertEqual(isbn_10, "178816167X") + def test_normalize_isbn(self): + """Remove misc characters from ISBNs""" + self.assertEqual(normalize_isbn("978-0-4633461-1-2"), "9780463346112") + def test_get_edition_info(self): """text slug about an edition""" book = models.Edition.objects.create(title="Test Edition") diff --git a/bookwyrm/tests/models/test_user_model.py b/bookwyrm/tests/models/test_user_model.py index 9d6294768..30d7918c0 100644 --- a/bookwyrm/tests/models/test_user_model.py +++ b/bookwyrm/tests/models/test_user_model.py @@ -1,7 +1,9 @@ """ testing models """ import json + from unittest.mock import patch from django.contrib.auth.models import Group +from django.db import IntegrityError from django.test import TestCase import responses @@ -9,9 +11,11 @@ from bookwyrm import models from bookwyrm.management.commands import initdb from bookwyrm.settings import USE_HTTPS, DOMAIN + # pylint: disable=missing-class-docstring # pylint: disable=missing-function-docstring class User(TestCase): + protocol = "https://" if USE_HTTPS else "http://" # pylint: disable=invalid-name @@ -26,6 +30,7 @@ class User(TestCase): local=True, localname="mouse", name="hi", + summary="a summary", bookwyrm_user=False, ) self.another_user = models.User.objects.create_user( @@ -88,9 +93,11 @@ class User(TestCase): "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "schema": "http://schema.org#", "PropertyValue": "schema:PropertyValue", + "alsoKnownAs": {"@id": "as:alsoKnownAs", "@type": "@id"}, + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "movedTo": {"@id": "as:movedTo", "@type": "@id"}, + "schema": "http://schema.org#", "value": "schema:value", }, ], @@ -216,19 +223,71 @@ class User(TestCase): @patch("bookwyrm.suggested_users.remove_user_task.delay") def test_delete_user(self, _): - """deactivate a user""" + """permanently delete a user""" self.assertTrue(self.user.is_active) + self.assertEqual(self.user.name, "hi") + self.assertEqual(self.user.summary, "a summary") + self.assertEqual(self.user.email, "mouse@mouse.mouse") with patch( "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as broadcast_mock: + ) as broadcast_mock, patch( + "bookwyrm.models.user.User.erase_user_statuses" + ) as erase_statuses_mock: self.user.delete() + self.assertEqual(erase_statuses_mock.call_count, 1) + + # make sure the deletion is broadcast self.assertEqual(broadcast_mock.call_count, 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.user.refresh_from_db() + + # the user's account data should be deleted + self.assertIsNone(self.user.name) + self.assertIsNone(self.user.summary) + self.assertNotEqual(self.user.email, "mouse@mouse.mouse") self.assertFalse(self.user.is_active) + @patch("bookwyrm.suggested_users.remove_user_task.delay") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") + @patch("bookwyrm.activitystreams.add_status_task.delay") + @patch("bookwyrm.activitystreams.remove_status_task.delay") + def test_delete_user_erase_statuses(self, *_): + """erase user statuses when user is deleted""" + status = models.Status.objects.create(user=self.user, content="hello") + self.assertFalse(status.deleted) + self.assertIsNotNone(status.content) + self.assertIsNone(status.deleted_date) + + self.user.delete() + status.refresh_from_db() + + self.assertTrue(status.deleted) + self.assertIsNone(status.content) + self.assertIsNotNone(status.deleted_date) + + @patch("bookwyrm.suggested_users.remove_user_task.delay") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") + @patch("bookwyrm.activitystreams.add_status_task.delay") + def test_delete_user_erase_statuses_invalid(self, *_): + """erase user statuses when user is deleted""" + status = models.Status.objects.create(user=self.user, content="hello") + self.assertFalse(status.deleted) + self.assertIsNotNone(status.content) + self.assertIsNone(status.deleted_date) + + self.user.deactivate() + with self.assertRaises(IntegrityError): + self.user.erase_user_statuses() + + status.refresh_from_db() + self.assertFalse(status.deleted) + self.assertIsNotNone(status.content) + self.assertIsNone(status.deleted_date) + def test_admins_no_admins(self): """list of admins""" result = models.User.admins() diff --git a/bookwyrm/tests/test_isbn.py b/bookwyrm/tests/test_isbn.py index b528e9210..5486c7151 100644 --- a/bookwyrm/tests/test_isbn.py +++ b/bookwyrm/tests/test_isbn.py @@ -29,3 +29,10 @@ class TestISBN(TestCase): self.assertEqual(hyphenator.hyphenate("9786769533251"), "9786769533251") # 979-8 (United States) 2300000-3499999 (unassigned) self.assertEqual(hyphenator.hyphenate("9798311111111"), "9798311111111") + + def test_isbn_hyphenation_invalid_data(self): + """Make sure not to throw an error when a bad ISBN is found""" + # no action taken + self.assertEqual(hyphenator.hyphenate("978-0-4633461-1-2"), "978-0-4633461-1-2") + self.assertEqual(hyphenator.hyphenate("9-0-4633461-1-2"), "9-0-4633461-1-2") + self.assertEqual(hyphenator.hyphenate("90463346112"), "90463346112") diff --git a/bookwyrm/tests/views/inbox/test_inbox_delete.py b/bookwyrm/tests/views/inbox/test_inbox_delete.py index 0fb108e22..7b4c12564 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_delete.py +++ b/bookwyrm/tests/views/inbox/test_inbox_delete.py @@ -11,6 +11,7 @@ from bookwyrm import models, views class InboxActivities(TestCase): """inbox tests""" + # pylint: disable=invalid-name def setUp(self): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( @@ -97,7 +98,8 @@ class InboxActivities(TestCase): self.assertEqual(models.Notification.objects.get(), notif) @patch("bookwyrm.suggested_users.remove_user_task.delay") - def test_delete_user(self, _): + @patch("bookwyrm.activitystreams.remove_status_task.delay") + def test_delete_user(self, *_): """delete a user""" self.assertTrue(models.User.objects.get(username="rat@example.com").is_active) activity = { diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index 33bd8b53a..424698130 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -420,21 +420,25 @@ http://www.fish.com/""" 'okay\n\nwww.fish.com/', ) - def test_format_links_parens(self, *_): - """find and format urls into a tags""" - url = "http://www.fish.com/" - self.assertEqual( - views.status.format_links(f"({url})"), - f'(www.fish.com/)', - ) - def test_format_links_punctuation(self, *_): - """don’t take trailing punctuation into account pls""" - url = "http://www.fish.com/" - self.assertEqual( - views.status.format_links(f"{url}."), - f'www.fish.com/.', - ) + """test many combinations of brackets, URLs, and punctuation""" + url = "https://bookwyrm.social" + html = f'bookwyrm.social' + test_table = [ + ("punct", f"text and {url}.", f"text and {html}."), + ("multi_punct", f"text, then {url}?...", f"text, then {html}?..."), + ("bracket_punct", f"here ({url}).", f"here ({html})."), + ("punct_bracket", f"there [{url}?]", f"there [{html}?]"), + ("punct_bracket_punct", f"not here? ({url}!).", f"not here? ({html}!)."), + ( + "multi_punct_bracket", + f"not there ({url}...);", + f"not there ({html}...);", + ), + ] + for desc, text, output in test_table: + with self.subTest(desc=desc): + self.assertEqual(views.status.format_links(text), output) def test_format_links_special_chars(self, *_): """find and format urls into a tags""" @@ -464,6 +468,13 @@ http://www.fish.com/""" views.status.format_links(url), f'{url[8:]}' ) + def test_format_links_ignore_non_urls(self, *_): + """formating links should leave plain text untouced""" + text_elision = "> “The distinction is significant.” [...]" # bookwyrm#2993 + text_quoteparens = "some kind of gene-editing technology (?)" # bookwyrm#3049 + self.assertEqual(views.status.format_links(text_elision), text_elision) + self.assertEqual(views.status.format_links(text_quoteparens), text_quoteparens) + def test_format_mentions_with_at_symbol_links(self, *_): """A link with an @username shouldn't treat the username as a mention""" content = "a link to https://example.com/user/@mouse" diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 0759012fe..8541f4fb6 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -600,6 +600,12 @@ urlpatterns = [ name="prompt-2fa", ), re_path(r"^preferences/export/?$", views.Export.as_view(), name="prefs-export"), + re_path(r"^preferences/move/?$", views.MoveUser.as_view(), name="prefs-move"), + re_path(r"^preferences/alias/?$", views.AliasUser.as_view(), name="prefs-alias"), + re_path( + r"^preferences/remove-alias/?$", views.remove_alias, name="prefs-remove-alias" + ), + re_path(r"^preferences/unmove/?$", views.unmove, name="prefs-unmove"), re_path(r"^preferences/delete/?$", views.DeleteUser.as_view(), name="prefs-delete"), re_path( r"^preferences/deactivate/?$", diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index 84060acb7..2d2e97f52 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -37,6 +37,7 @@ from .admin.user_admin import UserAdmin, UserAdminList, ActivateUserAdmin from .preferences.change_password import ChangePassword from .preferences.edit_user import EditUser from .preferences.export import Export +from .preferences.move_user import MoveUser, AliasUser, remove_alias, unmove from .preferences.delete_user import DeleteUser, DeactivateUser, ReactivateUser from .preferences.block import Block, unblock from .preferences.two_factor_auth import ( diff --git a/bookwyrm/views/admin/celery_status.py b/bookwyrm/views/admin/celery_status.py index cd8b85b6d..dbf18dac8 100644 --- a/bookwyrm/views/admin/celery_status.py +++ b/bookwyrm/views/admin/celery_status.py @@ -110,20 +110,20 @@ class ClearCeleryForm(forms.Form): queues = forms.MultipleChoiceField( label="Queues", choices=[ - (LOW, "Low prioirty"), + (LOW, "Low priority"), (MEDIUM, "Medium priority"), (HIGH, "High priority"), - (STREAMS, "Streams"), - (IMAGES, "Images"), - (SUGGESTED_USERS, "Suggested users"), - (EMAIL, "Email"), + (BROADCAST, "Broadcast"), (CONNECTORS, "Connectors"), - (LISTS, "Lists"), - (INBOX, "Inbox"), + (EMAIL, "Email"), + (IMAGES, "Images"), (IMPORTS, "Imports"), (IMPORT_TRIGGERED, "Import triggered"), - (BROADCAST, "Broadcasts"), + (INBOX, "Inbox"), + (LISTS, "Lists"), (MISC, "Misc"), + (STREAMS, "Streams"), + (SUGGESTED_USERS, "Suggested users"), ], widget=forms.CheckboxSelectMultiple, ) diff --git a/bookwyrm/views/preferences/move_user.py b/bookwyrm/views/preferences/move_user.py new file mode 100644 index 000000000..93abf2f18 --- /dev/null +++ b/bookwyrm/views/preferences/move_user.py @@ -0,0 +1,111 @@ +""" move your account somewhere else """ + +from django.core.exceptions import PermissionDenied +from django.contrib.auth.decorators import login_required +from django.shortcuts import get_object_or_404, redirect +from django.template.response import TemplateResponse +from django.utils.decorators import method_decorator +from django.views import View +from django.views.decorators.http import require_POST + +from bookwyrm import forms, models +from bookwyrm.views.helpers import handle_remote_webfinger + + +# pylint: disable=no-self-use +@method_decorator(login_required, name="dispatch") +class MoveUser(View): + """move user view""" + + def get(self, request): + """move page for a user""" + data = { + "form": forms.MoveUserForm(), + "user": request.user, + } + return TemplateResponse(request, "preferences/move_user.html", data) + + def post(self, request): + """Packing your stuff and moving house""" + form = forms.MoveUserForm(request.POST, instance=request.user) + user = models.User.objects.get(id=request.user.id) + + if form.is_valid() and user.check_password(form.cleaned_data["password"]): + username = form.cleaned_data["target"] + target = handle_remote_webfinger(username) + + try: + models.MoveUser.objects.create( + user=request.user, object=request.user.remote_id, target=target + ) + + return redirect("user-feed", username=request.user.username) + + except PermissionDenied: + form.errors["target"] = [ + "Set this user as an alias on the user you are moving to first" + ] + data = {"form": form, "user": request.user} + return TemplateResponse(request, "preferences/move_user.html", data) + + form.errors["password"] = ["Invalid password"] + data = {"form": form, "user": request.user} + return TemplateResponse(request, "preferences/move_user.html", data) + + +# pylint: disable=no-self-use +@method_decorator(login_required, name="dispatch") +class AliasUser(View): + """alias user view""" + + def get(self, request): + """move page for a user""" + data = { + "form": forms.AliasUserForm(), + "user": request.user, + } + return TemplateResponse(request, "preferences/alias_user.html", data) + + def post(self, request): + """Creating a nom de plume""" + form = forms.AliasUserForm(request.POST, instance=request.user) + user = models.User.objects.get(id=request.user.id) + + if form.is_valid() and user.check_password(form.cleaned_data["password"]): + username = form.cleaned_data["username"] + remote_user = handle_remote_webfinger(username) + + if remote_user is None: + form.errors["username"] = ["Username does not exist"] + data = {"form": form, "user": request.user} + return TemplateResponse(request, "preferences/alias_user.html", data) + + user.also_known_as.add(remote_user.id) + + return redirect("prefs-alias") + + form.errors["password"] = ["Invalid password"] + data = {"form": form, "user": request.user} + return TemplateResponse(request, "preferences/alias_user.html", data) + + +@login_required +@require_POST +def remove_alias(request): + """remove an alias from the user profile""" + + request.user.also_known_as.remove(request.POST["alias"]) + return redirect("prefs-alias") + + +@require_POST +@login_required +def unmove(request): + """undo a user move""" + target = get_object_or_404(models.User, remote_id=request.POST["remote_id"]) + move = get_object_or_404(models.MoveUser, target=target, user=request.user) + move.delete() + + request.user.moved_to = None + request.user.save(update_fields=["moved_to"], broadcast=True) + return redirect("prefs-alias") diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index 7a0517b01..34b62d0b4 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -1,7 +1,6 @@ """ what are we here for if not for posting """ import re import logging -from urllib.parse import urlparse from django.contrib.auth.decorators import login_required from django.core.validators import URLValidator @@ -297,65 +296,51 @@ def find_or_create_hashtags(content): def format_links(content): """detect and format links""" - validator = URLValidator() - formatted_content = "" + validator = URLValidator(["http", "https"]) + schema_re = re.compile(r"\bhttps?://") split_content = re.split(r"(\s+)", content) - for potential_link in split_content: - if not potential_link: + for i, potential_link in enumerate(split_content): + if not schema_re.search(potential_link): continue - wrapped = _wrapped(potential_link) - if wrapped: - wrapper_close = potential_link[-1] - formatted_content += potential_link[0] - potential_link = potential_link[1:-1] - - ends_with_punctuation = _ends_with_punctuation(potential_link) - if ends_with_punctuation: - punctuation_glyph = potential_link[-1] - potential_link = potential_link[0:-1] + # Strip surrounding brackets and trailing punctuation. + prefix, potential_link, suffix = _unwrap(potential_link) try: # raises an error on anything that's not a valid link validator(potential_link) # use everything but the scheme in the presentation of the link - url = urlparse(potential_link) - link = url.netloc + url.path + url.params - if url.query != "": - link += "?" + url.query - if url.fragment != "": - link += "#" + url.fragment - - formatted_content += f'{link}' + link = schema_re.sub("", potential_link) + split_content[i] = f'{prefix}{link}{suffix}' except (ValidationError, UnicodeError): - formatted_content += potential_link + pass - if wrapped: - formatted_content += wrapper_close - - if ends_with_punctuation: - formatted_content += punctuation_glyph - - return formatted_content + return "".join(split_content) -def _wrapped(text): - """check if a line of text is wrapped""" - wrappers = [("(", ")"), ("[", "]"), ("{", "}")] - for wrapper in wrappers: +def _unwrap(text): + """split surrounding brackets and trailing punctuation from a string of text""" + punct = re.compile(r'([.,;:!?"’”»]+)$') + prefix = suffix = "" + + if punct.search(text): + # Move punctuation to suffix segment. + text, suffix, _ = punct.split(text) + + for wrapper in ("()", "[]", "{}"): if text[0] == wrapper[0] and text[-1] == wrapper[-1]: - return True - return False + # Split out wrapping chars. + suffix = text[-1] + suffix + prefix, text = text[:1], text[1:-1] + break # Nested wrappers not supported atm. + if punct.search(text): + # Move inner punctuation to suffix segment. + text, inner_punct, _ = punct.split(text) + suffix = inner_punct + suffix -def _ends_with_punctuation(text): - """check if a line of text ends with a punctuation glyph""" - glyphs = [".", ",", ";", ":", "!", "?", "”", "’", '"', "»"] - for glyph in glyphs: - if text[-1] == glyph: - return True - return False + return prefix, text, suffix def to_markdown(content): diff --git a/bookwyrm/views/wellknown.py b/bookwyrm/views/wellknown.py index ec5acf98f..0f2805ff2 100644 --- a/bookwyrm/views/wellknown.py +++ b/bookwyrm/views/wellknown.py @@ -21,6 +21,7 @@ def webfinger(request): username = resource.replace("acct:", "") user = get_object_or_404(models.User, username__iexact=username) + href = user.moved_to if user.moved_to else user.remote_id return JsonResponse( { @@ -29,7 +30,7 @@ def webfinger(request): { "rel": "self", "type": "application/activity+json", - "href": user.remote_id, + "href": href, }, { "rel": "http://ostatus.org/schema/1.0/subscribe", diff --git a/bump-version.sh b/bump-version.sh new file mode 100755 index 000000000..552d8409d --- /dev/null +++ b/bump-version.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +NOW="$(date +'%B %d, %Y')" +RED="\033[1;31m" +GREEN="\033[0;32m" +YELLOW="\033[1;33m" +BLUE="\033[1;34m" +PURPLE="\033[1;35m" +CYAN="\033[1;36m" +WHITE="\033[1;37m" +RESET="\033[0m" + +LATEST_HASH=`git log --pretty=format:'%h' -n 1` + +QUESTION_FLAG="${GREEN}?" +WARNING_FLAG="${YELLOW}!" +NOTICE_FLAG="${CYAN}❯" + +# ADJUSTMENTS_MSG="${QUESTION_FLAG} ${CYAN}Now you can make adjustments to ${WHITE}CHANGELOG.md${CYAN}. Then press enter to continue." +PUSHING_MSG="${NOTICE_FLAG} Pushing new version to the ${WHITE}origin${CYAN}..." + +if [ -f VERSION ]; then + BASE_STRING=`cat VERSION` + BASE_LIST=(`echo $BASE_STRING | tr '.' ' '`) + V_MAJOR=${BASE_LIST[0]} + V_MINOR=${BASE_LIST[1]} + V_PATCH=${BASE_LIST[2]} + echo -e "${NOTICE_FLAG} Current version: ${WHITE}$BASE_STRING" + echo -e "${NOTICE_FLAG} Latest commit hash: ${WHITE}$LATEST_HASH" + V_MINOR=$((V_MINOR + 1)) + V_PATCH=0 + SUGGESTED_VERSION="$V_MAJOR.$V_MINOR.$V_PATCH" + echo -ne "${QUESTION_FLAG} ${CYAN}Enter a version number [${WHITE}$SUGGESTED_VERSION${CYAN}]: " + read INPUT_STRING + if [ "$INPUT_STRING" = "" ]; then + INPUT_STRING=$SUGGESTED_VERSION + fi + echo -e "${NOTICE_FLAG} Will set new version to be ${WHITE}$INPUT_STRING" + echo $INPUT_STRING > VERSION +# echo "## $INPUT_STRING ($NOW)" > tmpfile +# git log --pretty=format:" - %s" "v$BASE_STRING"...HEAD >> tmpfile +# echo "" >> tmpfile +# echo "" >> tmpfile +# cat CHANGELOG.md >> tmpfile +# mv tmpfile CHANGELOG.md +# echo -e "$ADJUSTMENTS_MSG" +# read + echo -e "$PUSHING_MSG" +# git add CHANGELOG.md + git add VERSION + git commit -m "Bump version to ${INPUT_STRING}." + git tag -a -m "Tag version ${INPUT_STRING}." "v$INPUT_STRING" + git push origin --tags +else + echo -e "${WARNING_FLAG} Could not find a VERSION file." + echo -ne "${QUESTION_FLAG} ${CYAN}Do you want to create a version file and start from scratch? [${WHITE}y${CYAN}]: " + read RESPONSE + if [ "$RESPONSE" = "" ]; then RESPONSE="y"; fi + if [ "$RESPONSE" = "Y" ]; then RESPONSE="y"; fi + if [ "$RESPONSE" = "Yes" ]; then RESPONSE="y"; fi + if [ "$RESPONSE" = "yes" ]; then RESPONSE="y"; fi + if [ "$RESPONSE" = "YES" ]; then RESPONSE="y"; fi + if [ "$RESPONSE" = "y" ]; then + echo "0.1.0" > VERSION +# echo "## 0.1.0 ($NOW)" > CHANGELOG.md +# git log --pretty=format:" - %s" >> CHANGELOG.md +# echo "" >> CHANGELOG.md +# echo "" >> CHANGELOG.md +# echo -e "$ADJUSTMENTS_MSG" +# read + echo -e "$PUSHING_MSG" +# git add CHANGELOG.md + git add VERSION + git commit -m "Add VERSION and CHANGELOG.md files, Bump version to v0.1.0." + git tag -a -m "Tag version 0.1.0." "v0.1.0" + git push origin --tags + fi +fi + +echo -e "${NOTICE_FLAG} Finished." diff --git a/locale/ca_ES/LC_MESSAGES/django.mo b/locale/ca_ES/LC_MESSAGES/django.mo index f62f704e5..a9b338a2a 100644 Binary files a/locale/ca_ES/LC_MESSAGES/django.mo and b/locale/ca_ES/LC_MESSAGES/django.mo differ diff --git a/locale/ca_ES/LC_MESSAGES/django.po b/locale/ca_ES/LC_MESSAGES/django.po index 6a58b0720..d5e96e0d1 100644 --- a/locale/ca_ES/LC_MESSAGES/django.po +++ b/locale/ca_ES/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 06:50\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-11 06:52\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Catalan\n" "Language: ca\n" @@ -1372,8 +1372,8 @@ msgstr "Edicions de %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Edicions de \"%(work_title)s\"" +msgid "Editions of %(work_title)s" +msgstr "Edicions de \"%(work_title)s\"" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,15 +2805,10 @@ msgstr "Fitxer CSV no vàlid" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " -msgstr[0] "\n" -"Actualment, es permet la importació de %(display_size)s llibres cada %(import_limit_reset)s dies. " -msgstr[1] "" +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." +msgstr[0] "" +msgstr[1] "Actualment, se't permet la importació de %(import_size_limit)s llibres cada %(import_limit_reset)s dies." #: bookwyrm/templates/import/import.html:27 #, python-format diff --git a/locale/de_DE/LC_MESSAGES/django.po b/locale/de_DE/LC_MESSAGES/django.po index baf448c10..63cdbd8fc 100644 --- a/locale/de_DE/LC_MESSAGES/django.po +++ b/locale/de_DE/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 16:03\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-02 18:13\n" "Last-Translator: Mouse Reeve \n" "Language-Team: German\n" "Language: de\n" @@ -1372,8 +1372,8 @@ msgstr "Ausgaben von %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Ausgaben von \"%(work_title)s\"" +msgid "Editions of %(work_title)s" +msgstr "" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,15 +2805,10 @@ msgstr "Keine gültige CSV-Datei" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" -msgstr[1] "\n" -"Momentan darfst du alle %(import_limit_reset)s Tage %(import_size_limit)s Bücher importieren. " +msgstr[1] "" #: bookwyrm/templates/import/import.html:27 #, python-format diff --git a/locale/en_US/LC_MESSAGES/django.po b/locale/en_US/LC_MESSAGES/django.po index 60fd2463e..e1196a49b 100644 --- a/locale/en_US/LC_MESSAGES/django.po +++ b/locale/en_US/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"POT-Creation-Date: 2023-11-02 21:32+0000\n" "PO-Revision-Date: 2021-02-28 17:19-0800\n" "Last-Translator: Mouse Reeve \n" "Language-Team: English \n" @@ -43,15 +43,15 @@ msgstr "" msgid "Unlimited" msgstr "" -#: bookwyrm/forms/edit_user.py:88 +#: bookwyrm/forms/edit_user.py:104 msgid "Incorrect password" msgstr "" -#: bookwyrm/forms/edit_user.py:95 bookwyrm/forms/landing.py:90 +#: bookwyrm/forms/edit_user.py:111 bookwyrm/forms/landing.py:90 msgid "Password does not match" msgstr "" -#: bookwyrm/forms/edit_user.py:118 +#: bookwyrm/forms/edit_user.py:134 msgid "Incorrect Password" msgstr "" @@ -103,8 +103,8 @@ msgstr "" msgid "Book Title" msgstr "" -#: bookwyrm/forms/lists.py:28 bookwyrm/templates/shelf/shelf.html:156 -#: bookwyrm/templates/shelf/shelf.html:188 +#: bookwyrm/forms/lists.py:28 bookwyrm/templates/shelf/shelf.html:171 +#: bookwyrm/templates/shelf/shelf.html:203 #: bookwyrm/templates/snippets/create_status/review.html:32 msgid "Rating" msgstr "" @@ -146,7 +146,7 @@ msgstr "" msgid "Automatically generated report" msgstr "" -#: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:47 +#: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 #: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" @@ -172,23 +172,23 @@ msgstr "" msgid "Domain block" msgstr "" -#: bookwyrm/models/book.py:283 +#: bookwyrm/models/book.py:282 msgid "Audiobook" msgstr "" -#: bookwyrm/models/book.py:284 +#: bookwyrm/models/book.py:283 msgid "eBook" msgstr "" -#: bookwyrm/models/book.py:285 +#: bookwyrm/models/book.py:284 msgid "Graphic novel" msgstr "" -#: bookwyrm/models/book.py:286 +#: bookwyrm/models/book.py:285 msgid "Hardcover" msgstr "" -#: bookwyrm/models/book.py:287 +#: bookwyrm/models/book.py:286 msgid "Paperback" msgstr "" @@ -206,26 +206,26 @@ msgstr "" msgid "Blocked" msgstr "" -#: bookwyrm/models/fields.py:29 +#: bookwyrm/models/fields.py:30 #, python-format msgid "%(value)s is not a valid remote_id" msgstr "" -#: bookwyrm/models/fields.py:38 bookwyrm/models/fields.py:47 +#: bookwyrm/models/fields.py:39 bookwyrm/models/fields.py:48 #, python-format msgid "%(value)s is not a valid username" msgstr "" -#: bookwyrm/models/fields.py:192 bookwyrm/templates/layout.html:128 +#: bookwyrm/models/fields.py:193 bookwyrm/templates/layout.html:129 #: bookwyrm/templates/ostatus/error.html:29 msgid "username" msgstr "" -#: bookwyrm/models/fields.py:197 +#: bookwyrm/models/fields.py:198 msgid "A user with that username already exists." msgstr "" -#: bookwyrm/models/fields.py:216 +#: bookwyrm/models/fields.py:217 #: bookwyrm/templates/snippets/privacy-icons.html:3 #: bookwyrm/templates/snippets/privacy-icons.html:4 #: bookwyrm/templates/snippets/privacy_select.html:11 @@ -233,7 +233,7 @@ msgstr "" msgid "Public" msgstr "" -#: bookwyrm/models/fields.py:217 +#: bookwyrm/models/fields.py:218 #: bookwyrm/templates/snippets/privacy-icons.html:7 #: bookwyrm/templates/snippets/privacy-icons.html:8 #: bookwyrm/templates/snippets/privacy_select.html:14 @@ -241,7 +241,7 @@ msgstr "" msgid "Unlisted" msgstr "" -#: bookwyrm/models/fields.py:218 +#: bookwyrm/models/fields.py:219 #: bookwyrm/templates/snippets/privacy_select.html:17 #: bookwyrm/templates/user/relationships/followers.html:6 #: bookwyrm/templates/user/relationships/followers.html:11 @@ -250,7 +250,7 @@ msgstr "" msgid "Followers" msgstr "" -#: bookwyrm/models/fields.py:219 +#: bookwyrm/models/fields.py:220 #: bookwyrm/templates/snippets/create_status/post_options_block.html:6 #: bookwyrm/templates/snippets/privacy-icons.html:15 #: bookwyrm/templates/snippets/privacy-icons.html:16 @@ -259,30 +259,30 @@ msgstr "" msgid "Private" msgstr "" -#: bookwyrm/models/import_job.py:48 bookwyrm/templates/import/import.html:174 +#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 #: bookwyrm/templates/settings/imports/imports.html:98 -#: bookwyrm/templates/settings/users/user_admin.html:81 -#: bookwyrm/templates/settings/users/user_info.html:28 +#: bookwyrm/templates/settings/users/user_admin.html:87 +#: bookwyrm/templates/settings/users/user_info.html:33 msgid "Active" msgstr "" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 msgid "Complete" msgstr "" -#: bookwyrm/models/import_job.py:50 +#: bookwyrm/models/import_job.py:51 msgid "Stopped" msgstr "" -#: bookwyrm/models/import_job.py:83 bookwyrm/models/import_job.py:91 +#: bookwyrm/models/import_job.py:84 bookwyrm/models/import_job.py:92 msgid "Import stopped" msgstr "" -#: bookwyrm/models/import_job.py:363 bookwyrm/models/import_job.py:388 +#: bookwyrm/models/import_job.py:356 bookwyrm/models/import_job.py:381 msgid "Error loading book" msgstr "" -#: bookwyrm/models/import_job.py:372 +#: bookwyrm/models/import_job.py:365 msgid "Could not find a match for book" msgstr "" @@ -369,103 +369,103 @@ msgstr "" msgid "Everything else" msgstr "" -#: bookwyrm/settings.py:223 +#: bookwyrm/settings.py:230 msgid "Home Timeline" msgstr "" -#: bookwyrm/settings.py:223 +#: bookwyrm/settings.py:230 msgid "Home" msgstr "" -#: bookwyrm/settings.py:224 +#: bookwyrm/settings.py:231 msgid "Books Timeline" msgstr "" -#: bookwyrm/settings.py:224 +#: bookwyrm/settings.py:231 #: bookwyrm/templates/guided_tour/user_profile.html:101 #: bookwyrm/templates/search/layout.html:22 #: bookwyrm/templates/search/layout.html:43 -#: bookwyrm/templates/user/layout.html:97 +#: bookwyrm/templates/user/layout.html:112 msgid "Books" msgstr "" -#: bookwyrm/settings.py:296 +#: bookwyrm/settings.py:303 msgid "English" msgstr "" -#: bookwyrm/settings.py:297 +#: bookwyrm/settings.py:304 msgid "Català (Catalan)" msgstr "" -#: bookwyrm/settings.py:298 +#: bookwyrm/settings.py:305 msgid "Deutsch (German)" msgstr "" -#: bookwyrm/settings.py:299 +#: bookwyrm/settings.py:306 msgid "Esperanto (Esperanto)" msgstr "" -#: bookwyrm/settings.py:300 +#: bookwyrm/settings.py:307 msgid "Español (Spanish)" msgstr "" -#: bookwyrm/settings.py:301 +#: bookwyrm/settings.py:308 msgid "Euskara (Basque)" msgstr "" -#: bookwyrm/settings.py:302 +#: bookwyrm/settings.py:309 msgid "Galego (Galician)" msgstr "" -#: bookwyrm/settings.py:303 +#: bookwyrm/settings.py:310 msgid "Italiano (Italian)" msgstr "" -#: bookwyrm/settings.py:304 +#: bookwyrm/settings.py:311 msgid "Suomi (Finnish)" msgstr "" -#: bookwyrm/settings.py:305 +#: bookwyrm/settings.py:312 msgid "Français (French)" msgstr "" -#: bookwyrm/settings.py:306 +#: bookwyrm/settings.py:313 msgid "Lietuvių (Lithuanian)" msgstr "" -#: bookwyrm/settings.py:307 +#: bookwyrm/settings.py:314 msgid "Nederlands (Dutch)" msgstr "" -#: bookwyrm/settings.py:308 +#: bookwyrm/settings.py:315 msgid "Norsk (Norwegian)" msgstr "" -#: bookwyrm/settings.py:309 +#: bookwyrm/settings.py:316 msgid "Polski (Polish)" msgstr "" -#: bookwyrm/settings.py:310 +#: bookwyrm/settings.py:317 msgid "Português do Brasil (Brazilian Portuguese)" msgstr "" -#: bookwyrm/settings.py:311 +#: bookwyrm/settings.py:318 msgid "Português Europeu (European Portuguese)" msgstr "" -#: bookwyrm/settings.py:312 +#: bookwyrm/settings.py:319 msgid "Română (Romanian)" msgstr "" -#: bookwyrm/settings.py:313 +#: bookwyrm/settings.py:320 msgid "Svenska (Swedish)" msgstr "" -#: bookwyrm/settings.py:314 +#: bookwyrm/settings.py:321 msgid "简体中文 (Simplified Chinese)" msgstr "" -#: bookwyrm/settings.py:315 +#: bookwyrm/settings.py:322 msgid "繁體中文 (Traditional Chinese)" msgstr "" @@ -576,7 +576,7 @@ msgid "Software version:" msgstr "" #: bookwyrm/templates/about/layout.html:30 -#: bookwyrm/templates/embed-layout.html:33 +#: bookwyrm/templates/embed-layout.html:34 #: bookwyrm/templates/snippets/footer.html:8 #, python-format msgid "About %(site_name)s" @@ -681,7 +681,7 @@ msgstr "" #: bookwyrm/templates/annual_summary/layout.html:157 #: bookwyrm/templates/annual_summary/layout.html:178 #: bookwyrm/templates/annual_summary/layout.html:247 -#: bookwyrm/templates/book/book.html:63 +#: bookwyrm/templates/book/book.html:65 #: bookwyrm/templates/discover/large-book.html:22 #: bookwyrm/templates/landing/large-book.html:26 #: bookwyrm/templates/landing/small-book.html:18 @@ -769,24 +769,24 @@ msgid "View ISNI record" msgstr "" #: bookwyrm/templates/author/author.html:95 -#: bookwyrm/templates/book/book.html:173 +#: bookwyrm/templates/book/book.html:175 msgid "View on ISFDB" msgstr "" #: bookwyrm/templates/author/author.html:100 #: bookwyrm/templates/author/sync_modal.html:5 -#: bookwyrm/templates/book/book.html:140 +#: bookwyrm/templates/book/book.html:142 #: bookwyrm/templates/book/sync_modal.html:5 msgid "Load data" msgstr "" #: bookwyrm/templates/author/author.html:104 -#: bookwyrm/templates/book/book.html:144 +#: bookwyrm/templates/book/book.html:146 msgid "View on OpenLibrary" msgstr "" #: bookwyrm/templates/author/author.html:119 -#: bookwyrm/templates/book/book.html:158 +#: bookwyrm/templates/book/book.html:160 msgid "View on Inventaire" msgstr "" @@ -798,11 +798,7 @@ msgstr "" msgid "View on Goodreads" msgstr "" -#: bookwyrm/templates/author/author.html:151 -msgid "View ISFDB entry" -msgstr "" - -#: bookwyrm/templates/author/author.html:166 +#: bookwyrm/templates/author/author.html:158 #, python-format msgid "Books by %(name)s" msgstr "" @@ -960,19 +956,19 @@ msgstr "" msgid "Unable to connect to remote source." msgstr "" -#: bookwyrm/templates/book/book.html:71 bookwyrm/templates/book/book.html:72 +#: bookwyrm/templates/book/book.html:73 bookwyrm/templates/book/book.html:74 msgid "Edit Book" msgstr "" -#: bookwyrm/templates/book/book.html:97 bookwyrm/templates/book/book.html:100 +#: bookwyrm/templates/book/book.html:99 bookwyrm/templates/book/book.html:102 msgid "Click to add cover" msgstr "" -#: bookwyrm/templates/book/book.html:106 +#: bookwyrm/templates/book/book.html:108 msgid "Failed to load cover" msgstr "" -#: bookwyrm/templates/book/book.html:117 +#: bookwyrm/templates/book/book.html:119 msgid "Click to enlarge" msgstr "" @@ -1047,13 +1043,13 @@ msgstr "" #: bookwyrm/templates/guided_tour/lists.html:14 #: bookwyrm/templates/guided_tour/user_books.html:102 #: bookwyrm/templates/guided_tour/user_profile.html:78 -#: bookwyrm/templates/layout.html:90 bookwyrm/templates/lists/curate.html:8 +#: bookwyrm/templates/layout.html:91 bookwyrm/templates/lists/curate.html:8 #: bookwyrm/templates/lists/list.html:12 bookwyrm/templates/lists/lists.html:5 #: bookwyrm/templates/lists/lists.html:12 #: bookwyrm/templates/search/layout.html:26 #: bookwyrm/templates/search/layout.html:51 #: bookwyrm/templates/settings/celery.html:77 -#: bookwyrm/templates/user/layout.html:91 bookwyrm/templates/user/lists.html:6 +#: bookwyrm/templates/user/layout.html:106 bookwyrm/templates/user/lists.html:6 msgid "Lists" msgstr "" @@ -1118,7 +1114,7 @@ msgstr "" #: bookwyrm/templates/book/cover_add_modal.html:23 #: bookwyrm/templates/book/edit/edit_book_form.html:250 -msgid "Load cover from url:" +msgid "Load cover from URL:" msgstr "" #: bookwyrm/templates/book/cover_show_modal.html:6 @@ -1329,7 +1325,7 @@ msgid "Add Another Author" msgstr "" #: bookwyrm/templates/book/edit/edit_book_form.html:231 -#: bookwyrm/templates/shelf/shelf.html:147 +#: bookwyrm/templates/shelf/shelf.html:162 msgid "Cover" msgstr "" @@ -1530,22 +1526,22 @@ msgstr "" msgid "%(languages)s language" msgstr "" -#: bookwyrm/templates/book/publisher_info.html:65 +#: bookwyrm/templates/book/publisher_info.html:63 #, python-format msgid "Published %(date)s by %(publisher)s." msgstr "" +#: bookwyrm/templates/book/publisher_info.html:65 +#, python-format +msgid "Published by %(publisher)s." +msgstr "" + #: bookwyrm/templates/book/publisher_info.html:67 #, python-format msgid "Published %(date)s" msgstr "" -#: bookwyrm/templates/book/publisher_info.html:69 -#, python-format -msgid "Published by %(publisher)s." -msgstr "" - -#: bookwyrm/templates/book/rating.html:13 +#: bookwyrm/templates/book/rating.html:19 msgid "rated it" msgstr "" @@ -1553,12 +1549,12 @@ msgstr "" msgid "Series by" msgstr "" -#: bookwyrm/templates/book/series.html:27 +#: bookwyrm/templates/book/series.html:28 #, python-format msgid "Book %(series_number)s" msgstr "" -#: bookwyrm/templates/book/series.html:27 +#: bookwyrm/templates/book/series.html:28 msgid "Unsorted Book" msgstr "" @@ -1588,7 +1584,7 @@ msgid "Sorry! We couldn't find that code." msgstr "" #: bookwyrm/templates/confirm_email/confirm_email.html:19 -#: bookwyrm/templates/settings/users/user_info.html:92 +#: bookwyrm/templates/settings/users/user_info.html:98 msgid "Confirmation code:" msgstr "" @@ -1682,6 +1678,7 @@ msgstr "" #: bookwyrm/templates/ostatus/subscribe.html:42 #: bookwyrm/templates/ostatus/success.html:17 #: bookwyrm/templates/ostatus/success.html:18 +#: bookwyrm/templates/user/moved.html:19 bookwyrm/templates/user/moved.html:20 #: bookwyrm/templates/user/user_preview.html:16 #: bookwyrm/templates/user/user_preview.html:17 msgid "Locked account" @@ -1756,7 +1753,7 @@ msgstr "" #: bookwyrm/templates/discover/discover.html:4 #: bookwyrm/templates/discover/discover.html:10 -#: bookwyrm/templates/layout.html:93 +#: bookwyrm/templates/layout.html:94 msgid "Discover" msgstr "" @@ -1888,20 +1885,20 @@ msgstr "" msgid "Test email" msgstr "" -#: bookwyrm/templates/embed-layout.html:20 bookwyrm/templates/layout.html:31 -#: bookwyrm/templates/setup/layout.html:15 +#: bookwyrm/templates/embed-layout.html:21 bookwyrm/templates/layout.html:33 +#: bookwyrm/templates/layout.html:163 bookwyrm/templates/setup/layout.html:15 #: bookwyrm/templates/two_factor_auth/two_factor_login.html:18 #: bookwyrm/templates/two_factor_auth/two_factor_prompt.html:18 #, python-format msgid "%(site_name)s home page" msgstr "" -#: bookwyrm/templates/embed-layout.html:39 +#: bookwyrm/templates/embed-layout.html:40 #: bookwyrm/templates/snippets/footer.html:12 msgid "Contact site admin" msgstr "" -#: bookwyrm/templates/embed-layout.html:45 +#: bookwyrm/templates/embed-layout.html:46 msgid "Join BookWyrm" msgstr "" @@ -1997,19 +1994,19 @@ msgid "Add to your books" msgstr "" #: bookwyrm/templates/get_started/book_preview.html:10 -#: bookwyrm/templates/shelf/shelf.html:86 bookwyrm/templates/user/user.html:37 +#: bookwyrm/templates/shelf/shelf.html:101 bookwyrm/templates/user/user.html:37 #: bookwyrm/templatetags/shelf_tags.py:14 msgid "To Read" msgstr "" #: bookwyrm/templates/get_started/book_preview.html:11 -#: bookwyrm/templates/shelf/shelf.html:87 bookwyrm/templates/user/user.html:38 +#: bookwyrm/templates/shelf/shelf.html:102 bookwyrm/templates/user/user.html:38 #: bookwyrm/templatetags/shelf_tags.py:15 msgid "Currently Reading" msgstr "" #: bookwyrm/templates/get_started/book_preview.html:12 -#: bookwyrm/templates/shelf/shelf.html:88 +#: bookwyrm/templates/shelf/shelf.html:103 #: bookwyrm/templates/snippets/shelf_selector.html:46 #: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:24 #: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:12 @@ -2018,7 +2015,7 @@ msgid "Read" msgstr "" #: bookwyrm/templates/get_started/book_preview.html:13 -#: bookwyrm/templates/shelf/shelf.html:89 bookwyrm/templates/user/user.html:40 +#: bookwyrm/templates/shelf/shelf.html:104 bookwyrm/templates/user/user.html:40 #: bookwyrm/templatetags/shelf_tags.py:17 msgid "Stopped Reading" msgstr "" @@ -2028,7 +2025,7 @@ msgid "What are you reading?" msgstr "" #: bookwyrm/templates/get_started/books.html:9 -#: bookwyrm/templates/layout.html:39 bookwyrm/templates/lists/list.html:213 +#: bookwyrm/templates/layout.html:41 bookwyrm/templates/lists/list.html:213 msgid "Search for a book" msgstr "" @@ -2047,8 +2044,8 @@ msgstr "" #: bookwyrm/templates/get_started/users.html:18 #: bookwyrm/templates/get_started/users.html:19 #: bookwyrm/templates/groups/members.html:15 -#: bookwyrm/templates/groups/members.html:16 bookwyrm/templates/layout.html:45 -#: bookwyrm/templates/layout.html:46 bookwyrm/templates/lists/list.html:217 +#: bookwyrm/templates/groups/members.html:16 bookwyrm/templates/layout.html:47 +#: bookwyrm/templates/layout.html:48 bookwyrm/templates/lists/list.html:217 #: bookwyrm/templates/search/layout.html:5 #: bookwyrm/templates/search/layout.html:10 #: bookwyrm/templates/search/layout.html:32 @@ -2539,8 +2536,8 @@ msgid "The bell will light up when you have a new notification. When it does, cl msgstr "" #: bookwyrm/templates/guided_tour/home.html:177 -#: bookwyrm/templates/layout.html:75 bookwyrm/templates/layout.html:106 -#: bookwyrm/templates/layout.html:107 +#: bookwyrm/templates/layout.html:77 bookwyrm/templates/layout.html:107 +#: bookwyrm/templates/layout.html:108 #: bookwyrm/templates/notifications/notifications_page.html:5 #: bookwyrm/templates/notifications/notifications_page.html:10 msgid "Notifications" @@ -2703,7 +2700,8 @@ msgstr "" #: bookwyrm/templates/guided_tour/user_groups.html:11 #: bookwyrm/templates/guided_tour/user_profile.html:55 -#: bookwyrm/templates/user/groups.html:6 bookwyrm/templates/user/layout.html:85 +#: bookwyrm/templates/user/groups.html:6 +#: bookwyrm/templates/user/layout.html:100 msgid "Groups" msgstr "" @@ -2748,7 +2746,7 @@ msgid "This is your user profile. All your latest activities will be listed here msgstr "" #: bookwyrm/templates/guided_tour/user_profile.html:11 -#: bookwyrm/templates/user/layout.html:19 bookwyrm/templates/user/user.html:14 +#: bookwyrm/templates/user/layout.html:20 bookwyrm/templates/user/user.html:14 msgid "User Profile" msgstr "" @@ -2757,7 +2755,7 @@ msgid "This tab shows everything you have read towards your annual reading goal, msgstr "" #: bookwyrm/templates/guided_tour/user_profile.html:32 -#: bookwyrm/templates/user/goal.html:6 bookwyrm/templates/user/layout.html:79 +#: bookwyrm/templates/user/goal.html:6 bookwyrm/templates/user/layout.html:94 msgid "Reading Goal" msgstr "" @@ -2796,7 +2794,7 @@ msgstr "" #: bookwyrm/templates/import/import.html:5 #: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:64 +#: bookwyrm/templates/shelf/shelf.html:79 msgid "Import Books" msgstr "" @@ -2807,7 +2805,7 @@ msgstr "" #: bookwyrm/templates/import/import.html:21 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." -msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." +msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" @@ -2868,7 +2866,7 @@ msgstr "" #: bookwyrm/templates/import/import.html:106 #: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:35 +#: bookwyrm/templates/preferences/layout.html:43 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "" @@ -2967,8 +2965,8 @@ msgid "Row" msgstr "" #: bookwyrm/templates/import/import_status.html:110 -#: bookwyrm/templates/shelf/shelf.html:148 -#: bookwyrm/templates/shelf/shelf.html:170 +#: bookwyrm/templates/shelf/shelf.html:163 +#: bookwyrm/templates/shelf/shelf.html:185 msgid "Title" msgstr "" @@ -2981,8 +2979,8 @@ msgid "Openlibrary key" msgstr "" #: bookwyrm/templates/import/import_status.html:121 -#: bookwyrm/templates/shelf/shelf.html:149 -#: bookwyrm/templates/shelf/shelf.html:173 +#: bookwyrm/templates/shelf/shelf.html:164 +#: bookwyrm/templates/shelf/shelf.html:188 msgid "Author" msgstr "" @@ -3139,7 +3137,7 @@ msgid "Login" msgstr "" #: bookwyrm/templates/landing/login.html:7 -#: bookwyrm/templates/landing/login.html:36 bookwyrm/templates/layout.html:136 +#: bookwyrm/templates/landing/login.html:36 bookwyrm/templates/layout.html:142 #: bookwyrm/templates/ostatus/error.html:37 msgid "Log in" msgstr "" @@ -3150,7 +3148,7 @@ msgstr "" #: bookwyrm/templates/landing/login.html:21 #: bookwyrm/templates/landing/reactivate.html:17 -#: bookwyrm/templates/layout.html:127 bookwyrm/templates/ostatus/error.html:28 +#: bookwyrm/templates/layout.html:128 bookwyrm/templates/ostatus/error.html:28 #: bookwyrm/templates/snippets/register_form.html:4 msgid "Username:" msgstr "" @@ -3158,13 +3156,13 @@ msgstr "" #: bookwyrm/templates/landing/login.html:27 #: bookwyrm/templates/landing/password_reset.html:26 #: bookwyrm/templates/landing/reactivate.html:23 -#: bookwyrm/templates/layout.html:131 bookwyrm/templates/ostatus/error.html:32 +#: bookwyrm/templates/layout.html:132 bookwyrm/templates/ostatus/error.html:32 #: bookwyrm/templates/preferences/2fa.html:91 #: bookwyrm/templates/snippets/register_form.html:45 msgid "Password:" msgstr "" -#: bookwyrm/templates/landing/login.html:39 bookwyrm/templates/layout.html:133 +#: bookwyrm/templates/landing/login.html:39 bookwyrm/templates/layout.html:139 #: bookwyrm/templates/ostatus/error.html:34 msgid "Forgot your password?" msgstr "" @@ -3207,35 +3205,39 @@ msgstr "" msgid "%(site_name)s search" msgstr "" -#: bookwyrm/templates/layout.html:37 +#: bookwyrm/templates/layout.html:39 msgid "Search for a book, user, or list" msgstr "" -#: bookwyrm/templates/layout.html:52 bookwyrm/templates/layout.html:53 +#: bookwyrm/templates/layout.html:54 bookwyrm/templates/layout.html:55 msgid "Scan Barcode" msgstr "" -#: bookwyrm/templates/layout.html:67 +#: bookwyrm/templates/layout.html:69 msgid "Main navigation menu" msgstr "" -#: bookwyrm/templates/layout.html:87 +#: bookwyrm/templates/layout.html:88 msgid "Feed" msgstr "" -#: bookwyrm/templates/layout.html:132 bookwyrm/templates/ostatus/error.html:33 +#: bookwyrm/templates/layout.html:134 bookwyrm/templates/ostatus/error.html:33 msgid "password" msgstr "" -#: bookwyrm/templates/layout.html:144 +#: bookwyrm/templates/layout.html:136 +msgid "Show/Hide password" +msgstr "" + +#: bookwyrm/templates/layout.html:150 msgid "Join" msgstr "" -#: bookwyrm/templates/layout.html:179 +#: bookwyrm/templates/layout.html:196 msgid "Successfully posted status" msgstr "" -#: bookwyrm/templates/layout.html:180 +#: bookwyrm/templates/layout.html:197 msgid "Error posting status" msgstr "" @@ -3494,6 +3496,23 @@ msgstr "" msgid "Saved Lists" msgstr "" +#: bookwyrm/templates/moved.html:27 +#, python-format +msgid "You have moved your account to %(username)s" +msgstr "" + +#: bookwyrm/templates/moved.html:32 +msgid "You can undo the move to restore full functionality, but some followers may have already unfollowed this account." +msgstr "" + +#: bookwyrm/templates/moved.html:42 bookwyrm/templates/shelf/shelf.html:32 +msgid "Undo move" +msgstr "" + +#: bookwyrm/templates/moved.html:46 bookwyrm/templates/user_menu.html:82 +msgid "Log out" +msgstr "" + #: bookwyrm/templates/notifications/items/accept.html:18 #, python-format msgid "%(related_user)s accepted your invitation to join group \"%(group_name)s\"" @@ -3745,6 +3764,16 @@ msgstr "" msgid "%(related_user)s mentioned you in a status" msgstr "" +#: bookwyrm/templates/notifications/items/move_user.html:18 +#, python-format +msgid "%(related_user)s has moved to %(username)s" +msgstr "" + +#: bookwyrm/templates/notifications/items/move_user.html:25 +#, python-format +msgid "%(related_user)s has undone their move" +msgstr "" + #: bookwyrm/templates/notifications/items/remove.html:17 #, python-format msgid "has been removed from your group \"%(group_name)s\"" @@ -3783,7 +3812,7 @@ msgstr[0] "" msgstr[1] "" #: bookwyrm/templates/notifications/items/status_preview.html:4 -#: bookwyrm/templates/snippets/status/content_status.html:73 +#: bookwyrm/templates/snippets/status/content_status.html:62 msgid "Content warning" msgstr "" @@ -4001,9 +4030,51 @@ msgstr "" msgid "Set up 2FA" msgstr "" +#: bookwyrm/templates/preferences/alias_user.html:4 +#: bookwyrm/templates/preferences/move_user.html:4 +#: bookwyrm/templates/preferences/move_user.html:7 +#: bookwyrm/templates/preferences/move_user.html:39 +msgid "Move Account" +msgstr "" + +#: bookwyrm/templates/preferences/alias_user.html:7 +#: bookwyrm/templates/preferences/alias_user.html:34 +msgid "Create Alias" +msgstr "" + +#: bookwyrm/templates/preferences/alias_user.html:12 +msgid "Add another account as an alias" +msgstr "" + +#: bookwyrm/templates/preferences/alias_user.html:16 +msgid "Marking another account as an alias is required if you want to move that account to this one." +msgstr "" + +#: bookwyrm/templates/preferences/alias_user.html:19 +msgid "This is a reversable action and will not change the functionality of this account." +msgstr "" + +#: bookwyrm/templates/preferences/alias_user.html:25 +msgid "Enter the username for the account you want to add as an alias e.g. user@example.com :" +msgstr "" + +#: bookwyrm/templates/preferences/alias_user.html:30 +#: bookwyrm/templates/preferences/move_user.html:35 +msgid "Confirm your password:" +msgstr "" + +#: bookwyrm/templates/preferences/alias_user.html:39 +#: bookwyrm/templates/preferences/layout.html:28 +msgid "Aliases" +msgstr "" + +#: bookwyrm/templates/preferences/alias_user.html:49 +msgid "Remove alias" +msgstr "" + #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:46 +#: bookwyrm/templates/preferences/layout.html:54 msgid "Blocked Users" msgstr "" @@ -4033,7 +4104,7 @@ msgstr "" #: bookwyrm/templates/preferences/delete_user.html:4 #: bookwyrm/templates/preferences/delete_user.html:7 #: bookwyrm/templates/preferences/delete_user.html:40 -#: bookwyrm/templates/preferences/layout.html:28 +#: bookwyrm/templates/preferences/layout.html:36 #: bookwyrm/templates/settings/users/delete_user_form.html:22 msgid "Delete Account" msgstr "" @@ -4155,18 +4226,46 @@ msgstr "" msgid "Account" msgstr "" -#: bookwyrm/templates/preferences/layout.html:31 -msgid "Data" +#: bookwyrm/templates/preferences/layout.html:32 +msgid "Move Account" msgstr "" #: bookwyrm/templates/preferences/layout.html:39 +msgid "Data" +msgstr "" + +#: bookwyrm/templates/preferences/layout.html:47 msgid "CSV export" msgstr "" -#: bookwyrm/templates/preferences/layout.html:42 +#: bookwyrm/templates/preferences/layout.html:50 msgid "Relationships" msgstr "" +#: bookwyrm/templates/preferences/move_user.html:12 +msgid "Migrate account to another server" +msgstr "" + +#: bookwyrm/templates/preferences/move_user.html:16 +msgid "Moving your account will notify all your followers and direct them to follow the new account." +msgstr "" + +#: bookwyrm/templates/preferences/move_user.html:19 +#, python-format +msgid "" +"\n" +" %(user)s will be marked as moved and will not be discoverable or usable unless you undo the move.\n" +" " +msgstr "" + +#: bookwyrm/templates/preferences/move_user.html:25 +msgid "Remember to add this user as an alias of the target account before you try to move." +msgstr "" + +#: bookwyrm/templates/preferences/move_user.html:30 +msgid "Enter the username for the account you want to move to e.g. user@example.com :" +msgstr "" + #: bookwyrm/templates/reading_progress/finish.html:5 #, python-format msgid "Finish \"%(book_title)s\"" @@ -4574,7 +4673,7 @@ msgid "Streams" msgstr "" #: bookwyrm/templates/settings/celery.html:32 -msgid "Broadcasts" +msgid "Broadcast" msgstr "" #: bookwyrm/templates/settings/celery.html:38 @@ -4900,19 +4999,19 @@ msgstr "" #: bookwyrm/templates/settings/federation/edit_instance.html:52 #: bookwyrm/templates/settings/federation/instance.html:46 -#: bookwyrm/templates/settings/users/user_info.html:113 +#: bookwyrm/templates/settings/users/user_info.html:119 msgid "Status:" msgstr "" #: bookwyrm/templates/settings/federation/edit_instance.html:66 #: bookwyrm/templates/settings/federation/instance.html:40 -#: bookwyrm/templates/settings/users/user_info.html:107 +#: bookwyrm/templates/settings/users/user_info.html:113 msgid "Software:" msgstr "" #: bookwyrm/templates/settings/federation/edit_instance.html:76 #: bookwyrm/templates/settings/federation/instance.html:43 -#: bookwyrm/templates/settings/users/user_info.html:110 +#: bookwyrm/templates/settings/users/user_info.html:116 msgid "Version:" msgstr "" @@ -4925,7 +5024,7 @@ msgid "Details" msgstr "" #: bookwyrm/templates/settings/federation/instance.html:53 -#: bookwyrm/templates/user/layout.html:69 +#: bookwyrm/templates/user/layout.html:84 msgid "Activity" msgstr "" @@ -4939,7 +5038,7 @@ msgid "View all" msgstr "" #: bookwyrm/templates/settings/federation/instance.html:62 -#: bookwyrm/templates/settings/users/user_info.html:60 +#: bookwyrm/templates/settings/users/user_info.html:66 msgid "Reports:" msgstr "" @@ -4956,7 +5055,7 @@ msgid "Blocked by us:" msgstr "" #: bookwyrm/templates/settings/federation/instance.html:90 -#: bookwyrm/templates/settings/users/user_info.html:117 +#: bookwyrm/templates/settings/users/user_info.html:123 msgid "Notes" msgstr "" @@ -5676,17 +5775,22 @@ msgstr "" msgid "Remote instance" msgstr "" -#: bookwyrm/templates/settings/users/user_admin.html:86 +#: bookwyrm/templates/settings/users/user_admin.html:82 +#: bookwyrm/templates/settings/users/user_info.html:29 +msgid "Moved" +msgstr "" + +#: bookwyrm/templates/settings/users/user_admin.html:93 msgid "Deleted" msgstr "" -#: bookwyrm/templates/settings/users/user_admin.html:92 -#: bookwyrm/templates/settings/users/user_info.html:32 +#: bookwyrm/templates/settings/users/user_admin.html:99 +#: bookwyrm/templates/settings/users/user_info.html:38 msgid "Inactive" msgstr "" -#: bookwyrm/templates/settings/users/user_admin.html:101 -#: bookwyrm/templates/settings/users/user_info.html:127 +#: bookwyrm/templates/settings/users/user_admin.html:108 +#: bookwyrm/templates/settings/users/user_info.html:133 msgid "Not set" msgstr "" @@ -5698,55 +5802,55 @@ msgstr "" msgid "Go to user admin" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:40 +#: bookwyrm/templates/settings/users/user_info.html:46 msgid "Local" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:42 +#: bookwyrm/templates/settings/users/user_info.html:48 msgid "Remote" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:51 +#: bookwyrm/templates/settings/users/user_info.html:57 msgid "User details" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:55 +#: bookwyrm/templates/settings/users/user_info.html:61 msgid "Email:" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:65 +#: bookwyrm/templates/settings/users/user_info.html:71 msgid "(View reports)" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:71 +#: bookwyrm/templates/settings/users/user_info.html:77 msgid "Blocked by count:" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:74 +#: bookwyrm/templates/settings/users/user_info.html:80 msgid "Date added:" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:77 +#: bookwyrm/templates/settings/users/user_info.html:83 msgid "Last active date:" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:80 +#: bookwyrm/templates/settings/users/user_info.html:86 msgid "Manually approved followers:" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:83 +#: bookwyrm/templates/settings/users/user_info.html:89 msgid "Discoverable:" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:87 +#: bookwyrm/templates/settings/users/user_info.html:93 msgid "Deactivation reason:" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:102 +#: bookwyrm/templates/settings/users/user_info.html:108 msgid "Instance details" msgstr "" -#: bookwyrm/templates/settings/users/user_info.html:124 +#: bookwyrm/templates/settings/users/user_info.html:130 msgid "View instance" msgstr "" @@ -5883,7 +5987,7 @@ msgid "Need help?" msgstr "" #: bookwyrm/templates/shelf/create_shelf_form.html:5 -#: bookwyrm/templates/shelf/shelf.html:72 +#: bookwyrm/templates/shelf/shelf.html:87 msgid "Create shelf" msgstr "" @@ -5891,58 +5995,66 @@ msgstr "" msgid "Edit Shelf" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:24 +#: bookwyrm/templates/shelf/shelf.html:25 +msgid "You have have moved to" +msgstr "" + +#: bookwyrm/templates/shelf/shelf.html:28 +msgid "You can undo this move to restore full functionality, but some followers may have already unfollowed this account." +msgstr "" + +#: bookwyrm/templates/shelf/shelf.html:39 #: bookwyrm/templates/user/relationships/followers.html:18 #: bookwyrm/templates/user/relationships/following.html:18 msgid "User profile" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:39 +#: bookwyrm/templates/shelf/shelf.html:54 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:97 +#: bookwyrm/templates/shelf/shelf.html:112 #, python-format msgid "%(formatted_count)s book" msgid_plural "%(formatted_count)s books" msgstr[0] "" msgstr[1] "" -#: bookwyrm/templates/shelf/shelf.html:104 +#: bookwyrm/templates/shelf/shelf.html:119 #, python-format msgid "(showing %(start)s-%(end)s)" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:116 +#: bookwyrm/templates/shelf/shelf.html:131 msgid "Edit shelf" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:124 +#: bookwyrm/templates/shelf/shelf.html:139 msgid "Delete shelf" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:152 -#: bookwyrm/templates/shelf/shelf.html:178 +#: bookwyrm/templates/shelf/shelf.html:167 +#: bookwyrm/templates/shelf/shelf.html:193 msgid "Shelved" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:153 -#: bookwyrm/templates/shelf/shelf.html:181 +#: bookwyrm/templates/shelf/shelf.html:168 +#: bookwyrm/templates/shelf/shelf.html:196 msgid "Started" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:154 -#: bookwyrm/templates/shelf/shelf.html:184 +#: bookwyrm/templates/shelf/shelf.html:169 +#: bookwyrm/templates/shelf/shelf.html:199 msgid "Finished" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:154 -#: bookwyrm/templates/shelf/shelf.html:184 +#: bookwyrm/templates/shelf/shelf.html:169 +#: bookwyrm/templates/shelf/shelf.html:199 msgid "Until" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:210 +#: bookwyrm/templates/shelf/shelf.html:225 msgid "This shelf is empty." msgstr "" @@ -6248,6 +6360,10 @@ msgstr "" msgid "%(username)s has read %(read_count)s of %(goal_count)s books." msgstr "" +#: bookwyrm/templates/snippets/move_user_buttons.html:10 +msgid "Follow at new account" +msgstr "" + #: bookwyrm/templates/snippets/page_text.html:8 #, python-format msgid "page %(page)s of %(total_pages)s" @@ -6389,35 +6505,35 @@ msgstr "" msgid "Finish reading" msgstr "" -#: bookwyrm/templates/snippets/status/content_status.html:80 +#: bookwyrm/templates/snippets/status/content_status.html:69 msgid "Show status" msgstr "" -#: bookwyrm/templates/snippets/status/content_status.html:102 +#: bookwyrm/templates/snippets/status/content_status.html:91 #, python-format msgid "(Page %(page)s" msgstr "" -#: bookwyrm/templates/snippets/status/content_status.html:102 +#: bookwyrm/templates/snippets/status/content_status.html:91 #, python-format msgid "%(endpage)s" msgstr "" -#: bookwyrm/templates/snippets/status/content_status.html:104 +#: bookwyrm/templates/snippets/status/content_status.html:93 #, python-format msgid "(%(percent)s%%" msgstr "" -#: bookwyrm/templates/snippets/status/content_status.html:104 +#: bookwyrm/templates/snippets/status/content_status.html:93 #, python-format msgid " - %(endpercent)s%%" msgstr "" -#: bookwyrm/templates/snippets/status/content_status.html:127 +#: bookwyrm/templates/snippets/status/content_status.html:116 msgid "Open image in new window" msgstr "" -#: bookwyrm/templates/snippets/status/content_status.html:148 +#: bookwyrm/templates/snippets/status/content_status.html:137 msgid "Hide status" msgstr "" @@ -6609,10 +6725,14 @@ msgid "Groups: %(username)s" msgstr "" #: bookwyrm/templates/user/layout.html:50 +msgid "has moved to" +msgstr "" + +#: bookwyrm/templates/user/layout.html:64 msgid "Follow Requests" msgstr "" -#: bookwyrm/templates/user/layout.html:73 +#: bookwyrm/templates/user/layout.html:88 #: bookwyrm/templates/user/reviews_comments.html:6 #: bookwyrm/templates/user/reviews_comments.html:12 msgid "Reviews and Comments" @@ -6627,6 +6747,12 @@ msgstr "" msgid "Create list" msgstr "" +#: bookwyrm/templates/user/moved.html:25 +#: bookwyrm/templates/user/user_preview.html:22 +#, python-format +msgid "Joined %(date)s" +msgstr "" + #: bookwyrm/templates/user/relationships/followers.html:31 #, python-format msgid "%(username)s has no followers" @@ -6698,11 +6824,6 @@ msgstr "" msgid "No activities yet!" msgstr "" -#: bookwyrm/templates/user/user_preview.html:22 -#, python-format -msgid "Joined %(date)s" -msgstr "" - #: bookwyrm/templates/user/user_preview.html:26 #, python-format msgid "%(display_count)s follower" @@ -6730,10 +6851,6 @@ msgstr "" msgid "View profile and more" msgstr "" -#: bookwyrm/templates/user_menu.html:82 -msgid "Log out" -msgstr "" - #: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:28 msgid "File exceeds maximum size: 10MB" msgstr "" @@ -6750,7 +6867,7 @@ msgid_plural "%(num)d books - by %(user)s" msgstr[0] "" msgstr[1] "" -#: bookwyrm/templatetags/utilities.py:39 +#: bookwyrm/templatetags/utilities.py:48 #, python-format msgid "%(title)s: %(subtitle)s" msgstr "" diff --git a/locale/eo_UY/LC_MESSAGES/django.mo b/locale/eo_UY/LC_MESSAGES/django.mo index 1f66de56e..6795f2e82 100644 Binary files a/locale/eo_UY/LC_MESSAGES/django.mo and b/locale/eo_UY/LC_MESSAGES/django.mo differ diff --git a/locale/eo_UY/LC_MESSAGES/django.po b/locale/eo_UY/LC_MESSAGES/django.po index 47bd205ef..1a95d4766 100644 --- a/locale/eo_UY/LC_MESSAGES/django.po +++ b/locale/eo_UY/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 00:08\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-02 19:32\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Esperanto\n" "Language: eo\n" @@ -1372,8 +1372,8 @@ msgstr "Eldonoj de %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Eldonoj de «%(work_title)s»" +msgid "Editions of %(work_title)s" +msgstr "Eldonoj de %(work_title)s" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,14 +2805,10 @@ msgstr "La CSV-a dosiero ne validas" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " -msgstr[0] "" -msgstr[1] "" +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." +msgstr[0] "Aktuale vi rajtas importi %(display_size)s librojn ĉiun %(import_limit_reset)s tagon." +msgstr[1] "Aktuale vi rajtas importi %(import_size_limit)s librojn ĉiujn %(import_limit_reset)s tagojn." #: bookwyrm/templates/import/import.html:27 #, python-format diff --git a/locale/es_ES/LC_MESSAGES/django.mo b/locale/es_ES/LC_MESSAGES/django.mo index 95c05e2cc..9ed73ceed 100644 Binary files a/locale/es_ES/LC_MESSAGES/django.mo and b/locale/es_ES/LC_MESSAGES/django.mo differ diff --git a/locale/es_ES/LC_MESSAGES/django.po b/locale/es_ES/LC_MESSAGES/django.po index 7738d0fa7..7f27a3e61 100644 --- a/locale/es_ES/LC_MESSAGES/django.po +++ b/locale/es_ES/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 14:47\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-30 00:47\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Spanish\n" "Language: es\n" @@ -1035,7 +1035,7 @@ msgstr "Tus citas" #: bookwyrm/templates/book/book.html:360 msgid "Subjects" -msgstr "Sujetos" +msgstr "Temas" #: bookwyrm/templates/book/book.html:372 msgid "Places" @@ -1372,8 +1372,8 @@ msgstr "Ediciones de %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Ediciones de \"%(work_title)s\"" +msgid "Editions of %(work_title)s" +msgstr "Ediciones de %(work_title)s" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,18 +2805,10 @@ msgstr "No es un archivo CSV válido" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " -msgstr[0] "\n" -" Actualmente, puedes importar %(display_size)s libros cada %(import_limit_reset)s días.\n" -" " -msgstr[1] "\n" -" Actualmente, puedes importar %(import_size_limit)s libros cada %(import_limit_reset)s días.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." +msgstr[0] "Actualmente, puedes importar %(display_size)s libros cada %(import_limit_reset)s días." +msgstr[1] "Actualmente, puedes importar %(import_size_limit)s libros cada %(import_limit_reset)s días." #: bookwyrm/templates/import/import.html:27 #, python-format @@ -6162,7 +6154,7 @@ msgstr "Apoya a %(site_name)s en GitHub." -msgstr "BookWyrm es software libre y de código abierto. Puedes contribuir o reportar problemas en GitHub." +msgstr "BookWyrm es software de código abierto. Puedes contribuir o reportar problemas en GitHub." #: bookwyrm/templates/snippets/form_rate_stars.html:20 #: bookwyrm/templates/snippets/stars.html:23 diff --git a/locale/eu_ES/LC_MESSAGES/django.mo b/locale/eu_ES/LC_MESSAGES/django.mo index 572a0f9b2..cceaa551c 100644 Binary files a/locale/eu_ES/LC_MESSAGES/django.mo and b/locale/eu_ES/LC_MESSAGES/django.mo differ diff --git a/locale/eu_ES/LC_MESSAGES/django.po b/locale/eu_ES/LC_MESSAGES/django.po index 24ede78e9..fe0ec9634 100644 --- a/locale/eu_ES/LC_MESSAGES/django.po +++ b/locale/eu_ES/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 00:08\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-02 18:13\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Basque\n" "Language: eu\n" @@ -1372,8 +1372,8 @@ msgstr "%(book_title)s(r)en edizioak" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "\"%(work_title)s\"-ren edizioak" +msgid "Editions of %(work_title)s" +msgstr "" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,12 +2805,8 @@ msgstr "CSV fitxategia ez da baliozkoa" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" diff --git a/locale/fi_FI/LC_MESSAGES/django.mo b/locale/fi_FI/LC_MESSAGES/django.mo index beacc8844..aef95bcc0 100644 Binary files a/locale/fi_FI/LC_MESSAGES/django.mo and b/locale/fi_FI/LC_MESSAGES/django.mo differ diff --git a/locale/fi_FI/LC_MESSAGES/django.po b/locale/fi_FI/LC_MESSAGES/django.po index b25e5c8e0..67bd955a7 100644 --- a/locale/fi_FI/LC_MESSAGES/django.po +++ b/locale/fi_FI/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-29 23:37\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-02 18:13\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Finnish\n" "Language: fi\n" @@ -1372,8 +1372,8 @@ msgstr "Kirjan %(book_title)s laitokset" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Kirjan \"%(work_title)s\" laitokset" +msgid "Editions of %(work_title)s" +msgstr "" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,12 +2805,8 @@ msgstr "Epäkelpo CSV-tiedosto" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" diff --git a/locale/fr_FR/LC_MESSAGES/django.mo b/locale/fr_FR/LC_MESSAGES/django.mo index fd48c948c..4cdcbf8ea 100644 Binary files a/locale/fr_FR/LC_MESSAGES/django.mo and b/locale/fr_FR/LC_MESSAGES/django.mo differ diff --git a/locale/fr_FR/LC_MESSAGES/django.po b/locale/fr_FR/LC_MESSAGES/django.po index 452c08205..1bd27f690 100644 --- a/locale/fr_FR/LC_MESSAGES/django.po +++ b/locale/fr_FR/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 00:08\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-31 20:26\n" "Last-Translator: Mouse Reeve \n" "Language-Team: French\n" "Language: fr\n" @@ -310,47 +310,47 @@ msgstr "Commentaire" #: bookwyrm/models/report.py:85 msgid "Resolved report" -msgstr "" +msgstr "Signalement résolu" #: bookwyrm/models/report.py:86 msgid "Re-opened report" -msgstr "" +msgstr "Ouvrir le signalement de nouveau" #: bookwyrm/models/report.py:87 msgid "Messaged reporter" -msgstr "" +msgstr "Rapporteur contacté" #: bookwyrm/models/report.py:88 msgid "Messaged reported user" -msgstr "" +msgstr "Compte signalé contacté" #: bookwyrm/models/report.py:89 msgid "Suspended user" -msgstr "" +msgstr "Compte suspendu" #: bookwyrm/models/report.py:90 msgid "Un-suspended user" -msgstr "" +msgstr "Compte non‑suspendu" #: bookwyrm/models/report.py:91 msgid "Changed user permission level" -msgstr "" +msgstr "Niveau des permissions utilisateur modifié" #: bookwyrm/models/report.py:92 msgid "Deleted user account" -msgstr "" +msgstr "Compte supprimé" #: bookwyrm/models/report.py:93 msgid "Blocked domain" -msgstr "" +msgstr "Domaine bloqué" #: bookwyrm/models/report.py:94 msgid "Approved domain" -msgstr "" +msgstr "Domaine approuvé" #: bookwyrm/models/report.py:95 msgid "Deleted item" -msgstr "" +msgstr "Item supprimé" #: bookwyrm/models/user.py:32 bookwyrm/templates/book/book.html:307 msgid "Reviews" @@ -378,7 +378,7 @@ msgstr "Accueil" #: bookwyrm/settings.py:224 msgid "Books Timeline" -msgstr "Actualité de mes livres" +msgstr "Mon fil d’actualité littéraire" #: bookwyrm/settings.py:224 #: bookwyrm/templates/guided_tour/user_profile.html:101 @@ -434,7 +434,7 @@ msgstr "Lietuvių (Lituanien)" #: bookwyrm/settings.py:307 msgid "Nederlands (Dutch)" -msgstr "" +msgstr "Pays‑Bas (Néerlandais)" #: bookwyrm/settings.py:308 msgid "Norsk (Norwegian)" @@ -1076,11 +1076,11 @@ msgstr "ISBN :" #: bookwyrm/templates/book/book_identifiers.html:12 #: bookwyrm/templates/book/book_identifiers.html:13 msgid "Copy ISBN" -msgstr "" +msgstr "Copier l’ISBN" #: bookwyrm/templates/book/book_identifiers.html:16 msgid "Copied ISBN!" -msgstr "" +msgstr "ISBN copié !" #: bookwyrm/templates/book/book_identifiers.html:23 #: bookwyrm/templates/book/edit/edit_book_form.html:352 @@ -1245,7 +1245,7 @@ msgstr "Titre :" #: bookwyrm/templates/book/edit/edit_book_form.html:35 msgid "Sort Title:" -msgstr "" +msgstr "Titre de tri :" #: bookwyrm/templates/book/edit/edit_book_form.html:44 msgid "Subtitle:" @@ -1372,8 +1372,8 @@ msgstr "Éditions de %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Éditions de « %(work_title)s »" +msgid "Editions of %(work_title)s" +msgstr "Éditions de %(work_title)s" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2268,7 +2268,7 @@ msgstr "Responsable" #: bookwyrm/templates/groups/user_groups.html:35 msgid "No groups found." -msgstr "" +msgstr "Aucun groupe trouvé." #: bookwyrm/templates/guided_tour/book.html:10 msgid "This is home page of a book. Let's see what you can do while you're here!" @@ -2805,19 +2805,15 @@ msgstr "Fichier CSV non valide" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " -msgstr[0] "" -msgstr[1] "" +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." +msgstr[0] "Vous êtes actuellement autorisé à importer %(display_size)s livres tous les %(import_limit_reset)s jours." +msgstr[1] "Vous avez le droit d’importer %(display_size)s livres chaque %(import_limit_reset)s jours actuellement." #: bookwyrm/templates/import/import.html:27 #, python-format msgid "You have %(display_left)s left." -msgstr "" +msgstr "Encore %(display_left)s." #: bookwyrm/templates/import/import.html:34 #, python-format @@ -3483,7 +3479,7 @@ msgstr "Sauvegardé" #: bookwyrm/templates/lists/list_items.html:50 msgid "No lists found." -msgstr "" +msgstr "Aucune liste trouvée." #: bookwyrm/templates/lists/lists.html:14 bookwyrm/templates/user/lists.html:14 msgid "Your Lists" @@ -4575,7 +4571,7 @@ msgstr "Queues" #: bookwyrm/templates/settings/celery.html:26 msgid "Streams" -msgstr "" +msgstr "Flux" #: bookwyrm/templates/settings/celery.html:32 msgid "Broadcasts" @@ -4583,15 +4579,15 @@ msgstr "Diffusion" #: bookwyrm/templates/settings/celery.html:38 msgid "Inbox" -msgstr "" +msgstr "Boîte de réception" #: bookwyrm/templates/settings/celery.html:51 msgid "Import triggered" -msgstr "" +msgstr "Import déclenché" #: bookwyrm/templates/settings/celery.html:57 msgid "Connectors" -msgstr "" +msgstr "Connecteurs" #: bookwyrm/templates/settings/celery.html:64 #: bookwyrm/templates/settings/site.html:91 @@ -4600,7 +4596,7 @@ msgstr "Images" #: bookwyrm/templates/settings/celery.html:70 msgid "Suggested Users" -msgstr "" +msgstr "Comptes suggérés" #: bookwyrm/templates/settings/celery.html:83 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:43 @@ -4610,7 +4606,7 @@ msgstr "Email" #: bookwyrm/templates/settings/celery.html:89 msgid "Misc" -msgstr "" +msgstr "Divers" #: bookwyrm/templates/settings/celery.html:96 msgid "Low priority" @@ -5424,22 +5420,22 @@ msgstr "Liens signalés" #: bookwyrm/templates/settings/reports/report.html:66 msgid "Moderation Activity" -msgstr "" +msgstr "Activité de la modération" #: bookwyrm/templates/settings/reports/report.html:73 #, python-format msgid "%(user)s opened this report" -msgstr "" +msgstr "%(user)s a ouvert ce signalement" #: bookwyrm/templates/settings/reports/report.html:86 #, python-format msgid "%(user)s commented on this report:" -msgstr "" +msgstr "%(user)s a commenté ce signalement :" #: bookwyrm/templates/settings/reports/report.html:90 #, python-format msgid "%(user)s took an action on this report:" -msgstr "" +msgstr "%(user)s a traité ce signalement :" #: bookwyrm/templates/settings/reports/report_header.html:6 #, python-format @@ -5463,7 +5459,7 @@ msgstr "Signalement #%(report_id)s : compte @%(username)s" #: bookwyrm/templates/settings/reports/report_links_table.html:19 msgid "Approve domain" -msgstr "" +msgstr "Approuver le domaine" #: bookwyrm/templates/settings/reports/report_links_table.html:26 msgid "Block domain" @@ -6053,7 +6049,7 @@ msgstr "Commentaire :" #: bookwyrm/templates/snippets/create_status/post_options_block.html:19 msgid "Update" -msgstr "" +msgstr "Mettre à jour" #: bookwyrm/templates/snippets/create_status/post_options_block.html:21 msgid "Post" @@ -6711,8 +6707,8 @@ msgstr "A rejoint ce serveur %(date)s" #, python-format msgid "%(display_count)s follower" msgid_plural "%(display_count)s followers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%(display_count)s abonné⋅e" +msgstr[1] "%(display_count)s abonné⋅es" #: bookwyrm/templates/user/user_preview.html:31 #, python-format diff --git a/locale/gl_ES/LC_MESSAGES/django.mo b/locale/gl_ES/LC_MESSAGES/django.mo index 30542ace1..780a8def4 100644 Binary files a/locale/gl_ES/LC_MESSAGES/django.mo and b/locale/gl_ES/LC_MESSAGES/django.mo differ diff --git a/locale/gl_ES/LC_MESSAGES/django.po b/locale/gl_ES/LC_MESSAGES/django.po index 37edcfee9..904c15a63 100644 --- a/locale/gl_ES/LC_MESSAGES/django.po +++ b/locale/gl_ES/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 04:25\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-20 13:05\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Galician\n" "Language: gl\n" @@ -497,7 +497,7 @@ msgstr "Acerca de" #: bookwyrm/templates/get_started/layout.html:22 #, python-format msgid "Welcome to %(site_name)s!" -msgstr "Sexas ben vida a %(site_name)s!" +msgstr "Recibe a benvida a %(site_name)s!" #: bookwyrm/templates/about/about.html:25 #, python-format @@ -1372,8 +1372,8 @@ msgstr "Edicións de %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Edicións de %(work_title)s" +msgid "Editions of %(work_title)s" +msgstr "Edicións de %(work_title)s" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,18 +2805,10 @@ msgstr "Non é un ficheiro CSV válido" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " -msgstr[0] "\n" -" Actualmente, tes permiso para importar %(display_size)s libros cada %(import_limit_reset)s día.\n" -" " -msgstr[1] "\n" -" Actualmente, tes permiso para importar %(import_size_limit)s libros cada %(import_limit_reset)s días.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." +msgstr[0] "Actualmente podes importar %(display_size)s libros cada %(import_limit_reset)s día." +msgstr[1] "Actualmente podes importar %(import_size_limit)s libros cada %(import_limit_reset)s días." #: bookwyrm/templates/import/import.html:27 #, python-format diff --git a/locale/it_IT/LC_MESSAGES/django.mo b/locale/it_IT/LC_MESSAGES/django.mo index 2114d45c5..958cdcbf3 100644 Binary files a/locale/it_IT/LC_MESSAGES/django.mo and b/locale/it_IT/LC_MESSAGES/django.mo differ diff --git a/locale/it_IT/LC_MESSAGES/django.po b/locale/it_IT/LC_MESSAGES/django.po index d0c4e2c69..379d826a6 100644 --- a/locale/it_IT/LC_MESSAGES/django.po +++ b/locale/it_IT/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 09:30\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-02 19:32\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Italian\n" "Language: it\n" @@ -310,15 +310,15 @@ msgstr "Commenta" #: bookwyrm/models/report.py:85 msgid "Resolved report" -msgstr "" +msgstr "Segnalazione risolta" #: bookwyrm/models/report.py:86 msgid "Re-opened report" -msgstr "" +msgstr "Segnalazione riaperta" #: bookwyrm/models/report.py:87 msgid "Messaged reporter" -msgstr "" +msgstr "Messaggio inviato al segnalatore" #: bookwyrm/models/report.py:88 msgid "Messaged reported user" @@ -326,11 +326,11 @@ msgstr "" #: bookwyrm/models/report.py:89 msgid "Suspended user" -msgstr "" +msgstr "Utente sospeso" #: bookwyrm/models/report.py:90 msgid "Un-suspended user" -msgstr "" +msgstr "Utente riattivato" #: bookwyrm/models/report.py:91 msgid "Changed user permission level" @@ -1372,8 +1372,8 @@ msgstr "Edizioni di %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Edizioni di \"%(work_title)s\"" +msgid "Editions of %(work_title)s" +msgstr "Edizioni di %(work_title)s" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,14 +2805,10 @@ msgstr "Non è un file di csv valido" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" -msgstr[1] "" +msgstr[1] "Al momento puoi importare %(import_size_limit)s libri ogni %(import_limit_reset)s giorni." #: bookwyrm/templates/import/import.html:27 #, python-format diff --git a/locale/lt_LT/LC_MESSAGES/django.mo b/locale/lt_LT/LC_MESSAGES/django.mo index 9f002fe1b..7f23c75a3 100644 Binary files a/locale/lt_LT/LC_MESSAGES/django.mo and b/locale/lt_LT/LC_MESSAGES/django.mo differ diff --git a/locale/lt_LT/LC_MESSAGES/django.po b/locale/lt_LT/LC_MESSAGES/django.po index c86bd8fc8..771492f85 100644 --- a/locale/lt_LT/LC_MESSAGES/django.po +++ b/locale/lt_LT/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 00:08\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-02 18:13\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Lithuanian\n" "Language: lt\n" @@ -1384,8 +1384,8 @@ msgstr "Knygos %(book_title)s leidimai" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "\"%(work_title)s\" leidimai" +msgid "Editions of %(work_title)s" +msgstr "" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2825,12 +2825,8 @@ msgstr "Netinkamas CSV failas" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" msgstr[2] "" diff --git a/locale/nl_NL/LC_MESSAGES/django.mo b/locale/nl_NL/LC_MESSAGES/django.mo index 4f0130fd2..088c596b1 100644 Binary files a/locale/nl_NL/LC_MESSAGES/django.mo and b/locale/nl_NL/LC_MESSAGES/django.mo differ diff --git a/locale/nl_NL/LC_MESSAGES/django.po b/locale/nl_NL/LC_MESSAGES/django.po index 5945b5257..0cb6c8ee5 100644 --- a/locale/nl_NL/LC_MESSAGES/django.po +++ b/locale/nl_NL/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 08:16\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-02 19:32\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Dutch\n" "Language: nl\n" @@ -1372,8 +1372,8 @@ msgstr "Edities van %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Edities van \"%(work_title)s\"" +msgid "Editions of %(work_title)s" +msgstr "Edities van %(work_title)s" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,16 +2805,10 @@ msgstr "Geen geldig CSV-bestand" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " -msgstr[0] "\n" -"Momenteel mag je elke %(import_limit_reset)s dag %(display_size)s boeken importeren. " -msgstr[1] "\n" -"Momenteel mag je elke %(import_limit_reset)s dagen %(import_size_limit)s boeken importeren. " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." +msgstr[0] "Momenteel mag je %(display_size)s boek importeren elke %(import_limit_reset)s dagen." +msgstr[1] "Momenteel mag je %(import_size_limit)s boeken importeren elke %(import_limit_reset)s dagen." #: bookwyrm/templates/import/import.html:27 #, python-format diff --git a/locale/no_NO/LC_MESSAGES/django.mo b/locale/no_NO/LC_MESSAGES/django.mo index 66dfbb931..f2038692f 100644 Binary files a/locale/no_NO/LC_MESSAGES/django.mo and b/locale/no_NO/LC_MESSAGES/django.mo differ diff --git a/locale/no_NO/LC_MESSAGES/django.po b/locale/no_NO/LC_MESSAGES/django.po index 851887e7c..3c125d8aa 100644 --- a/locale/no_NO/LC_MESSAGES/django.po +++ b/locale/no_NO/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 00:08\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-09 19:52\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Norwegian\n" "Language: no\n" @@ -314,31 +314,31 @@ msgstr "" #: bookwyrm/models/report.py:86 msgid "Re-opened report" -msgstr "" +msgstr "Gjenåpnet rapport" #: bookwyrm/models/report.py:87 msgid "Messaged reporter" -msgstr "" +msgstr "Melding sendt til rapportør" #: bookwyrm/models/report.py:88 msgid "Messaged reported user" -msgstr "" +msgstr "Melding sendt til rapportert bruker" #: bookwyrm/models/report.py:89 msgid "Suspended user" -msgstr "" +msgstr "Deaktivert bruker" #: bookwyrm/models/report.py:90 msgid "Un-suspended user" -msgstr "" +msgstr "Reaktivert bruker" #: bookwyrm/models/report.py:91 msgid "Changed user permission level" -msgstr "" +msgstr "Endret brukerens rettighetsnivå" #: bookwyrm/models/report.py:92 msgid "Deleted user account" -msgstr "" +msgstr "Slettet brukerkonto" #: bookwyrm/models/report.py:93 msgid "Blocked domain" @@ -1372,8 +1372,8 @@ msgstr "Utgaver av %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Utgaver av \"%(work_title)s\"" +msgid "Editions of %(work_title)s" +msgstr "" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,12 +2805,8 @@ msgstr "Ikke en gyldig CSV-fil" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" diff --git a/locale/pl_PL/LC_MESSAGES/django.mo b/locale/pl_PL/LC_MESSAGES/django.mo index 7c12649d7..e7134182d 100644 Binary files a/locale/pl_PL/LC_MESSAGES/django.mo and b/locale/pl_PL/LC_MESSAGES/django.mo differ diff --git a/locale/pl_PL/LC_MESSAGES/django.po b/locale/pl_PL/LC_MESSAGES/django.po index 9544f3110..a5d366804 100644 --- a/locale/pl_PL/LC_MESSAGES/django.po +++ b/locale/pl_PL/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 00:08\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-03 01:28\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Polish\n" "Language: pl\n" @@ -350,7 +350,7 @@ msgstr "" #: bookwyrm/models/report.py:95 msgid "Deleted item" -msgstr "" +msgstr "Usunięty element" #: bookwyrm/models/user.py:32 bookwyrm/templates/book/book.html:307 msgid "Reviews" @@ -434,7 +434,7 @@ msgstr "Lietuvių (Litewski)" #: bookwyrm/settings.py:307 msgid "Nederlands (Dutch)" -msgstr "" +msgstr "Holenderski" #: bookwyrm/settings.py:308 msgid "Norsk (Norwegian)" @@ -502,7 +502,7 @@ msgstr "Witaj na %(site_name)s!" #: bookwyrm/templates/about/about.html:25 #, python-format msgid "%(site_name)s is part of BookWyrm, a network of independent, self-directed communities for readers. While you can interact seamlessly with users anywhere in the BookWyrm network, this community is unique." -msgstr "" +msgstr "%(site_name)s jest częścią BookWyrm, sieci niezależnych, samostanowiących społeczności czytelników. Możesz beproblemowo wchodzić w interakcje z użytkownikami gdziekolwiek w sieci BookWyrm, ta społeczność jest wyjątkowa." #: bookwyrm/templates/about/about.html:45 #, python-format @@ -521,7 +521,7 @@ msgstr "%(title)s ma najbardziej podzielo #: bookwyrm/templates/about/about.html:94 msgid "Track your reading, talk about books, write reviews, and discover what to read next. Always ad-free, anti-corporate, and community-oriented, BookWyrm is human-scale software, designed to stay small and personal. If you have feature requests, bug reports, or grand dreams, reach out and make yourself heard." -msgstr "" +msgstr "Śledź swój postęp czytelniczy, rozmawiaj o książkach, pisz opinie i odkrywaj co czytać następne. Na zawsze bez reklam, antykorporacyjne i skierowane w stronę społeczności, BookWyrm jest programem dla ludzi, stworzonym, by pozostać małym i personalnym. Jeśli masz pomysł, zauważył_ś błąd, albo masz wielkie marzenie, złoś się i pozwól się wysłuchać." #: bookwyrm/templates/about/about.html:105 msgid "Meet your admins" @@ -672,7 +672,7 @@ msgstr "Przekłada się to na średnio %(pages)s stron na książkę." #, python-format msgid "(No page data was available for %(no_page_number)s book)" msgid_plural "(No page data was available for %(no_page_number)s books)" -msgstr[0] "" +msgstr[0] "(Nie mamy informacji o liczbie stron dla książki %(no_page_number)s)" msgstr[1] "" msgstr[2] "" msgstr[3] "" @@ -778,7 +778,7 @@ msgstr "Zobacz wpis ISNI" #: bookwyrm/templates/author/author.html:95 #: bookwyrm/templates/book/book.html:173 msgid "View on ISFDB" -msgstr "" +msgstr "Zobacz na ISFDB" #: bookwyrm/templates/author/author.html:100 #: bookwyrm/templates/author/sync_modal.html:5 @@ -1116,7 +1116,7 @@ msgstr "" #: bookwyrm/templates/book/book_identifiers.html:51 msgid "Goodreads:" -msgstr "" +msgstr "Goodreads:" #: bookwyrm/templates/book/cover_add_modal.html:5 msgid "Add cover" @@ -1257,7 +1257,7 @@ msgstr "Tytuł:" #: bookwyrm/templates/book/edit/edit_book_form.html:35 msgid "Sort Title:" -msgstr "" +msgstr "Sortuj Według Tytułu:" #: bookwyrm/templates/book/edit/edit_book_form.html:44 msgid "Subtitle:" @@ -1384,8 +1384,8 @@ msgstr "Edycje %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Edycje \"%(work_title)s\"" +msgid "Editions of %(work_title)s" +msgstr "Edycje %(work_title)s" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -1567,7 +1567,7 @@ msgstr "" #: bookwyrm/templates/book/series.html:27 #, python-format msgid "Book %(series_number)s" -msgstr "" +msgstr "Książka%(series_number)s" #: bookwyrm/templates/book/series.html:27 msgid "Unsorted Book" @@ -2825,12 +2825,8 @@ msgstr "To nie jest prawidłowy plik CSV" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" msgstr[2] "" diff --git a/locale/pt_BR/LC_MESSAGES/django.mo b/locale/pt_BR/LC_MESSAGES/django.mo index 05c4cbd8c..42da17a08 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 c11dd5830..495ea43b3 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: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 18:50\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-02 18:13\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Portuguese, Brazilian\n" "Language: pt\n" @@ -1372,8 +1372,8 @@ msgstr "Edições de %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Edições de \"%(work_title)s\"" +msgid "Editions of %(work_title)s" +msgstr "" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,12 +2805,8 @@ msgstr "" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" diff --git a/locale/pt_PT/LC_MESSAGES/django.mo b/locale/pt_PT/LC_MESSAGES/django.mo index 1ca5e1dd7..4e2f18bcb 100644 Binary files a/locale/pt_PT/LC_MESSAGES/django.mo and b/locale/pt_PT/LC_MESSAGES/django.mo differ diff --git a/locale/pt_PT/LC_MESSAGES/django.po b/locale/pt_PT/LC_MESSAGES/django.po index 807fade98..5788aff29 100644 --- a/locale/pt_PT/LC_MESSAGES/django.po +++ b/locale/pt_PT/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 00:08\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-02 18:13\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Portuguese\n" "Language: pt\n" @@ -1372,8 +1372,8 @@ msgstr "Edições de %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Edições de \"%(work_title)s\"" +msgid "Editions of %(work_title)s" +msgstr "" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,12 +2805,8 @@ msgstr "Não é um ficheiro CSV válido" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" diff --git a/locale/ro_RO/LC_MESSAGES/django.mo b/locale/ro_RO/LC_MESSAGES/django.mo index 85a193ba8..7aa5899d1 100644 Binary files a/locale/ro_RO/LC_MESSAGES/django.mo and b/locale/ro_RO/LC_MESSAGES/django.mo differ diff --git a/locale/ro_RO/LC_MESSAGES/django.po b/locale/ro_RO/LC_MESSAGES/django.po index 5f1068e8b..54e13162c 100644 --- a/locale/ro_RO/LC_MESSAGES/django.po +++ b/locale/ro_RO/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 00:08\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-02 18:13\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Romanian\n" "Language: ro\n" @@ -1378,8 +1378,8 @@ msgstr "Ediții ale %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Ediții ale %(work_title)s" +msgid "Editions of %(work_title)s" +msgstr "" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2815,12 +2815,8 @@ msgstr "" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" msgstr[2] "" diff --git a/locale/sv_SE/LC_MESSAGES/django.mo b/locale/sv_SE/LC_MESSAGES/django.mo index 890f3304b..0086e5259 100644 Binary files a/locale/sv_SE/LC_MESSAGES/django.mo and b/locale/sv_SE/LC_MESSAGES/django.mo differ diff --git a/locale/sv_SE/LC_MESSAGES/django.po b/locale/sv_SE/LC_MESSAGES/django.po index 7246dbc19..78106ff7a 100644 --- a/locale/sv_SE/LC_MESSAGES/django.po +++ b/locale/sv_SE/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 09:30\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-02 18:13\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Swedish\n" "Language: sv\n" @@ -1372,8 +1372,8 @@ msgstr "Utgåvor av %(book_title)s" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "Utgåvor av \"%(work_title)s\"" +msgid "Editions of %(work_title)s" +msgstr "" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2805,12 +2805,8 @@ msgstr "Inte en giltig CSV-fil" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" diff --git a/locale/zh_Hans/LC_MESSAGES/django.po b/locale/zh_Hans/LC_MESSAGES/django.po index a3c31e913..77591afa9 100644 --- a/locale/zh_Hans/LC_MESSAGES/django.po +++ b/locale/zh_Hans/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 00:08\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-02 18:13\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Chinese Simplified\n" "Language: zh\n" @@ -1366,8 +1366,8 @@ msgstr "%(book_title)s 的各版本" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "《%(work_title)s》 的各版本" +msgid "Editions of %(work_title)s" +msgstr "" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2795,12 +2795,8 @@ msgstr "" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" #: bookwyrm/templates/import/import.html:27 diff --git a/locale/zh_Hant/LC_MESSAGES/django.po b/locale/zh_Hant/LC_MESSAGES/django.po index a95eebec1..c6f7dc28b 100644 --- a/locale/zh_Hant/LC_MESSAGES/django.po +++ b/locale/zh_Hant/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-27 01:11+0000\n" -"PO-Revision-Date: 2023-09-28 00:08\n" +"POT-Creation-Date: 2023-10-02 16:40+0000\n" +"PO-Revision-Date: 2023-10-29 07:42\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Chinese Traditional\n" "Language: zh\n" @@ -173,7 +173,7 @@ msgstr "" #: bookwyrm/models/book.py:283 msgid "Audiobook" -msgstr "" +msgstr "有聲書" #: bookwyrm/models/book.py:284 msgid "eBook" @@ -181,15 +181,15 @@ msgstr "電子書" #: bookwyrm/models/book.py:285 msgid "Graphic novel" -msgstr "" +msgstr "圖像小說" #: bookwyrm/models/book.py:286 msgid "Hardcover" -msgstr "" +msgstr "精裝書" #: bookwyrm/models/book.py:287 msgid "Paperback" -msgstr "" +msgstr "平裝書" #: bookwyrm/models/federated_server.py:11 #: bookwyrm/templates/settings/federation/edit_instance.html:55 @@ -267,15 +267,15 @@ msgstr "活躍" #: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:172 msgid "Complete" -msgstr "" +msgstr "已完成" #: bookwyrm/models/import_job.py:50 msgid "Stopped" -msgstr "" +msgstr "已停止" #: bookwyrm/models/import_job.py:83 bookwyrm/models/import_job.py:91 msgid "Import stopped" -msgstr "" +msgstr "匯入已停止" #: bookwyrm/models/import_job.py:363 bookwyrm/models/import_job.py:388 msgid "Error loading book" @@ -287,20 +287,20 @@ msgstr "" #: bookwyrm/models/link.py:51 msgid "Free" -msgstr "" +msgstr "免費" #: bookwyrm/models/link.py:52 msgid "Purchasable" -msgstr "" +msgstr "可購買" #: bookwyrm/models/link.py:53 msgid "Available for loan" -msgstr "" +msgstr "可借閱" #: bookwyrm/models/link.py:70 #: bookwyrm/templates/settings/link_domains/link_domains.html:23 msgid "Approved" -msgstr "" +msgstr "已核准" #: bookwyrm/models/report.py:84 #: bookwyrm/templates/settings/reports/report.html:115 @@ -310,11 +310,11 @@ msgstr "評論" #: bookwyrm/models/report.py:85 msgid "Resolved report" -msgstr "" +msgstr "已處理的舉報" #: bookwyrm/models/report.py:86 msgid "Re-opened report" -msgstr "" +msgstr "已重新打開的舉報" #: bookwyrm/models/report.py:87 msgid "Messaged reporter" @@ -358,15 +358,15 @@ msgstr "書評" #: bookwyrm/models/user.py:33 msgid "Comments" -msgstr "" +msgstr "評論" #: bookwyrm/models/user.py:34 msgid "Quotations" -msgstr "" +msgstr "引用" #: bookwyrm/models/user.py:35 msgid "Everything else" -msgstr "" +msgstr "所有其他內容" #: bookwyrm/settings.py:223 msgid "Home Timeline" @@ -378,7 +378,7 @@ msgstr "主頁" #: bookwyrm/settings.py:224 msgid "Books Timeline" -msgstr "" +msgstr "書目時間線" #: bookwyrm/settings.py:224 #: bookwyrm/templates/guided_tour/user_profile.html:101 @@ -394,7 +394,7 @@ msgstr "English(英語)" #: bookwyrm/settings.py:297 msgid "Català (Catalan)" -msgstr "" +msgstr "Català (加泰羅尼亞語)" #: bookwyrm/settings.py:298 msgid "Deutsch (German)" @@ -402,7 +402,7 @@ msgstr "Deutsch(德語)" #: bookwyrm/settings.py:299 msgid "Esperanto (Esperanto)" -msgstr "" +msgstr "Esperanto (世界語)" #: bookwyrm/settings.py:300 msgid "Español (Spanish)" @@ -410,19 +410,19 @@ msgstr "Español(西班牙語)" #: bookwyrm/settings.py:301 msgid "Euskara (Basque)" -msgstr "" +msgstr "Euskara (巴斯克語)" #: bookwyrm/settings.py:302 msgid "Galego (Galician)" -msgstr "" +msgstr "Galego (加利西亞語)" #: bookwyrm/settings.py:303 msgid "Italiano (Italian)" -msgstr "" +msgstr "Italiano (意大利語)" #: bookwyrm/settings.py:304 msgid "Suomi (Finnish)" -msgstr "" +msgstr "Suomi (芬蘭語)" #: bookwyrm/settings.py:305 msgid "Français (French)" @@ -430,35 +430,35 @@ msgstr "Français(法語)" #: bookwyrm/settings.py:306 msgid "Lietuvių (Lithuanian)" -msgstr "" +msgstr "Lietuvių (立陶宛語)" #: bookwyrm/settings.py:307 msgid "Nederlands (Dutch)" -msgstr "" +msgstr "Nederlands (荷蘭語)" #: bookwyrm/settings.py:308 msgid "Norsk (Norwegian)" -msgstr "" +msgstr "Norsk (挪威語)" #: bookwyrm/settings.py:309 msgid "Polski (Polish)" -msgstr "" +msgstr "Polski (波蘭語)" #: bookwyrm/settings.py:310 msgid "Português do Brasil (Brazilian Portuguese)" -msgstr "" +msgstr "Português do Brasil (巴西葡萄牙語)" #: bookwyrm/settings.py:311 msgid "Português Europeu (European Portuguese)" -msgstr "" +msgstr "Português Europeu (歐洲葡萄牙語)" #: bookwyrm/settings.py:312 msgid "Română (Romanian)" -msgstr "" +msgstr "Română (羅馬尼亞語)" #: bookwyrm/settings.py:313 msgid "Svenska (Swedish)" -msgstr "" +msgstr "Svenska (瑞典語)" #: bookwyrm/settings.py:314 msgid "简体中文 (Simplified Chinese)" @@ -491,7 +491,7 @@ msgstr "某些東西出錯了!抱歉。" #: bookwyrm/templates/about/about.html:9 #: bookwyrm/templates/about/layout.html:35 msgid "About" -msgstr "" +msgstr "關於" #: bookwyrm/templates/about/about.html:21 #: bookwyrm/templates/get_started/layout.html:22 @@ -502,12 +502,12 @@ msgstr "歡迎來到 %(site_name)s!" #: bookwyrm/templates/about/about.html:25 #, python-format msgid "%(site_name)s is part of BookWyrm, a network of independent, self-directed communities for readers. While you can interact seamlessly with users anywhere in the BookWyrm network, this community is unique." -msgstr "" +msgstr "%(site_name)s 是 BookWyrm 的一部分,這是一個為讀者建立的獨立、自我導向的社區網絡。雖然您可以在 BookWyrm 網絡中任何地方的用戶無縫互動,但這個社區是獨一無二的。" #: bookwyrm/templates/about/about.html:45 #, python-format msgid "%(title)s is %(site_name)s's most beloved book, with an average rating of %(rating)s out of 5." -msgstr "" +msgstr "%(title)s 是 %(site_name)s 最受歡迎的書,平均得分為 %(rating)s(滿分五分)。" #: bookwyrm/templates/about/about.html:64 #, python-format @@ -703,13 +703,13 @@ msgstr[0] "" #: bookwyrm/templates/annual_summary/layout.html:211 msgid "Way to go!" -msgstr "" +msgstr "還不錯!" #: bookwyrm/templates/annual_summary/layout.html:226 #, python-format msgid "%(display_name)s left %(ratings_total)s rating,
    their average rating is %(rating_average)s" msgid_plural "%(display_name)s left %(ratings_total)s ratings,
    their average rating is %(rating_average)s" -msgstr[0] "" +msgstr[0] "%(display_name)s 留下了 %(ratings_total)s 條評分,
    他的平均評分是 %(rating_average)s" #: bookwyrm/templates/annual_summary/layout.html:240 msgid "Their best rated review" @@ -732,7 +732,7 @@ msgstr "編輯作者" #: bookwyrm/templates/author/author.html:36 msgid "Author details" -msgstr "" +msgstr "作者詳情" #: bookwyrm/templates/author/author.html:40 #: bookwyrm/templates/author/edit_author.html:42 @@ -749,7 +749,7 @@ msgstr "逝世:" #: bookwyrm/templates/author/author.html:66 msgid "External links" -msgstr "" +msgstr "外部連結" #: bookwyrm/templates/author/author.html:71 msgid "Wikipedia" @@ -757,23 +757,23 @@ msgstr "維基百科" #: bookwyrm/templates/author/author.html:79 msgid "Website" -msgstr "" +msgstr "網站" #: bookwyrm/templates/author/author.html:87 msgid "View ISNI record" -msgstr "" +msgstr "查看 ISNI 記錄" #: bookwyrm/templates/author/author.html:95 #: bookwyrm/templates/book/book.html:173 msgid "View on ISFDB" -msgstr "" +msgstr "在 ISFDB 查看" #: bookwyrm/templates/author/author.html:100 #: bookwyrm/templates/author/sync_modal.html:5 #: bookwyrm/templates/book/book.html:140 #: bookwyrm/templates/book/sync_modal.html:5 msgid "Load data" -msgstr "" +msgstr "載入資料" #: bookwyrm/templates/author/author.html:104 #: bookwyrm/templates/book/book.html:144 @@ -787,15 +787,15 @@ msgstr "在 Inventaire 檢視" #: bookwyrm/templates/author/author.html:135 msgid "View on LibraryThing" -msgstr "" +msgstr "在 LibraryThing 查看" #: bookwyrm/templates/author/author.html:143 msgid "View on Goodreads" -msgstr "" +msgstr "在 Goodreads 查看" #: bookwyrm/templates/author/author.html:151 msgid "View ISFDB entry" -msgstr "" +msgstr "查看 ISFDB 條目" #: bookwyrm/templates/author/author.html:166 #, python-format @@ -849,7 +849,7 @@ msgstr "維基百科連結:" #: bookwyrm/templates/author/edit_author.html:60 msgid "Website:" -msgstr "" +msgstr "網站:" #: bookwyrm/templates/author/edit_author.html:65 msgid "Birth date:" @@ -883,11 +883,11 @@ msgstr "Goodreads key:" #: bookwyrm/templates/author/edit_author.html:109 msgid "ISFDB:" -msgstr "" +msgstr "ISFDB:" #: bookwyrm/templates/author/edit_author.html:116 msgid "ISNI:" -msgstr "" +msgstr "ISNI:" #: bookwyrm/templates/author/edit_author.html:126 #: bookwyrm/templates/book/book.html:220 @@ -953,7 +953,7 @@ msgstr "確認" #: bookwyrm/templates/book/book.html:20 msgid "Unable to connect to remote source." -msgstr "" +msgstr "無法連接到遠程數據源。" #: bookwyrm/templates/book/book.html:71 bookwyrm/templates/book/book.html:72 msgid "Edit Book" @@ -961,7 +961,7 @@ msgstr "編輯書目" #: bookwyrm/templates/book/book.html:97 bookwyrm/templates/book/book.html:100 msgid "Click to add cover" -msgstr "" +msgstr "點擊添加封面" #: bookwyrm/templates/book/book.html:106 msgid "Failed to load cover" @@ -969,7 +969,7 @@ msgstr "載入封面失敗" #: bookwyrm/templates/book/book.html:117 msgid "Click to enlarge" -msgstr "" +msgstr "點擊放大" #: bookwyrm/templates/book/book.html:196 #, python-format @@ -991,7 +991,7 @@ msgstr "描述:" #, python-format msgid "%(count)s edition" msgid_plural "%(count)s editions" -msgstr[0] "" +msgstr[0] "%(count)s 版次" #: bookwyrm/templates/book/book.html:246 msgid "You have shelved this edition in:" @@ -1070,11 +1070,11 @@ msgstr "ISBN:" #: bookwyrm/templates/book/book_identifiers.html:12 #: bookwyrm/templates/book/book_identifiers.html:13 msgid "Copy ISBN" -msgstr "" +msgstr "複製ISBN" #: bookwyrm/templates/book/book_identifiers.html:16 msgid "Copied ISBN!" -msgstr "" +msgstr "已複製ISBN!" #: bookwyrm/templates/book/book_identifiers.html:23 #: bookwyrm/templates/book/edit/edit_book_form.html:352 @@ -1089,16 +1089,16 @@ msgstr "ASIN:" #: bookwyrm/templates/book/book_identifiers.html:37 #: bookwyrm/templates/book/edit/edit_book_form.html:370 msgid "Audible ASIN:" -msgstr "" +msgstr "Audible ASIN:" #: bookwyrm/templates/book/book_identifiers.html:44 #: bookwyrm/templates/book/edit/edit_book_form.html:379 msgid "ISFDB ID:" -msgstr "" +msgstr "ISFDB ID:" #: bookwyrm/templates/book/book_identifiers.html:51 msgid "Goodreads:" -msgstr "" +msgstr "Goodreads:" #: bookwyrm/templates/book/cover_add_modal.html:5 msgid "Add cover" @@ -1116,7 +1116,7 @@ msgstr "從網址載入封面:" #: bookwyrm/templates/book/cover_show_modal.html:6 msgid "Book cover preview" -msgstr "" +msgstr "書籍封面預覽" #: bookwyrm/templates/book/cover_show_modal.html:11 #: bookwyrm/templates/components/inline_form.html:8 @@ -1310,16 +1310,16 @@ msgstr "新增作者:" #: bookwyrm/templates/book/edit/edit_book_form.html:211 #: bookwyrm/templates/book/edit/edit_book_form.html:214 msgid "Add Author" -msgstr "" +msgstr "新增作者" #: bookwyrm/templates/book/edit/edit_book_form.html:212 #: bookwyrm/templates/book/edit/edit_book_form.html:215 msgid "Jane Doe" -msgstr "" +msgstr "陳大文" #: bookwyrm/templates/book/edit/edit_book_form.html:221 msgid "Add Another Author" -msgstr "" +msgstr "新增其他作者" #: bookwyrm/templates/book/edit/edit_book_form.html:231 #: bookwyrm/templates/shelf/shelf.html:147 @@ -1337,7 +1337,7 @@ msgstr "格式:" #: bookwyrm/templates/book/edit/edit_book_form.html:280 msgid "Format details:" -msgstr "" +msgstr "裝訂詳情:" #: bookwyrm/templates/book/edit/edit_book_form.html:291 msgid "Pages:" @@ -1366,8 +1366,8 @@ msgstr "%(book_title)s 的各版本" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format -msgid "Editions of \"%(work_title)s\"" -msgstr "\"%(work_title)s\" 的各版本" +msgid "Editions of %(work_title)s" +msgstr "" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -2795,12 +2795,8 @@ msgstr "" #: bookwyrm/templates/import/import.html:21 #, python-format -msgid "\n" -" Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day.\n" -" " -msgid_plural "\n" -" Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days.\n" -" " +msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." +msgid_plural "Currently, you are allowed to import %(import_size_limit)s books every %(import_limit_reset)s days." msgstr[0] "" #: bookwyrm/templates/import/import.html:27 diff --git a/requirements.txt b/requirements.txt index 0602f8da4..b01e110bf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ aiohttp==3.8.5 bleach==5.0.1 celery==5.2.7 colorthief==0.2.1 -Django==3.2.20 +Django==3.2.23 django-celery-beat==2.4.0 django-compressor==4.3.1 django-imagekit==4.1.0