diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py
index c112186ae..298f73da9 100644
--- a/bookwyrm/forms.py
+++ b/bookwyrm/forms.py
@@ -293,7 +293,13 @@ class AnnouncementForm(CustomForm):
class ListForm(CustomForm):
class Meta:
model = models.List
- fields = ["user", "name", "description", "curation", "privacy"]
+ fields = ["user", "name", "description", "curation", "privacy", "group"]
+
+
+class GroupForm(CustomForm):
+ class Meta:
+ model = models.Group
+ fields = ["user", "privacy", "name", "description"]
class ReportForm(CustomForm):
diff --git a/bookwyrm/importers/goodreads_import.py b/bookwyrm/importers/goodreads_import.py
index 7b577ea85..c62e65827 100644
--- a/bookwyrm/importers/goodreads_import.py
+++ b/bookwyrm/importers/goodreads_import.py
@@ -3,10 +3,10 @@ from . import Importer
class GoodreadsImporter(Importer):
- """GoodReads is the default importer, thus Importer follows its structure.
+ """Goodreads is the default importer, thus Importer follows its structure.
For a more complete example of overriding see librarything_import.py"""
- service = "GoodReads"
+ service = "Goodreads"
def parse_fields(self, entry):
"""handle the specific fields in goodreads csvs"""
diff --git a/bookwyrm/importers/importer.py b/bookwyrm/importers/importer.py
index a10b4060c..6d898a2a3 100644
--- a/bookwyrm/importers/importer.py
+++ b/bookwyrm/importers/importer.py
@@ -1,4 +1,4 @@
-""" handle reading a csv from an external service, defaults are from GoodReads """
+""" handle reading a csv from an external service, defaults are from Goodreads """
import csv
import logging
diff --git a/bookwyrm/migrations/0107_auto_20211016_0639.py b/bookwyrm/migrations/0107_auto_20211016_0639.py
new file mode 100644
index 000000000..61dffca34
--- /dev/null
+++ b/bookwyrm/migrations/0107_auto_20211016_0639.py
@@ -0,0 +1,871 @@
+# Generated by Django 3.2.5 on 2021-10-16 06:39
+
+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", "0106_user_preferred_language"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="Group",
+ 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],
+ ),
+ ),
+ ("name", bookwyrm.models.fields.CharField(max_length=100)),
+ (
+ "description",
+ bookwyrm.models.fields.TextField(blank=True, null=True),
+ ),
+ (
+ "privacy",
+ bookwyrm.models.fields.PrivacyField(
+ choices=[
+ ("public", "Public"),
+ ("unlisted", "Unlisted"),
+ ("followers", "Followers"),
+ ("direct", "Direct"),
+ ],
+ default="public",
+ max_length=255,
+ ),
+ ),
+ ],
+ options={
+ "abstract": False,
+ },
+ ),
+ migrations.CreateModel(
+ name="GroupMember",
+ 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)),
+ ],
+ ),
+ migrations.CreateModel(
+ name="GroupMemberInvitation",
+ fields=[
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("created_date", models.DateTimeField(auto_now_add=True)),
+ ],
+ ),
+ migrations.RemoveConstraint(
+ model_name="notification",
+ name="notification_type_valid",
+ ),
+ migrations.AlterField(
+ model_name="list",
+ name="curation",
+ field=bookwyrm.models.fields.CharField(
+ choices=[
+ ("closed", "Closed"),
+ ("open", "Open"),
+ ("curated", "Curated"),
+ ("group", "Group"),
+ ],
+ default="closed",
+ max_length=255,
+ ),
+ ),
+ 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"),
+ ("INVITE", "Invite"),
+ ("ACCEPT", "Accept"),
+ ("JOIN", "Join"),
+ ("LEAVE", "Leave"),
+ ("REMOVE", "Remove"),
+ ],
+ max_length=255,
+ ),
+ ),
+ migrations.AlterField(
+ model_name="user",
+ name="preferred_language",
+ field=models.CharField(
+ blank=True,
+ choices=[
+ ("en-us", "English"),
+ ("de-de", "Deutsch (German)"),
+ ("es", "Español (Spanish)"),
+ ("fr-fr", "Français (French)"),
+ ("zh-hans", "简体中文 (Simplified Chinese)"),
+ ("zh-hant", "繁體中文 (Traditional Chinese)"),
+ ],
+ max_length=255,
+ null=True,
+ ),
+ ),
+ migrations.AlterField(
+ model_name="user",
+ name="preferred_timezone",
+ field=models.CharField(
+ choices=[
+ ("Africa/Abidjan", "Africa/Abidjan"),
+ ("Africa/Accra", "Africa/Accra"),
+ ("Africa/Addis_Ababa", "Africa/Addis_Ababa"),
+ ("Africa/Algiers", "Africa/Algiers"),
+ ("Africa/Asmara", "Africa/Asmara"),
+ ("Africa/Asmera", "Africa/Asmera"),
+ ("Africa/Bamako", "Africa/Bamako"),
+ ("Africa/Bangui", "Africa/Bangui"),
+ ("Africa/Banjul", "Africa/Banjul"),
+ ("Africa/Bissau", "Africa/Bissau"),
+ ("Africa/Blantyre", "Africa/Blantyre"),
+ ("Africa/Brazzaville", "Africa/Brazzaville"),
+ ("Africa/Bujumbura", "Africa/Bujumbura"),
+ ("Africa/Cairo", "Africa/Cairo"),
+ ("Africa/Casablanca", "Africa/Casablanca"),
+ ("Africa/Ceuta", "Africa/Ceuta"),
+ ("Africa/Conakry", "Africa/Conakry"),
+ ("Africa/Dakar", "Africa/Dakar"),
+ ("Africa/Dar_es_Salaam", "Africa/Dar_es_Salaam"),
+ ("Africa/Djibouti", "Africa/Djibouti"),
+ ("Africa/Douala", "Africa/Douala"),
+ ("Africa/El_Aaiun", "Africa/El_Aaiun"),
+ ("Africa/Freetown", "Africa/Freetown"),
+ ("Africa/Gaborone", "Africa/Gaborone"),
+ ("Africa/Harare", "Africa/Harare"),
+ ("Africa/Johannesburg", "Africa/Johannesburg"),
+ ("Africa/Juba", "Africa/Juba"),
+ ("Africa/Kampala", "Africa/Kampala"),
+ ("Africa/Khartoum", "Africa/Khartoum"),
+ ("Africa/Kigali", "Africa/Kigali"),
+ ("Africa/Kinshasa", "Africa/Kinshasa"),
+ ("Africa/Lagos", "Africa/Lagos"),
+ ("Africa/Libreville", "Africa/Libreville"),
+ ("Africa/Lome", "Africa/Lome"),
+ ("Africa/Luanda", "Africa/Luanda"),
+ ("Africa/Lubumbashi", "Africa/Lubumbashi"),
+ ("Africa/Lusaka", "Africa/Lusaka"),
+ ("Africa/Malabo", "Africa/Malabo"),
+ ("Africa/Maputo", "Africa/Maputo"),
+ ("Africa/Maseru", "Africa/Maseru"),
+ ("Africa/Mbabane", "Africa/Mbabane"),
+ ("Africa/Mogadishu", "Africa/Mogadishu"),
+ ("Africa/Monrovia", "Africa/Monrovia"),
+ ("Africa/Nairobi", "Africa/Nairobi"),
+ ("Africa/Ndjamena", "Africa/Ndjamena"),
+ ("Africa/Niamey", "Africa/Niamey"),
+ ("Africa/Nouakchott", "Africa/Nouakchott"),
+ ("Africa/Ouagadougou", "Africa/Ouagadougou"),
+ ("Africa/Porto-Novo", "Africa/Porto-Novo"),
+ ("Africa/Sao_Tome", "Africa/Sao_Tome"),
+ ("Africa/Timbuktu", "Africa/Timbuktu"),
+ ("Africa/Tripoli", "Africa/Tripoli"),
+ ("Africa/Tunis", "Africa/Tunis"),
+ ("Africa/Windhoek", "Africa/Windhoek"),
+ ("America/Adak", "America/Adak"),
+ ("America/Anchorage", "America/Anchorage"),
+ ("America/Anguilla", "America/Anguilla"),
+ ("America/Antigua", "America/Antigua"),
+ ("America/Araguaina", "America/Araguaina"),
+ (
+ "America/Argentina/Buenos_Aires",
+ "America/Argentina/Buenos_Aires",
+ ),
+ ("America/Argentina/Catamarca", "America/Argentina/Catamarca"),
+ (
+ "America/Argentina/ComodRivadavia",
+ "America/Argentina/ComodRivadavia",
+ ),
+ ("America/Argentina/Cordoba", "America/Argentina/Cordoba"),
+ ("America/Argentina/Jujuy", "America/Argentina/Jujuy"),
+ ("America/Argentina/La_Rioja", "America/Argentina/La_Rioja"),
+ ("America/Argentina/Mendoza", "America/Argentina/Mendoza"),
+ (
+ "America/Argentina/Rio_Gallegos",
+ "America/Argentina/Rio_Gallegos",
+ ),
+ ("America/Argentina/Salta", "America/Argentina/Salta"),
+ ("America/Argentina/San_Juan", "America/Argentina/San_Juan"),
+ ("America/Argentina/San_Luis", "America/Argentina/San_Luis"),
+ ("America/Argentina/Tucuman", "America/Argentina/Tucuman"),
+ ("America/Argentina/Ushuaia", "America/Argentina/Ushuaia"),
+ ("America/Aruba", "America/Aruba"),
+ ("America/Asuncion", "America/Asuncion"),
+ ("America/Atikokan", "America/Atikokan"),
+ ("America/Atka", "America/Atka"),
+ ("America/Bahia", "America/Bahia"),
+ ("America/Bahia_Banderas", "America/Bahia_Banderas"),
+ ("America/Barbados", "America/Barbados"),
+ ("America/Belem", "America/Belem"),
+ ("America/Belize", "America/Belize"),
+ ("America/Blanc-Sablon", "America/Blanc-Sablon"),
+ ("America/Boa_Vista", "America/Boa_Vista"),
+ ("America/Bogota", "America/Bogota"),
+ ("America/Boise", "America/Boise"),
+ ("America/Buenos_Aires", "America/Buenos_Aires"),
+ ("America/Cambridge_Bay", "America/Cambridge_Bay"),
+ ("America/Campo_Grande", "America/Campo_Grande"),
+ ("America/Cancun", "America/Cancun"),
+ ("America/Caracas", "America/Caracas"),
+ ("America/Catamarca", "America/Catamarca"),
+ ("America/Cayenne", "America/Cayenne"),
+ ("America/Cayman", "America/Cayman"),
+ ("America/Chicago", "America/Chicago"),
+ ("America/Chihuahua", "America/Chihuahua"),
+ ("America/Coral_Harbour", "America/Coral_Harbour"),
+ ("America/Cordoba", "America/Cordoba"),
+ ("America/Costa_Rica", "America/Costa_Rica"),
+ ("America/Creston", "America/Creston"),
+ ("America/Cuiaba", "America/Cuiaba"),
+ ("America/Curacao", "America/Curacao"),
+ ("America/Danmarkshavn", "America/Danmarkshavn"),
+ ("America/Dawson", "America/Dawson"),
+ ("America/Dawson_Creek", "America/Dawson_Creek"),
+ ("America/Denver", "America/Denver"),
+ ("America/Detroit", "America/Detroit"),
+ ("America/Dominica", "America/Dominica"),
+ ("America/Edmonton", "America/Edmonton"),
+ ("America/Eirunepe", "America/Eirunepe"),
+ ("America/El_Salvador", "America/El_Salvador"),
+ ("America/Ensenada", "America/Ensenada"),
+ ("America/Fort_Nelson", "America/Fort_Nelson"),
+ ("America/Fort_Wayne", "America/Fort_Wayne"),
+ ("America/Fortaleza", "America/Fortaleza"),
+ ("America/Glace_Bay", "America/Glace_Bay"),
+ ("America/Godthab", "America/Godthab"),
+ ("America/Goose_Bay", "America/Goose_Bay"),
+ ("America/Grand_Turk", "America/Grand_Turk"),
+ ("America/Grenada", "America/Grenada"),
+ ("America/Guadeloupe", "America/Guadeloupe"),
+ ("America/Guatemala", "America/Guatemala"),
+ ("America/Guayaquil", "America/Guayaquil"),
+ ("America/Guyana", "America/Guyana"),
+ ("America/Halifax", "America/Halifax"),
+ ("America/Havana", "America/Havana"),
+ ("America/Hermosillo", "America/Hermosillo"),
+ ("America/Indiana/Indianapolis", "America/Indiana/Indianapolis"),
+ ("America/Indiana/Knox", "America/Indiana/Knox"),
+ ("America/Indiana/Marengo", "America/Indiana/Marengo"),
+ ("America/Indiana/Petersburg", "America/Indiana/Petersburg"),
+ ("America/Indiana/Tell_City", "America/Indiana/Tell_City"),
+ ("America/Indiana/Vevay", "America/Indiana/Vevay"),
+ ("America/Indiana/Vincennes", "America/Indiana/Vincennes"),
+ ("America/Indiana/Winamac", "America/Indiana/Winamac"),
+ ("America/Indianapolis", "America/Indianapolis"),
+ ("America/Inuvik", "America/Inuvik"),
+ ("America/Iqaluit", "America/Iqaluit"),
+ ("America/Jamaica", "America/Jamaica"),
+ ("America/Jujuy", "America/Jujuy"),
+ ("America/Juneau", "America/Juneau"),
+ ("America/Kentucky/Louisville", "America/Kentucky/Louisville"),
+ ("America/Kentucky/Monticello", "America/Kentucky/Monticello"),
+ ("America/Knox_IN", "America/Knox_IN"),
+ ("America/Kralendijk", "America/Kralendijk"),
+ ("America/La_Paz", "America/La_Paz"),
+ ("America/Lima", "America/Lima"),
+ ("America/Los_Angeles", "America/Los_Angeles"),
+ ("America/Louisville", "America/Louisville"),
+ ("America/Lower_Princes", "America/Lower_Princes"),
+ ("America/Maceio", "America/Maceio"),
+ ("America/Managua", "America/Managua"),
+ ("America/Manaus", "America/Manaus"),
+ ("America/Marigot", "America/Marigot"),
+ ("America/Martinique", "America/Martinique"),
+ ("America/Matamoros", "America/Matamoros"),
+ ("America/Mazatlan", "America/Mazatlan"),
+ ("America/Mendoza", "America/Mendoza"),
+ ("America/Menominee", "America/Menominee"),
+ ("America/Merida", "America/Merida"),
+ ("America/Metlakatla", "America/Metlakatla"),
+ ("America/Mexico_City", "America/Mexico_City"),
+ ("America/Miquelon", "America/Miquelon"),
+ ("America/Moncton", "America/Moncton"),
+ ("America/Monterrey", "America/Monterrey"),
+ ("America/Montevideo", "America/Montevideo"),
+ ("America/Montreal", "America/Montreal"),
+ ("America/Montserrat", "America/Montserrat"),
+ ("America/Nassau", "America/Nassau"),
+ ("America/New_York", "America/New_York"),
+ ("America/Nipigon", "America/Nipigon"),
+ ("America/Nome", "America/Nome"),
+ ("America/Noronha", "America/Noronha"),
+ ("America/North_Dakota/Beulah", "America/North_Dakota/Beulah"),
+ ("America/North_Dakota/Center", "America/North_Dakota/Center"),
+ (
+ "America/North_Dakota/New_Salem",
+ "America/North_Dakota/New_Salem",
+ ),
+ ("America/Nuuk", "America/Nuuk"),
+ ("America/Ojinaga", "America/Ojinaga"),
+ ("America/Panama", "America/Panama"),
+ ("America/Pangnirtung", "America/Pangnirtung"),
+ ("America/Paramaribo", "America/Paramaribo"),
+ ("America/Phoenix", "America/Phoenix"),
+ ("America/Port-au-Prince", "America/Port-au-Prince"),
+ ("America/Port_of_Spain", "America/Port_of_Spain"),
+ ("America/Porto_Acre", "America/Porto_Acre"),
+ ("America/Porto_Velho", "America/Porto_Velho"),
+ ("America/Puerto_Rico", "America/Puerto_Rico"),
+ ("America/Punta_Arenas", "America/Punta_Arenas"),
+ ("America/Rainy_River", "America/Rainy_River"),
+ ("America/Rankin_Inlet", "America/Rankin_Inlet"),
+ ("America/Recife", "America/Recife"),
+ ("America/Regina", "America/Regina"),
+ ("America/Resolute", "America/Resolute"),
+ ("America/Rio_Branco", "America/Rio_Branco"),
+ ("America/Rosario", "America/Rosario"),
+ ("America/Santa_Isabel", "America/Santa_Isabel"),
+ ("America/Santarem", "America/Santarem"),
+ ("America/Santiago", "America/Santiago"),
+ ("America/Santo_Domingo", "America/Santo_Domingo"),
+ ("America/Sao_Paulo", "America/Sao_Paulo"),
+ ("America/Scoresbysund", "America/Scoresbysund"),
+ ("America/Shiprock", "America/Shiprock"),
+ ("America/Sitka", "America/Sitka"),
+ ("America/St_Barthelemy", "America/St_Barthelemy"),
+ ("America/St_Johns", "America/St_Johns"),
+ ("America/St_Kitts", "America/St_Kitts"),
+ ("America/St_Lucia", "America/St_Lucia"),
+ ("America/St_Thomas", "America/St_Thomas"),
+ ("America/St_Vincent", "America/St_Vincent"),
+ ("America/Swift_Current", "America/Swift_Current"),
+ ("America/Tegucigalpa", "America/Tegucigalpa"),
+ ("America/Thule", "America/Thule"),
+ ("America/Thunder_Bay", "America/Thunder_Bay"),
+ ("America/Tijuana", "America/Tijuana"),
+ ("America/Toronto", "America/Toronto"),
+ ("America/Tortola", "America/Tortola"),
+ ("America/Vancouver", "America/Vancouver"),
+ ("America/Virgin", "America/Virgin"),
+ ("America/Whitehorse", "America/Whitehorse"),
+ ("America/Winnipeg", "America/Winnipeg"),
+ ("America/Yakutat", "America/Yakutat"),
+ ("America/Yellowknife", "America/Yellowknife"),
+ ("Antarctica/Casey", "Antarctica/Casey"),
+ ("Antarctica/Davis", "Antarctica/Davis"),
+ ("Antarctica/DumontDUrville", "Antarctica/DumontDUrville"),
+ ("Antarctica/Macquarie", "Antarctica/Macquarie"),
+ ("Antarctica/Mawson", "Antarctica/Mawson"),
+ ("Antarctica/McMurdo", "Antarctica/McMurdo"),
+ ("Antarctica/Palmer", "Antarctica/Palmer"),
+ ("Antarctica/Rothera", "Antarctica/Rothera"),
+ ("Antarctica/South_Pole", "Antarctica/South_Pole"),
+ ("Antarctica/Syowa", "Antarctica/Syowa"),
+ ("Antarctica/Troll", "Antarctica/Troll"),
+ ("Antarctica/Vostok", "Antarctica/Vostok"),
+ ("Arctic/Longyearbyen", "Arctic/Longyearbyen"),
+ ("Asia/Aden", "Asia/Aden"),
+ ("Asia/Almaty", "Asia/Almaty"),
+ ("Asia/Amman", "Asia/Amman"),
+ ("Asia/Anadyr", "Asia/Anadyr"),
+ ("Asia/Aqtau", "Asia/Aqtau"),
+ ("Asia/Aqtobe", "Asia/Aqtobe"),
+ ("Asia/Ashgabat", "Asia/Ashgabat"),
+ ("Asia/Ashkhabad", "Asia/Ashkhabad"),
+ ("Asia/Atyrau", "Asia/Atyrau"),
+ ("Asia/Baghdad", "Asia/Baghdad"),
+ ("Asia/Bahrain", "Asia/Bahrain"),
+ ("Asia/Baku", "Asia/Baku"),
+ ("Asia/Bangkok", "Asia/Bangkok"),
+ ("Asia/Barnaul", "Asia/Barnaul"),
+ ("Asia/Beirut", "Asia/Beirut"),
+ ("Asia/Bishkek", "Asia/Bishkek"),
+ ("Asia/Brunei", "Asia/Brunei"),
+ ("Asia/Calcutta", "Asia/Calcutta"),
+ ("Asia/Chita", "Asia/Chita"),
+ ("Asia/Choibalsan", "Asia/Choibalsan"),
+ ("Asia/Chongqing", "Asia/Chongqing"),
+ ("Asia/Chungking", "Asia/Chungking"),
+ ("Asia/Colombo", "Asia/Colombo"),
+ ("Asia/Dacca", "Asia/Dacca"),
+ ("Asia/Damascus", "Asia/Damascus"),
+ ("Asia/Dhaka", "Asia/Dhaka"),
+ ("Asia/Dili", "Asia/Dili"),
+ ("Asia/Dubai", "Asia/Dubai"),
+ ("Asia/Dushanbe", "Asia/Dushanbe"),
+ ("Asia/Famagusta", "Asia/Famagusta"),
+ ("Asia/Gaza", "Asia/Gaza"),
+ ("Asia/Harbin", "Asia/Harbin"),
+ ("Asia/Hebron", "Asia/Hebron"),
+ ("Asia/Ho_Chi_Minh", "Asia/Ho_Chi_Minh"),
+ ("Asia/Hong_Kong", "Asia/Hong_Kong"),
+ ("Asia/Hovd", "Asia/Hovd"),
+ ("Asia/Irkutsk", "Asia/Irkutsk"),
+ ("Asia/Istanbul", "Asia/Istanbul"),
+ ("Asia/Jakarta", "Asia/Jakarta"),
+ ("Asia/Jayapura", "Asia/Jayapura"),
+ ("Asia/Jerusalem", "Asia/Jerusalem"),
+ ("Asia/Kabul", "Asia/Kabul"),
+ ("Asia/Kamchatka", "Asia/Kamchatka"),
+ ("Asia/Karachi", "Asia/Karachi"),
+ ("Asia/Kashgar", "Asia/Kashgar"),
+ ("Asia/Kathmandu", "Asia/Kathmandu"),
+ ("Asia/Katmandu", "Asia/Katmandu"),
+ ("Asia/Khandyga", "Asia/Khandyga"),
+ ("Asia/Kolkata", "Asia/Kolkata"),
+ ("Asia/Krasnoyarsk", "Asia/Krasnoyarsk"),
+ ("Asia/Kuala_Lumpur", "Asia/Kuala_Lumpur"),
+ ("Asia/Kuching", "Asia/Kuching"),
+ ("Asia/Kuwait", "Asia/Kuwait"),
+ ("Asia/Macao", "Asia/Macao"),
+ ("Asia/Macau", "Asia/Macau"),
+ ("Asia/Magadan", "Asia/Magadan"),
+ ("Asia/Makassar", "Asia/Makassar"),
+ ("Asia/Manila", "Asia/Manila"),
+ ("Asia/Muscat", "Asia/Muscat"),
+ ("Asia/Nicosia", "Asia/Nicosia"),
+ ("Asia/Novokuznetsk", "Asia/Novokuznetsk"),
+ ("Asia/Novosibirsk", "Asia/Novosibirsk"),
+ ("Asia/Omsk", "Asia/Omsk"),
+ ("Asia/Oral", "Asia/Oral"),
+ ("Asia/Phnom_Penh", "Asia/Phnom_Penh"),
+ ("Asia/Pontianak", "Asia/Pontianak"),
+ ("Asia/Pyongyang", "Asia/Pyongyang"),
+ ("Asia/Qatar", "Asia/Qatar"),
+ ("Asia/Qostanay", "Asia/Qostanay"),
+ ("Asia/Qyzylorda", "Asia/Qyzylorda"),
+ ("Asia/Rangoon", "Asia/Rangoon"),
+ ("Asia/Riyadh", "Asia/Riyadh"),
+ ("Asia/Saigon", "Asia/Saigon"),
+ ("Asia/Sakhalin", "Asia/Sakhalin"),
+ ("Asia/Samarkand", "Asia/Samarkand"),
+ ("Asia/Seoul", "Asia/Seoul"),
+ ("Asia/Shanghai", "Asia/Shanghai"),
+ ("Asia/Singapore", "Asia/Singapore"),
+ ("Asia/Srednekolymsk", "Asia/Srednekolymsk"),
+ ("Asia/Taipei", "Asia/Taipei"),
+ ("Asia/Tashkent", "Asia/Tashkent"),
+ ("Asia/Tbilisi", "Asia/Tbilisi"),
+ ("Asia/Tehran", "Asia/Tehran"),
+ ("Asia/Tel_Aviv", "Asia/Tel_Aviv"),
+ ("Asia/Thimbu", "Asia/Thimbu"),
+ ("Asia/Thimphu", "Asia/Thimphu"),
+ ("Asia/Tokyo", "Asia/Tokyo"),
+ ("Asia/Tomsk", "Asia/Tomsk"),
+ ("Asia/Ujung_Pandang", "Asia/Ujung_Pandang"),
+ ("Asia/Ulaanbaatar", "Asia/Ulaanbaatar"),
+ ("Asia/Ulan_Bator", "Asia/Ulan_Bator"),
+ ("Asia/Urumqi", "Asia/Urumqi"),
+ ("Asia/Ust-Nera", "Asia/Ust-Nera"),
+ ("Asia/Vientiane", "Asia/Vientiane"),
+ ("Asia/Vladivostok", "Asia/Vladivostok"),
+ ("Asia/Yakutsk", "Asia/Yakutsk"),
+ ("Asia/Yangon", "Asia/Yangon"),
+ ("Asia/Yekaterinburg", "Asia/Yekaterinburg"),
+ ("Asia/Yerevan", "Asia/Yerevan"),
+ ("Atlantic/Azores", "Atlantic/Azores"),
+ ("Atlantic/Bermuda", "Atlantic/Bermuda"),
+ ("Atlantic/Canary", "Atlantic/Canary"),
+ ("Atlantic/Cape_Verde", "Atlantic/Cape_Verde"),
+ ("Atlantic/Faeroe", "Atlantic/Faeroe"),
+ ("Atlantic/Faroe", "Atlantic/Faroe"),
+ ("Atlantic/Jan_Mayen", "Atlantic/Jan_Mayen"),
+ ("Atlantic/Madeira", "Atlantic/Madeira"),
+ ("Atlantic/Reykjavik", "Atlantic/Reykjavik"),
+ ("Atlantic/South_Georgia", "Atlantic/South_Georgia"),
+ ("Atlantic/St_Helena", "Atlantic/St_Helena"),
+ ("Atlantic/Stanley", "Atlantic/Stanley"),
+ ("Australia/ACT", "Australia/ACT"),
+ ("Australia/Adelaide", "Australia/Adelaide"),
+ ("Australia/Brisbane", "Australia/Brisbane"),
+ ("Australia/Broken_Hill", "Australia/Broken_Hill"),
+ ("Australia/Canberra", "Australia/Canberra"),
+ ("Australia/Currie", "Australia/Currie"),
+ ("Australia/Darwin", "Australia/Darwin"),
+ ("Australia/Eucla", "Australia/Eucla"),
+ ("Australia/Hobart", "Australia/Hobart"),
+ ("Australia/LHI", "Australia/LHI"),
+ ("Australia/Lindeman", "Australia/Lindeman"),
+ ("Australia/Lord_Howe", "Australia/Lord_Howe"),
+ ("Australia/Melbourne", "Australia/Melbourne"),
+ ("Australia/NSW", "Australia/NSW"),
+ ("Australia/North", "Australia/North"),
+ ("Australia/Perth", "Australia/Perth"),
+ ("Australia/Queensland", "Australia/Queensland"),
+ ("Australia/South", "Australia/South"),
+ ("Australia/Sydney", "Australia/Sydney"),
+ ("Australia/Tasmania", "Australia/Tasmania"),
+ ("Australia/Victoria", "Australia/Victoria"),
+ ("Australia/West", "Australia/West"),
+ ("Australia/Yancowinna", "Australia/Yancowinna"),
+ ("Brazil/Acre", "Brazil/Acre"),
+ ("Brazil/DeNoronha", "Brazil/DeNoronha"),
+ ("Brazil/East", "Brazil/East"),
+ ("Brazil/West", "Brazil/West"),
+ ("CET", "CET"),
+ ("CST6CDT", "CST6CDT"),
+ ("Canada/Atlantic", "Canada/Atlantic"),
+ ("Canada/Central", "Canada/Central"),
+ ("Canada/Eastern", "Canada/Eastern"),
+ ("Canada/Mountain", "Canada/Mountain"),
+ ("Canada/Newfoundland", "Canada/Newfoundland"),
+ ("Canada/Pacific", "Canada/Pacific"),
+ ("Canada/Saskatchewan", "Canada/Saskatchewan"),
+ ("Canada/Yukon", "Canada/Yukon"),
+ ("Chile/Continental", "Chile/Continental"),
+ ("Chile/EasterIsland", "Chile/EasterIsland"),
+ ("Cuba", "Cuba"),
+ ("EET", "EET"),
+ ("EST", "EST"),
+ ("EST5EDT", "EST5EDT"),
+ ("Egypt", "Egypt"),
+ ("Eire", "Eire"),
+ ("Etc/GMT", "Etc/GMT"),
+ ("Etc/GMT+0", "Etc/GMT+0"),
+ ("Etc/GMT+1", "Etc/GMT+1"),
+ ("Etc/GMT+10", "Etc/GMT+10"),
+ ("Etc/GMT+11", "Etc/GMT+11"),
+ ("Etc/GMT+12", "Etc/GMT+12"),
+ ("Etc/GMT+2", "Etc/GMT+2"),
+ ("Etc/GMT+3", "Etc/GMT+3"),
+ ("Etc/GMT+4", "Etc/GMT+4"),
+ ("Etc/GMT+5", "Etc/GMT+5"),
+ ("Etc/GMT+6", "Etc/GMT+6"),
+ ("Etc/GMT+7", "Etc/GMT+7"),
+ ("Etc/GMT+8", "Etc/GMT+8"),
+ ("Etc/GMT+9", "Etc/GMT+9"),
+ ("Etc/GMT-0", "Etc/GMT-0"),
+ ("Etc/GMT-1", "Etc/GMT-1"),
+ ("Etc/GMT-10", "Etc/GMT-10"),
+ ("Etc/GMT-11", "Etc/GMT-11"),
+ ("Etc/GMT-12", "Etc/GMT-12"),
+ ("Etc/GMT-13", "Etc/GMT-13"),
+ ("Etc/GMT-14", "Etc/GMT-14"),
+ ("Etc/GMT-2", "Etc/GMT-2"),
+ ("Etc/GMT-3", "Etc/GMT-3"),
+ ("Etc/GMT-4", "Etc/GMT-4"),
+ ("Etc/GMT-5", "Etc/GMT-5"),
+ ("Etc/GMT-6", "Etc/GMT-6"),
+ ("Etc/GMT-7", "Etc/GMT-7"),
+ ("Etc/GMT-8", "Etc/GMT-8"),
+ ("Etc/GMT-9", "Etc/GMT-9"),
+ ("Etc/GMT0", "Etc/GMT0"),
+ ("Etc/Greenwich", "Etc/Greenwich"),
+ ("Etc/UCT", "Etc/UCT"),
+ ("Etc/UTC", "Etc/UTC"),
+ ("Etc/Universal", "Etc/Universal"),
+ ("Etc/Zulu", "Etc/Zulu"),
+ ("Europe/Amsterdam", "Europe/Amsterdam"),
+ ("Europe/Andorra", "Europe/Andorra"),
+ ("Europe/Astrakhan", "Europe/Astrakhan"),
+ ("Europe/Athens", "Europe/Athens"),
+ ("Europe/Belfast", "Europe/Belfast"),
+ ("Europe/Belgrade", "Europe/Belgrade"),
+ ("Europe/Berlin", "Europe/Berlin"),
+ ("Europe/Bratislava", "Europe/Bratislava"),
+ ("Europe/Brussels", "Europe/Brussels"),
+ ("Europe/Bucharest", "Europe/Bucharest"),
+ ("Europe/Budapest", "Europe/Budapest"),
+ ("Europe/Busingen", "Europe/Busingen"),
+ ("Europe/Chisinau", "Europe/Chisinau"),
+ ("Europe/Copenhagen", "Europe/Copenhagen"),
+ ("Europe/Dublin", "Europe/Dublin"),
+ ("Europe/Gibraltar", "Europe/Gibraltar"),
+ ("Europe/Guernsey", "Europe/Guernsey"),
+ ("Europe/Helsinki", "Europe/Helsinki"),
+ ("Europe/Isle_of_Man", "Europe/Isle_of_Man"),
+ ("Europe/Istanbul", "Europe/Istanbul"),
+ ("Europe/Jersey", "Europe/Jersey"),
+ ("Europe/Kaliningrad", "Europe/Kaliningrad"),
+ ("Europe/Kiev", "Europe/Kiev"),
+ ("Europe/Kirov", "Europe/Kirov"),
+ ("Europe/Lisbon", "Europe/Lisbon"),
+ ("Europe/Ljubljana", "Europe/Ljubljana"),
+ ("Europe/London", "Europe/London"),
+ ("Europe/Luxembourg", "Europe/Luxembourg"),
+ ("Europe/Madrid", "Europe/Madrid"),
+ ("Europe/Malta", "Europe/Malta"),
+ ("Europe/Mariehamn", "Europe/Mariehamn"),
+ ("Europe/Minsk", "Europe/Minsk"),
+ ("Europe/Monaco", "Europe/Monaco"),
+ ("Europe/Moscow", "Europe/Moscow"),
+ ("Europe/Nicosia", "Europe/Nicosia"),
+ ("Europe/Oslo", "Europe/Oslo"),
+ ("Europe/Paris", "Europe/Paris"),
+ ("Europe/Podgorica", "Europe/Podgorica"),
+ ("Europe/Prague", "Europe/Prague"),
+ ("Europe/Riga", "Europe/Riga"),
+ ("Europe/Rome", "Europe/Rome"),
+ ("Europe/Samara", "Europe/Samara"),
+ ("Europe/San_Marino", "Europe/San_Marino"),
+ ("Europe/Sarajevo", "Europe/Sarajevo"),
+ ("Europe/Saratov", "Europe/Saratov"),
+ ("Europe/Simferopol", "Europe/Simferopol"),
+ ("Europe/Skopje", "Europe/Skopje"),
+ ("Europe/Sofia", "Europe/Sofia"),
+ ("Europe/Stockholm", "Europe/Stockholm"),
+ ("Europe/Tallinn", "Europe/Tallinn"),
+ ("Europe/Tirane", "Europe/Tirane"),
+ ("Europe/Tiraspol", "Europe/Tiraspol"),
+ ("Europe/Ulyanovsk", "Europe/Ulyanovsk"),
+ ("Europe/Uzhgorod", "Europe/Uzhgorod"),
+ ("Europe/Vaduz", "Europe/Vaduz"),
+ ("Europe/Vatican", "Europe/Vatican"),
+ ("Europe/Vienna", "Europe/Vienna"),
+ ("Europe/Vilnius", "Europe/Vilnius"),
+ ("Europe/Volgograd", "Europe/Volgograd"),
+ ("Europe/Warsaw", "Europe/Warsaw"),
+ ("Europe/Zagreb", "Europe/Zagreb"),
+ ("Europe/Zaporozhye", "Europe/Zaporozhye"),
+ ("Europe/Zurich", "Europe/Zurich"),
+ ("GB", "GB"),
+ ("GB-Eire", "GB-Eire"),
+ ("GMT", "GMT"),
+ ("GMT+0", "GMT+0"),
+ ("GMT-0", "GMT-0"),
+ ("GMT0", "GMT0"),
+ ("Greenwich", "Greenwich"),
+ ("HST", "HST"),
+ ("Hongkong", "Hongkong"),
+ ("Iceland", "Iceland"),
+ ("Indian/Antananarivo", "Indian/Antananarivo"),
+ ("Indian/Chagos", "Indian/Chagos"),
+ ("Indian/Christmas", "Indian/Christmas"),
+ ("Indian/Cocos", "Indian/Cocos"),
+ ("Indian/Comoro", "Indian/Comoro"),
+ ("Indian/Kerguelen", "Indian/Kerguelen"),
+ ("Indian/Mahe", "Indian/Mahe"),
+ ("Indian/Maldives", "Indian/Maldives"),
+ ("Indian/Mauritius", "Indian/Mauritius"),
+ ("Indian/Mayotte", "Indian/Mayotte"),
+ ("Indian/Reunion", "Indian/Reunion"),
+ ("Iran", "Iran"),
+ ("Israel", "Israel"),
+ ("Jamaica", "Jamaica"),
+ ("Japan", "Japan"),
+ ("Kwajalein", "Kwajalein"),
+ ("Libya", "Libya"),
+ ("MET", "MET"),
+ ("MST", "MST"),
+ ("MST7MDT", "MST7MDT"),
+ ("Mexico/BajaNorte", "Mexico/BajaNorte"),
+ ("Mexico/BajaSur", "Mexico/BajaSur"),
+ ("Mexico/General", "Mexico/General"),
+ ("NZ", "NZ"),
+ ("NZ-CHAT", "NZ-CHAT"),
+ ("Navajo", "Navajo"),
+ ("PRC", "PRC"),
+ ("PST8PDT", "PST8PDT"),
+ ("Pacific/Apia", "Pacific/Apia"),
+ ("Pacific/Auckland", "Pacific/Auckland"),
+ ("Pacific/Bougainville", "Pacific/Bougainville"),
+ ("Pacific/Chatham", "Pacific/Chatham"),
+ ("Pacific/Chuuk", "Pacific/Chuuk"),
+ ("Pacific/Easter", "Pacific/Easter"),
+ ("Pacific/Efate", "Pacific/Efate"),
+ ("Pacific/Enderbury", "Pacific/Enderbury"),
+ ("Pacific/Fakaofo", "Pacific/Fakaofo"),
+ ("Pacific/Fiji", "Pacific/Fiji"),
+ ("Pacific/Funafuti", "Pacific/Funafuti"),
+ ("Pacific/Galapagos", "Pacific/Galapagos"),
+ ("Pacific/Gambier", "Pacific/Gambier"),
+ ("Pacific/Guadalcanal", "Pacific/Guadalcanal"),
+ ("Pacific/Guam", "Pacific/Guam"),
+ ("Pacific/Honolulu", "Pacific/Honolulu"),
+ ("Pacific/Johnston", "Pacific/Johnston"),
+ ("Pacific/Kanton", "Pacific/Kanton"),
+ ("Pacific/Kiritimati", "Pacific/Kiritimati"),
+ ("Pacific/Kosrae", "Pacific/Kosrae"),
+ ("Pacific/Kwajalein", "Pacific/Kwajalein"),
+ ("Pacific/Majuro", "Pacific/Majuro"),
+ ("Pacific/Marquesas", "Pacific/Marquesas"),
+ ("Pacific/Midway", "Pacific/Midway"),
+ ("Pacific/Nauru", "Pacific/Nauru"),
+ ("Pacific/Niue", "Pacific/Niue"),
+ ("Pacific/Norfolk", "Pacific/Norfolk"),
+ ("Pacific/Noumea", "Pacific/Noumea"),
+ ("Pacific/Pago_Pago", "Pacific/Pago_Pago"),
+ ("Pacific/Palau", "Pacific/Palau"),
+ ("Pacific/Pitcairn", "Pacific/Pitcairn"),
+ ("Pacific/Pohnpei", "Pacific/Pohnpei"),
+ ("Pacific/Ponape", "Pacific/Ponape"),
+ ("Pacific/Port_Moresby", "Pacific/Port_Moresby"),
+ ("Pacific/Rarotonga", "Pacific/Rarotonga"),
+ ("Pacific/Saipan", "Pacific/Saipan"),
+ ("Pacific/Samoa", "Pacific/Samoa"),
+ ("Pacific/Tahiti", "Pacific/Tahiti"),
+ ("Pacific/Tarawa", "Pacific/Tarawa"),
+ ("Pacific/Tongatapu", "Pacific/Tongatapu"),
+ ("Pacific/Truk", "Pacific/Truk"),
+ ("Pacific/Wake", "Pacific/Wake"),
+ ("Pacific/Wallis", "Pacific/Wallis"),
+ ("Pacific/Yap", "Pacific/Yap"),
+ ("Poland", "Poland"),
+ ("Portugal", "Portugal"),
+ ("ROC", "ROC"),
+ ("ROK", "ROK"),
+ ("Singapore", "Singapore"),
+ ("Turkey", "Turkey"),
+ ("UCT", "UCT"),
+ ("US/Alaska", "US/Alaska"),
+ ("US/Aleutian", "US/Aleutian"),
+ ("US/Arizona", "US/Arizona"),
+ ("US/Central", "US/Central"),
+ ("US/East-Indiana", "US/East-Indiana"),
+ ("US/Eastern", "US/Eastern"),
+ ("US/Hawaii", "US/Hawaii"),
+ ("US/Indiana-Starke", "US/Indiana-Starke"),
+ ("US/Michigan", "US/Michigan"),
+ ("US/Mountain", "US/Mountain"),
+ ("US/Pacific", "US/Pacific"),
+ ("US/Samoa", "US/Samoa"),
+ ("UTC", "UTC"),
+ ("Universal", "Universal"),
+ ("W-SU", "W-SU"),
+ ("WET", "WET"),
+ ("Zulu", "Zulu"),
+ ],
+ default="UTC",
+ max_length=255,
+ ),
+ ),
+ migrations.AddConstraint(
+ model_name="notification",
+ constraint=models.CheckConstraint(
+ check=models.Q(
+ (
+ "notification_type__in",
+ [
+ "FAVORITE",
+ "REPLY",
+ "MENTION",
+ "TAG",
+ "FOLLOW",
+ "FOLLOW_REQUEST",
+ "BOOST",
+ "IMPORT",
+ "ADD",
+ "REPORT",
+ "INVITE",
+ "ACCEPT",
+ "JOIN",
+ "LEAVE",
+ "REMOVE",
+ ],
+ )
+ ),
+ name="notification_type_valid",
+ ),
+ ),
+ migrations.AddField(
+ model_name="groupmemberinvitation",
+ name="group",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="user_invitations",
+ to="bookwyrm.group",
+ ),
+ ),
+ migrations.AddField(
+ model_name="groupmemberinvitation",
+ name="user",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="group_invitations",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ migrations.AddField(
+ model_name="groupmember",
+ name="group",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="memberships",
+ to="bookwyrm.group",
+ ),
+ ),
+ migrations.AddField(
+ model_name="groupmember",
+ name="user",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="memberships",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ migrations.AddField(
+ model_name="group",
+ name="user",
+ field=bookwyrm.models.fields.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
+ ),
+ ),
+ migrations.AddField(
+ model_name="list",
+ name="group",
+ field=models.ForeignKey(
+ blank=True,
+ default=None,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ to="bookwyrm.group",
+ ),
+ ),
+ migrations.AddField(
+ model_name="notification",
+ name="related_group",
+ field=models.ForeignKey(
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="notifications",
+ to="bookwyrm.group",
+ ),
+ ),
+ migrations.AddConstraint(
+ model_name="groupmemberinvitation",
+ constraint=models.UniqueConstraint(
+ fields=("group", "user"), name="unique_invitation"
+ ),
+ ),
+ migrations.AddConstraint(
+ model_name="groupmember",
+ constraint=models.UniqueConstraint(
+ fields=("group", "user"), name="unique_membership"
+ ),
+ ),
+ ]
diff --git a/bookwyrm/migrations/0111_merge_0107_auto_20211016_0639_0110_auto_20211015_1734.py b/bookwyrm/migrations/0111_merge_0107_auto_20211016_0639_0110_auto_20211015_1734.py
new file mode 100644
index 000000000..f5f316c13
--- /dev/null
+++ b/bookwyrm/migrations/0111_merge_0107_auto_20211016_0639_0110_auto_20211015_1734.py
@@ -0,0 +1,13 @@
+# Generated by Django 3.2.5 on 2021-10-16 19:30
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("bookwyrm", "0107_auto_20211016_0639"),
+ ("bookwyrm", "0110_auto_20211015_1734"),
+ ]
+
+ operations = []
diff --git a/bookwyrm/migrations/0112_auto_20211022_0844.py b/bookwyrm/migrations/0112_auto_20211022_0844.py
new file mode 100644
index 000000000..246480b3a
--- /dev/null
+++ b/bookwyrm/migrations/0112_auto_20211022_0844.py
@@ -0,0 +1,93 @@
+# Generated by Django 3.2.5 on 2021-10-22 08:44
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("bookwyrm", "0111_merge_0107_auto_20211016_0639_0110_auto_20211015_1734"),
+ ]
+
+ operations = [
+ migrations.RemoveConstraint(
+ model_name="notification",
+ name="notification_type_valid",
+ ),
+ 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"),
+ ("INVITE", "Invite"),
+ ("ACCEPT", "Accept"),
+ ("JOIN", "Join"),
+ ("LEAVE", "Leave"),
+ ("REMOVE", "Remove"),
+ ("GROUP_PRIVACY", "Group Privacy"),
+ ("GROUP_NAME", "Group Name"),
+ ("GROUP_DESCRIPTION", "Group Description"),
+ ],
+ max_length=255,
+ ),
+ ),
+ migrations.AlterField(
+ model_name="user",
+ name="preferred_language",
+ field=models.CharField(
+ blank=True,
+ choices=[
+ ("en-us", "English"),
+ ("de-de", "Deutsch (German)"),
+ ("es-es", "Español (Spanish)"),
+ ("fr-fr", "Français (French)"),
+ ("pt-br", "Português - Brasil (Brazilian Portuguese)"),
+ ("zh-hans", "简体中文 (Simplified Chinese)"),
+ ("zh-hant", "繁體中文 (Traditional Chinese)"),
+ ],
+ max_length=255,
+ null=True,
+ ),
+ ),
+ migrations.AddConstraint(
+ model_name="notification",
+ constraint=models.CheckConstraint(
+ check=models.Q(
+ (
+ "notification_type__in",
+ [
+ "FAVORITE",
+ "REPLY",
+ "MENTION",
+ "TAG",
+ "FOLLOW",
+ "FOLLOW_REQUEST",
+ "BOOST",
+ "IMPORT",
+ "ADD",
+ "REPORT",
+ "INVITE",
+ "ACCEPT",
+ "JOIN",
+ "LEAVE",
+ "REMOVE",
+ "GROUP_PRIVACY",
+ "GROUP_NAME",
+ "GROUP_DESCRIPTION",
+ ],
+ )
+ ),
+ name="notification_type_valid",
+ ),
+ ),
+ ]
diff --git a/bookwyrm/models/__init__.py b/bookwyrm/models/__init__.py
index bffd62b45..c5ea44e0a 100644
--- a/bookwyrm/models/__init__.py
+++ b/bookwyrm/models/__init__.py
@@ -21,6 +21,8 @@ from .relationship import UserFollows, UserFollowRequest, UserBlocks
from .report import Report, ReportComment
from .federated_server import FederatedServer
+from .group import Group, GroupMember, GroupMemberInvitation
+
from .import_job import ImportJob, ImportItem
from .site import SiteSettings, SiteInvite
diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py
index 07f6b0d5c..f62678f7e 100644
--- a/bookwyrm/models/base_model.py
+++ b/bookwyrm/models/base_model.py
@@ -78,7 +78,24 @@ class BookWyrmModel(models.Model):
self.privacy in ["direct", "followers"]
and self.mention_users.filter(id=viewer.id).first()
):
+
return
+
+ # you can see groups of which you are a member
+ if (
+ hasattr(self, "memberships")
+ and self.memberships.filter(user=viewer).exists()
+ ):
+ return
+
+ # you can see objects which have a group of which you are a member
+ if hasattr(self, "group"):
+ if (
+ hasattr(self.group, "memberships")
+ and self.group.memberships.filter(user=viewer).exists()
+ ):
+ return
+
raise Http404()
def raise_not_editable(self, viewer):
diff --git a/bookwyrm/models/group.py b/bookwyrm/models/group.py
new file mode 100644
index 000000000..bd5b8d410
--- /dev/null
+++ b/bookwyrm/models/group.py
@@ -0,0 +1,182 @@
+""" do book related things with other users """
+from django.apps import apps
+from django.db import models, IntegrityError, transaction
+from django.db.models import Q
+from bookwyrm.settings import DOMAIN
+from .base_model import BookWyrmModel
+from . import fields
+from .relationship import UserBlocks
+
+
+class Group(BookWyrmModel):
+ """A group of users"""
+
+ name = fields.CharField(max_length=100)
+ user = fields.ForeignKey("User", on_delete=models.CASCADE)
+ description = fields.TextField(blank=True, null=True)
+ privacy = fields.PrivacyField()
+
+ def get_remote_id(self):
+ """don't want the user to be in there in this case"""
+ return f"https://{DOMAIN}/group/{self.id}"
+
+ @classmethod
+ def followers_filter(cls, queryset, viewer):
+ """Override filter for "followers" privacy level to allow non-following
+ group members to see the existence of group-curated lists"""
+
+ return queryset.exclude(
+ ~Q( # user is not a group member
+ Q(user__followers=viewer) | Q(user=viewer) | Q(memberships__user=viewer)
+ ),
+ privacy="followers", # and the status of the group is followers only
+ )
+
+ @classmethod
+ def direct_filter(cls, queryset, viewer):
+ """Override filter for "direct" privacy level to allow group members
+ to see the existence of groups and group lists"""
+
+ return queryset.exclude(~Q(memberships__user=viewer), privacy="direct")
+
+
+class GroupMember(models.Model):
+ """Users who are members of a group"""
+
+ created_date = models.DateTimeField(auto_now_add=True)
+ updated_date = models.DateTimeField(auto_now=True)
+ group = models.ForeignKey(
+ "Group", on_delete=models.CASCADE, related_name="memberships"
+ )
+ user = models.ForeignKey(
+ "User", on_delete=models.CASCADE, related_name="memberships"
+ )
+
+ class Meta:
+ """Users can only have one membership per group"""
+
+ constraints = [
+ models.UniqueConstraint(fields=["group", "user"], name="unique_membership")
+ ]
+
+ def save(self, *args, **kwargs):
+ """don't let a user invite someone who blocked them"""
+ # blocking in either direction is a no-go
+ if UserBlocks.objects.filter(
+ Q(
+ user_subject=self.group.user,
+ user_object=self.user,
+ )
+ | Q(
+ user_subject=self.user,
+ user_object=self.group.user,
+ )
+ ).exists():
+ raise IntegrityError()
+ # accepts and requests are handled by the GroupInvitation model
+ super().save(*args, **kwargs)
+
+ @classmethod
+ def from_request(cls, join_request):
+ """converts a join request into a member relationship"""
+
+ # remove the invite
+ join_request.delete()
+
+ # make a group member
+ return cls.objects.create(
+ user=join_request.user,
+ group=join_request.group,
+ )
+
+ @classmethod
+ def remove(cls, owner, user):
+ """remove a user from a group"""
+
+ memberships = cls.objects.filter(group__user=owner, user=user).all()
+ for member in memberships:
+ member.delete()
+
+
+class GroupMemberInvitation(models.Model):
+ """adding a user to a group requires manual confirmation"""
+
+ created_date = models.DateTimeField(auto_now_add=True)
+ group = models.ForeignKey(
+ "Group", on_delete=models.CASCADE, related_name="user_invitations"
+ )
+ user = models.ForeignKey(
+ "User", on_delete=models.CASCADE, related_name="group_invitations"
+ )
+
+ class Meta:
+ """Users can only have one outstanding invitation per group"""
+
+ constraints = [
+ models.UniqueConstraint(fields=["group", "user"], name="unique_invitation")
+ ]
+
+ def save(self, *args, **kwargs):
+ """make sure the membership doesn't already exist"""
+ # if there's an invitation for a membership that already exists, accept it
+ # without changing the local database state
+ if GroupMember.objects.filter(user=self.user, group=self.group).exists():
+ self.accept()
+ return
+
+ # blocking in either direction is a no-go
+ if UserBlocks.objects.filter(
+ Q(
+ user_subject=self.group.user,
+ user_object=self.user,
+ )
+ | Q(
+ user_subject=self.user,
+ user_object=self.group.user,
+ )
+ ).exists():
+ raise IntegrityError()
+
+ # make an invitation
+ super().save(*args, **kwargs)
+
+ # now send the invite
+ model = apps.get_model("bookwyrm.Notification", require_ready=True)
+ notification_type = "INVITE"
+ model.objects.create(
+ user=self.user,
+ related_user=self.group.user,
+ related_group=self.group,
+ notification_type=notification_type,
+ )
+
+ def accept(self):
+ """turn this request into the real deal"""
+
+ with transaction.atomic():
+ GroupMember.from_request(self)
+
+ model = apps.get_model("bookwyrm.Notification", require_ready=True)
+ # tell the group owner
+ model.objects.create(
+ user=self.group.user,
+ related_user=self.user,
+ related_group=self.group,
+ notification_type="ACCEPT",
+ )
+
+ # let the other members know about it
+ for membership in self.group.memberships.all():
+ member = membership.user
+ if member not in (self.user, self.group.user):
+ model.objects.create(
+ user=member,
+ related_user=self.user,
+ related_group=self.group,
+ notification_type="JOIN",
+ )
+
+ def reject(self):
+ """generate a Reject for this membership request"""
+
+ self.delete()
diff --git a/bookwyrm/models/list.py b/bookwyrm/models/list.py
index 022a0d981..978a7a9b3 100644
--- a/bookwyrm/models/list.py
+++ b/bookwyrm/models/list.py
@@ -1,22 +1,20 @@
""" make a list of books!! """
from django.apps import apps
from django.db import models
+from django.db.models import Q
from django.utils import timezone
from bookwyrm import activitypub
from bookwyrm.settings import DOMAIN
+
from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin
from .base_model import BookWyrmModel
+from .group import GroupMember
from . import fields
-
CurationType = models.TextChoices(
"Curation",
- [
- "closed",
- "open",
- "curated",
- ],
+ ["closed", "open", "curated", "group"],
)
@@ -32,6 +30,13 @@ class List(OrderedCollectionMixin, BookWyrmModel):
curation = fields.CharField(
max_length=255, default="closed", choices=CurationType.choices
)
+ group = models.ForeignKey(
+ "Group",
+ on_delete=models.SET_NULL,
+ default=None,
+ blank=True,
+ null=True,
+ )
books = models.ManyToManyField(
"Edition",
symmetrical=False,
@@ -54,6 +59,52 @@ class List(OrderedCollectionMixin, BookWyrmModel):
ordering = ("-updated_date",)
+ def raise_not_editable(self, viewer):
+ """the associated user OR the list owner can edit"""
+ if self.user == viewer:
+ return
+ # group members can edit items in group lists
+ is_group_member = GroupMember.objects.filter(
+ group=self.group, user=viewer
+ ).exists()
+ if is_group_member:
+ return
+ super().raise_not_editable(viewer)
+
+ @classmethod
+ def followers_filter(cls, queryset, viewer):
+ """Override filter for "followers" privacy level to allow non-following
+ group members to see the existence of group lists"""
+
+ return queryset.exclude(
+ ~Q( # user isn't following or group member
+ Q(user__followers=viewer)
+ | Q(user=viewer)
+ | Q(group__memberships__user=viewer)
+ ),
+ privacy="followers", # and the status (of the list) is followers only
+ )
+
+ @classmethod
+ def direct_filter(cls, queryset, viewer):
+ """Override filter for "direct" privacy level to allow
+ group members to see the existence of group lists"""
+
+ return queryset.exclude(
+ ~Q( # user not self and not in the group if this is a group list
+ Q(user=viewer) | Q(group__memberships__user=viewer)
+ ),
+ privacy="direct",
+ )
+
+ @classmethod
+ def remove_from_group(cls, owner, user):
+ """remove a list from a group"""
+
+ cls.objects.filter(group__user=owner, user=user).all().update(
+ group=None, curation="closed"
+ )
+
class ListItem(CollectionItemMixin, BookWyrmModel):
"""ok"""
@@ -82,9 +133,9 @@ class ListItem(CollectionItemMixin, BookWyrmModel):
self.book_list.save(broadcast=False)
list_owner = self.book_list.user
+ model = apps.get_model("bookwyrm.Notification", require_ready=True)
# create a notification if somoene ELSE added to a local user's list
if created and list_owner.local and list_owner != self.user:
- model = apps.get_model("bookwyrm.Notification", require_ready=True)
model.objects.create(
user=list_owner,
related_user=self.user,
@@ -92,10 +143,26 @@ class ListItem(CollectionItemMixin, BookWyrmModel):
notification_type="ADD",
)
+ if self.book_list.group:
+ for membership in self.book_list.group.memberships.all():
+ if membership.user != self.user:
+ model.objects.create(
+ user=membership.user,
+ related_user=self.user,
+ related_list_item=self,
+ notification_type="ADD",
+ )
+
def raise_not_deletable(self, viewer):
"""the associated user OR the list owner can delete"""
if self.book_list.user == viewer:
return
+ # group members can delete items in group lists
+ is_group_member = GroupMember.objects.filter(
+ group=self.book_list.group, user=viewer
+ ).exists()
+ if is_group_member:
+ return
super().raise_not_deletable(viewer)
class Meta:
diff --git a/bookwyrm/models/notification.py b/bookwyrm/models/notification.py
index a4968f61f..2f1aae4f3 100644
--- a/bookwyrm/models/notification.py
+++ b/bookwyrm/models/notification.py
@@ -4,10 +4,10 @@ from django.dispatch import receiver
from .base_model import BookWyrmModel
from . import Boost, Favorite, ImportJob, Report, Status, User
-
+# pylint: disable=line-too-long
NotificationType = models.TextChoices(
"NotificationType",
- "FAVORITE REPLY MENTION TAG FOLLOW FOLLOW_REQUEST BOOST IMPORT ADD REPORT",
+ "FAVORITE REPLY MENTION TAG FOLLOW FOLLOW_REQUEST BOOST IMPORT ADD REPORT INVITE ACCEPT JOIN LEAVE REMOVE GROUP_PRIVACY GROUP_NAME GROUP_DESCRIPTION",
)
@@ -19,6 +19,9 @@ class Notification(BookWyrmModel):
related_user = models.ForeignKey(
"User", on_delete=models.CASCADE, null=True, related_name="related_user"
)
+ related_group = models.ForeignKey(
+ "Group", on_delete=models.CASCADE, null=True, related_name="notifications"
+ )
related_status = models.ForeignKey("Status", on_delete=models.CASCADE, null=True)
related_import = models.ForeignKey("ImportJob", on_delete=models.CASCADE, null=True)
related_list_item = models.ForeignKey(
@@ -37,6 +40,7 @@ class Notification(BookWyrmModel):
user=self.user,
related_book=self.related_book,
related_user=self.related_user,
+ related_group=self.related_group,
related_status=self.related_status,
related_import=self.related_import,
related_list_item=self.related_list_item,
diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js
index f000fd082..2d5b88adc 100644
--- a/bookwyrm/static/js/bookwyrm.js
+++ b/bookwyrm/static/js/bookwyrm.js
@@ -28,6 +28,12 @@ let BookWyrm = new class {
this.revealForm.bind(this))
);
+ document.querySelectorAll('[data-hides]')
+ .forEach(button => button.addEventListener(
+ 'change',
+ this.hideForm.bind(this))
+ );
+
document.querySelectorAll('[data-back]')
.forEach(button => button.addEventListener(
'click',
@@ -119,8 +125,8 @@ let BookWyrm = new class {
}
/**
- * Toggle form.
- *
+ * Show form.
+ *
* @param {Event} event
* @return {undefined}
*/
@@ -128,7 +134,23 @@ let BookWyrm = new class {
let trigger = event.currentTarget;
let hidden = trigger.closest('.hidden-form').querySelectorAll('.is-hidden')[0];
- this.addRemoveClass(hidden, 'is-hidden', !hidden);
+ if (hidden) {
+ this.addRemoveClass(hidden, 'is-hidden', !hidden);
+ }
+ }
+
+ /**
+ * Hide form.
+ *
+ * @param {Event} event
+ * @return {undefined}
+ */
+ hideForm(event) {
+ let trigger = event.currentTarget;
+ let targetId = trigger.dataset.hides
+ let visible = document.getElementById(targetId)
+
+ this.addRemoveClass(visible, 'is-hidden', true);
}
/**
@@ -227,7 +249,7 @@ let BookWyrm = new class {
}
/**
- * Check or uncheck a checbox.
+ * Check or uncheck a checkbox.
*
* @param {string} checkbox - id of the checkbox
* @param {boolean} pressed - Is the trigger pressed?
diff --git a/bookwyrm/suggested_users.py b/bookwyrm/suggested_users.py
index aa53fcb25..86c181a28 100644
--- a/bookwyrm/suggested_users.py
+++ b/bookwyrm/suggested_users.py
@@ -81,7 +81,7 @@ class SuggestedUsers(RedisStore):
"""take a user out of someone's suggestions"""
self.bulk_remove_objects_from_store([suggested_user], self.store_id(user))
- def get_suggestions(self, user):
+ def get_suggestions(self, user, local=False):
"""get suggestions"""
values = self.get_store(self.store_id(user), withscores=True)
results = []
@@ -97,8 +97,8 @@ class SuggestedUsers(RedisStore):
logger.exception(err)
continue
user.mutuals = counts["mutuals"]
- # user.shared_books = counts["shared_books"]
- results.append(user)
+ if (local and user.local) or not local:
+ results.append(user)
if len(results) >= 5:
break
return results
diff --git a/bookwyrm/templates/author/author.html b/bookwyrm/templates/author/author.html
index 8a15cd0f0..6a67b50b3 100644
--- a/bookwyrm/templates/author/author.html
+++ b/bookwyrm/templates/author/author.html
@@ -110,8 +110,14 @@
{% for book in books %}
{% include 'landing/small-book.html' with book=book %}
+ {% include 'snippets/shelve_button/shelve_button.html' with book=book %}
{% endfor %}
+
+
+ {% include 'snippets/pagination.html' with page=books %}
+
+
{% endblock %}
diff --git a/bookwyrm/templates/author/edit_author.html b/bookwyrm/templates/author/edit_author.html
index 103341bfd..54d7f4f1c 100644
--- a/bookwyrm/templates/author/edit_author.html
+++ b/bookwyrm/templates/author/edit_author.html
@@ -12,7 +12,9 @@
{% trans "Added:" %} {{ author.created_date | naturaltime }}
{% trans "Updated:" %} {{ author.updated_date | naturaltime }}
+ {% if author.last_edited_by %}
{% trans "Last edited by:" %} {{ author.last_edited_by.display_name }}
+ {% endif %}
diff --git a/bookwyrm/templates/book/edit/edit_book.html b/bookwyrm/templates/book/edit/edit_book.html
index ec7b08586..fc11208fd 100644
--- a/bookwyrm/templates/book/edit/edit_book.html
+++ b/bookwyrm/templates/book/edit/edit_book.html
@@ -108,7 +108,13 @@
{% if not confirm_mode %}
{% endif %}
diff --git a/bookwyrm/templates/book/publisher_info.html b/bookwyrm/templates/book/publisher_info.html
index e0711fa82..b39bcf5ce 100644
--- a/bookwyrm/templates/book/publisher_info.html
+++ b/bookwyrm/templates/book/publisher_info.html
@@ -3,7 +3,7 @@
{% load i18n %}
{% load humanize %}
-{% firstof book.physical_format_detail book.physical_format as format %}
+{% firstof book.physical_format_detail book.get_physical_format_display as format %}
{% firstof book.physical_format book.physical_format_detail as format_property %}
{% with pages=book.pages %}
{% if format or pages %}
@@ -18,7 +18,7 @@
{% if format and not pages %}
- {% blocktrans %}{{ format }}{% endblocktrans %}
+ {{ format }}
{% elif format and pages %}
{% blocktrans %}{{ format }}, {{ pages }} pages{% endblocktrans %}
{% elif pages %}
diff --git a/bookwyrm/templates/discover/card-header.html b/bookwyrm/templates/discover/card-header.html
new file mode 100644
index 000000000..0eb9a678c
--- /dev/null
+++ b/bookwyrm/templates/discover/card-header.html
@@ -0,0 +1,26 @@
+{% load i18n %}
+{% load utilities %}
+
+{% with user_path=status.user.local_path username=status.user.display_name book_path=status.book.local_poth book_title=book|book_title %}
+
+{% if status.status_type == 'GeneratedNote' %}
+ {{ status.content|safe }}
+{% elif status.status_type == 'Rating' %}
+ {% blocktrans trimmed %}
+ {{ username }} rated {{ book_title }}
+ {% endblocktrans %}
+{% elif status.status_type == 'Review' %}
+ {% blocktrans trimmed %}
+ {{ username }} reviewed {{ book_title }}
+ {% endblocktrans %}
+{% elif status.status_type == 'Comment' %}
+ {% blocktrans trimmed %}
+ {{ username }} commented on {{ book_title }}
+ {% endblocktrans %}
+{% elif status.status_type == 'Quotation' %}
+ {% blocktrans trimmed %}
+ {{ username }} quoted {{ book_title }}
+ {% endblocktrans %}
+{% endif %}
+
+{% endwith %}
diff --git a/bookwyrm/templates/discover/large-book.html b/bookwyrm/templates/discover/large-book.html
index 6d80c3daf..1fa0afb92 100644
--- a/bookwyrm/templates/discover/large-book.html
+++ b/bookwyrm/templates/discover/large-book.html
@@ -36,23 +36,7 @@
-
- {{ status.user.display_name }}
-
-
- {% if status.status_type == 'GeneratedNote' %}
- {{ status.content|safe }}
- {% elif status.status_type == 'Rating' %}
- {% trans "rated" %}
- {% elif status.status_type == 'Review' %}
- {% trans "reviewed" %}
- {% elif status.status_type == 'Comment' %}
- {% trans "commented on" %}
- {% elif status.status_type == 'Quotation' %}
- {% trans "quoted" %}
- {% endif %}
-
- {{ book.title }}
+ {% include "discover/card-header.html" %}
diff --git a/bookwyrm/templates/discover/small-book.html b/bookwyrm/templates/discover/small-book.html
index 5b2070188..76732ca14 100644
--- a/bookwyrm/templates/discover/small-book.html
+++ b/bookwyrm/templates/discover/small-book.html
@@ -22,23 +22,7 @@
-
- {{ status.user.display_name }}
-
-
- {% if status.status_type == 'GeneratedNote' %}
- {{ status.content|safe }}
- {% elif status.status_type == 'Rating' %}
- {% trans "rated" %}
- {% elif status.status_type == 'Review' %}
- {% trans "reviewed" %}
- {% elif status.status_type == 'Comment' %}
- {% trans "commented on" %}
- {% elif status.status_type == 'Quotation' %}
- {% trans "quoted" %}
- {% endif %}
-
- {{ book.title }}
+ {% include "discover/card-header.html" %}
{% if status.rating %}
diff --git a/bookwyrm/templates/email/invite/html_content.html b/bookwyrm/templates/email/invite/html_content.html
index 358e23dc1..adc993b7b 100644
--- a/bookwyrm/templates/email/invite/html_content.html
+++ b/bookwyrm/templates/email/invite/html_content.html
@@ -12,6 +12,6 @@
{% url 'code-of-conduct' as coc_path %}
{% url 'about' as about_path %}
- {% blocktrans %}Learn more about this instance .{% endblocktrans %}
+ {% blocktrans %}Learn more about {{ site_name }} .{% endblocktrans %}
{% endblock %}
diff --git a/bookwyrm/templates/email/invite/text_content.html b/bookwyrm/templates/email/invite/text_content.html
index c3fcdc04e..26dcd1720 100644
--- a/bookwyrm/templates/email/invite/text_content.html
+++ b/bookwyrm/templates/email/invite/text_content.html
@@ -5,6 +5,6 @@
{{ invite_link }}
-{% trans "Learn more about this instance:" %} https://{{ domain }}{% url 'about' %}
+{% blocktrans %}Learn more about {{ site_name }}:{% endblocktrans %} https://{{ domain }}{% url 'about' %}
{% endblock %}
diff --git a/bookwyrm/templates/groups/create_form.html b/bookwyrm/templates/groups/create_form.html
new file mode 100644
index 000000000..dbb8ad88b
--- /dev/null
+++ b/bookwyrm/templates/groups/create_form.html
@@ -0,0 +1,12 @@
+{% extends 'components/inline_form.html' %}
+{% load i18n %}
+
+{% block header %}
+{% trans "Create Group" %}
+{% endblock %}
+
+{% block form %}
+
+{% endblock %}
diff --git a/bookwyrm/templates/groups/created_text.html b/bookwyrm/templates/groups/created_text.html
new file mode 100644
index 000000000..5e6ce513d
--- /dev/null
+++ b/bookwyrm/templates/groups/created_text.html
@@ -0,0 +1,6 @@
+{% load i18n %}
+{% spaceless %}
+
+{% blocktrans with username=group.user.display_name path=group.user.local_path %}Managed by
{{ username }} {% endblocktrans %}
+
+{% endspaceless %}
diff --git a/bookwyrm/templates/groups/delete_group_modal.html b/bookwyrm/templates/groups/delete_group_modal.html
new file mode 100644
index 000000000..4bb87ed9b
--- /dev/null
+++ b/bookwyrm/templates/groups/delete_group_modal.html
@@ -0,0 +1,21 @@
+{% extends 'components/modal.html' %}
+{% load i18n %}
+
+{% block modal-title %}{% trans "Delete this group?" %}{% endblock %}
+
+{% block modal-body %}
+{% trans "This action cannot be un-done" %}
+{% endblock %}
+
+{% block modal-footer %}
+
+{% endblock %}
+
diff --git a/bookwyrm/templates/groups/edit_form.html b/bookwyrm/templates/groups/edit_form.html
new file mode 100644
index 000000000..1c58dc77e
--- /dev/null
+++ b/bookwyrm/templates/groups/edit_form.html
@@ -0,0 +1,13 @@
+{% extends 'components/inline_form.html' %}
+{% load i18n %}
+
+{% block header %}
+{% trans "Edit Group" %}
+{% endblock %}
+
+{% block form %}
+
+{% include "groups/delete_group_modal.html" with controls_text="delete_group" controls_uid=group.id %}
+{% endblock %}
diff --git a/bookwyrm/templates/groups/find_users.html b/bookwyrm/templates/groups/find_users.html
new file mode 100644
index 000000000..377e3a0b3
--- /dev/null
+++ b/bookwyrm/templates/groups/find_users.html
@@ -0,0 +1,9 @@
+{% extends 'groups/group.html' %}
+{% load i18n %}
+
+{% block searchresults %}
+
+ {% trans "Add new members!" %}
+
+ {% include 'groups/suggested_users.html' with suggested_users=suggested_users %}
+{% endblock %}
diff --git a/bookwyrm/templates/groups/form.html b/bookwyrm/templates/groups/form.html
new file mode 100644
index 000000000..21c525ee0
--- /dev/null
+++ b/bookwyrm/templates/groups/form.html
@@ -0,0 +1,34 @@
+{% load i18n %}
+{% csrf_token %}
+
+
+
+
+
+ {% trans "Group Name:" %}
+ {{ group_form.name }}
+
+
+ {% trans "Group Description:" %}
+ {{ group_form.description }}
+
+
+
+
+
+
+
+ {% include 'snippets/privacy_select_no_followers.html' with current=group.privacy %}
+
+
+ {% trans "Save" %}
+
+
+
+ {% if group.id %}
+
+ {% trans "Delete group" as button_text %}
+ {% include 'snippets/toggle/toggle_button.html' with class="is-danger" text=button_text icon_with_text="x" controls_text="delete_group" controls_uid=group.id focus="modal_title_delete_group" %}
+
+ {% endif %}
+
diff --git a/bookwyrm/templates/groups/group.html b/bookwyrm/templates/groups/group.html
new file mode 100644
index 000000000..f25a1f270
--- /dev/null
+++ b/bookwyrm/templates/groups/group.html
@@ -0,0 +1,82 @@
+{% extends 'groups/layout.html' %}
+{% load i18n %}
+{% load bookwyrm_tags %}
+{% load markdown %}
+
+{% block panel %}
+
+
+
+
+ {% if group.user == request.user %}
+
+ {% endif %}
+
+ {% block searchresults %}
+ {% endblock %}
+
+ {% include "groups/members.html" with group=group %}
+
+
+ Lists
+ {% if not lists %}
+ {% trans "This group has no lists" %}
+ {% else %}
+
+
+ {% for list in lists %}
+
+
+
+
+ {% with list_books=list.listitem_set.all|slice:5 %}
+ {% if list_books %}
+
+ {% endif %}
+ {% endwith %}
+
+
+
+ {% if list.description %}
+ {{ list.description|to_markdown|safe|truncatechars_html:30 }}
+ {% else %}
+
+ {% endif %}
+
+
+ {% include 'lists/created_text.html' with list=list %}
+
+
+
+
+ {% endfor %}
+
+
+ {% endif %}
+ {% include "snippets/pagination.html" with page=items %}
+
+
+{% endblock %}
diff --git a/bookwyrm/templates/groups/layout.html b/bookwyrm/templates/groups/layout.html
new file mode 100644
index 000000000..f558f169a
--- /dev/null
+++ b/bookwyrm/templates/groups/layout.html
@@ -0,0 +1,32 @@
+{% extends 'layout.html' %}
+{% load i18n %}
+
+{% block title %}{{ group.name }}{% endblock %}
+
+{% block content %}
+
+
+
{{ group.name }} {% include 'snippets/privacy-icons.html' with item=group %}
+
+ {% include 'groups/created_text.html' with group=group %}
+
+
+
+ {% if request.user == group.user %}
+ {% trans "Edit group" as button_text %}
+ {% include 'snippets/toggle/open_button.html' with text=button_text icon_with_text="pencil" controls_text="edit_group" focus="edit_group_header" %}
+ {% endif %}
+
+
+
+
+ {% include 'snippets/trimmed_text.html' with full=group.description %}
+
+
+
+ {% include 'groups/edit_form.html' with controls_text="edit_group" %}
+
+
+{% block panel %}{% endblock %}
+
+{% endblock %}
diff --git a/bookwyrm/templates/groups/members.html b/bookwyrm/templates/groups/members.html
new file mode 100644
index 000000000..719674d89
--- /dev/null
+++ b/bookwyrm/templates/groups/members.html
@@ -0,0 +1,47 @@
+{% load i18n %}
+{% load utilities %}
+{% load humanize %}
+{% load bookwyrm_tags %}
+{% load bookwyrm_group_tags %}
+
+
Group Members
+
{% trans "Members can add and remove books on a group's book lists" %}
+
+{% if group.user != request.user and group|is_member:request.user %}
+
+{% endif %}
+
+
diff --git a/bookwyrm/templates/groups/suggested_users.html b/bookwyrm/templates/groups/suggested_users.html
new file mode 100644
index 000000000..64498eb85
--- /dev/null
+++ b/bookwyrm/templates/groups/suggested_users.html
@@ -0,0 +1,46 @@
+{% load i18n %}
+{% load utilities %}
+{% load humanize %}
+
+{% if suggested_users %}
+
+ {% for user in suggested_users %}
+
+
+ {% include 'snippets/avatar.html' with user=user large=True %}
+ {{ user.display_name|truncatechars:10 }}
+ @{{ user|username|truncatechars:8 }}
+
+ {% include 'snippets/add_to_group_button.html' with user=user group=group %}
+ {% if user.mutuals %}
+
+ {% blocktrans trimmed with mutuals=user.mutuals|intcomma count counter=user.mutuals %}
+ {{ mutuals }} follower you follow
+ {% plural %}
+ {{ mutuals }} followers you follow{% endblocktrans %}
+
+ {% elif user.shared_books %}
+
+ {% blocktrans trimmed with shared_books=user.shared_books|intcomma count counter=user.shared_books %}
+ {{ shared_books }} book on your shelves
+ {% plural %}
+ {{ shared_books }} books on your shelves
+ {% endblocktrans %}
+
+ {% elif request.user in user.following.all %}
+
+ {% trans "Follows you" %}
+
+ {% endif %}
+
+ {% endfor %}
+
+ {% else %}
+
+ {% blocktrans trimmed %}
+ No potential members found for "{{ user_query }}"
+ {% endblocktrans %}
+
+
+
+{% endif %}
diff --git a/bookwyrm/templates/groups/user_groups.html b/bookwyrm/templates/groups/user_groups.html
new file mode 100644
index 000000000..cc27ce42d
--- /dev/null
+++ b/bookwyrm/templates/groups/user_groups.html
@@ -0,0 +1,35 @@
+{% load i18n %}
+{% load markdown %}
+{% load interaction %}
+
+
+ {% for group in groups %}
+
+
+
+
+
+
+ {% if group.description %}
+ {{ group.description|to_markdown|safe|truncatechars_html:30 }}
+ {% else %}
+
+ {% endif %}
+
+
+
+
+ {% endfor %}
+
diff --git a/bookwyrm/templates/import/import.html b/bookwyrm/templates/import/import.html
index cc296b75b..81f0daa54 100644
--- a/bookwyrm/templates/import/import.html
+++ b/bookwyrm/templates/import/import.html
@@ -22,8 +22,8 @@
-
- GoodReads (CSV)
+
+ Goodreads (CSV)
Storygraph (CSV)
diff --git a/bookwyrm/templates/import/tooltip.html b/bookwyrm/templates/import/tooltip.html
index 1cfe5a3b2..311cce82c 100644
--- a/bookwyrm/templates/import/tooltip.html
+++ b/bookwyrm/templates/import/tooltip.html
@@ -3,6 +3,6 @@
{% block tooltip_content %}
-{% trans 'You can download your GoodReads data from the Import/Export page of your GoodReads account.' %}
+{% trans 'You can download your Goodreads data from the Import/Export page of your Goodreads account.' %}
{% endblock %}
diff --git a/bookwyrm/templates/invite.html b/bookwyrm/templates/landing/invite.html
similarity index 91%
rename from bookwyrm/templates/invite.html
rename to bookwyrm/templates/landing/invite.html
index fcd379e26..d56cad38c 100644
--- a/bookwyrm/templates/invite.html
+++ b/bookwyrm/templates/landing/invite.html
@@ -12,7 +12,7 @@
{% if valid %}
diff --git a/bookwyrm/templates/login.html b/bookwyrm/templates/landing/login.html
similarity index 79%
rename from bookwyrm/templates/login.html
rename to bookwyrm/templates/landing/login.html
index 31e9cebb4..95baa06de 100644
--- a/bookwyrm/templates/login.html
+++ b/bookwyrm/templates/landing/login.html
@@ -14,19 +14,19 @@
{% if show_confirmed_email %}
{% trans "Success! Email address confirmed." %}
{% endif %}
-
{% if request.user.is_authenticated and not list.curation == 'closed' or request.user == list.user %}
- {% if list.curation == 'open' or request.user == list.user %}
+ {% if list.curation == 'open' or request.user == list.user or list.group|is_member:request.user %}
{% trans "Add Books" %}
{% else %}
{% trans "Suggest Books" %}
@@ -178,7 +179,7 @@
{% csrf_token %}
- {% if list.curation == 'open' or request.user == list.user %}{% trans "Add" %}{% else %}{% trans "Suggest" %}{% endif %}
+ {% if list.curation == 'open' or request.user == list.user or list.group|is_member:request.user %}{% trans "Add" %}{% else %}{% trans "Suggest" %}{% endif %}
diff --git a/bookwyrm/templates/lists/lists.html b/bookwyrm/templates/lists/lists.html
index d909f5e81..49091bcf0 100644
--- a/bookwyrm/templates/lists/lists.html
+++ b/bookwyrm/templates/lists/lists.html
@@ -22,10 +22,11 @@
{% endif %}
-
+{% if request.user.is_authenticated %}
{% include 'lists/create_form.html' with controls_text="create_list" %}
+{% endif %}
{% if request.user.is_authenticated %}
diff --git a/bookwyrm/templates/notifications/item.html b/bookwyrm/templates/notifications/item.html
index 348d8950f..e8e2dcb26 100644
--- a/bookwyrm/templates/notifications/item.html
+++ b/bookwyrm/templates/notifications/item.html
@@ -17,4 +17,20 @@
{% include 'notifications/items/add.html' %}
{% elif notification.notification_type == 'REPORT' %}
{% include 'notifications/items/report.html' %}
+{% elif notification.notification_type == 'INVITE' %}
+ {% include 'notifications/items/invite.html' %}
+{% elif notification.notification_type == 'ACCEPT' %}
+ {% include 'notifications/items/accept.html' %}
+{% elif notification.notification_type == 'JOIN' %}
+ {% include 'notifications/items/join.html' %}
+{% elif notification.notification_type == 'LEAVE' %}
+ {% include 'notifications/items/leave.html' %}
+{% elif notification.notification_type == 'REMOVE' %}
+ {% include 'notifications/items/remove.html' %}
+{% elif notification.notification_type == 'GROUP_PRIVACY' %}
+ {% include 'notifications/items/update.html' %}
+{% elif notification.notification_type == 'GROUP_NAME' %}
+ {% include 'notifications/items/update.html' %}
+{% elif notification.notification_type == 'GROUP_DESCRIPTION' %}
+ {% include 'notifications/items/update.html' %}
{% endif %}
diff --git a/bookwyrm/templates/notifications/items/accept.html b/bookwyrm/templates/notifications/items/accept.html
new file mode 100644
index 000000000..045e23266
--- /dev/null
+++ b/bookwyrm/templates/notifications/items/accept.html
@@ -0,0 +1,20 @@
+{% extends 'notifications/items/item_layout.html' %}
+
+{% load i18n %}
+{% load utilities %}
+
+{% block primary_link %}{% spaceless %}
+ {{ notification.related_group.local_path }}
+{% endspaceless %}{% endblock %}
+
+{% block icon %}
+
+{% endblock %}
+
+{% block description %}
+
+ {% blocktrans trimmed with group_name=notification.related_group.name group_path=notification.related_group.local_path %}
+ accepted your invitation to join group "{{ group_name }} "
+ {% endblocktrans %}
+
+{% endblock %}
diff --git a/bookwyrm/templates/notifications/items/fav.html b/bookwyrm/templates/notifications/items/fav.html
index d430598e9..fbb865e4f 100644
--- a/bookwyrm/templates/notifications/items/fav.html
+++ b/bookwyrm/templates/notifications/items/fav.html
@@ -18,25 +18,25 @@
{% if related_status.status_type == 'Review' %}
{% blocktrans trimmed %}
- favorited your review of {{ book_title }}
+ liked your review of {{ book_title }}
{% endblocktrans %}
{% elif related_status.status_type == 'Comment' %}
{% blocktrans trimmed %}
- favorited your comment on{{ book_title }}
+ liked your comment on {{ book_title }}
{% endblocktrans %}
{% elif related_status.status_type == 'Quotation' %}
{% blocktrans trimmed %}
- favorited your quote from {{ book_title }}
+ liked your quote from {{ book_title }}
{% endblocktrans %}
{% else %}
{% blocktrans trimmed %}
- favorited your status
+ liked your status
{% endblocktrans %}
{% endif %}
diff --git a/bookwyrm/templates/notifications/items/invite.html b/bookwyrm/templates/notifications/items/invite.html
new file mode 100644
index 000000000..abb8cd02f
--- /dev/null
+++ b/bookwyrm/templates/notifications/items/invite.html
@@ -0,0 +1,22 @@
+{% extends 'notifications/items/item_layout.html' %}
+
+{% load i18n %}
+{% load utilities %}
+
+{% block primary_link %}{% spaceless %}
+ {{ notification.related_group.local_path }}
+{% endspaceless %}{% endblock %}
+
+{% block icon %}
+
+{% endblock %}
+
+{% block description %}
+{% blocktrans trimmed with group_name=notification.related_group.name group_path=notification.related_group.local_path %}
+invited you to join the group "{{ group_name }} "
+{% endblocktrans %}
+
+ {% include 'snippets/join_invitation_buttons.html' with group=notification.related_group %}
+
+{% endblock %}
+
diff --git a/bookwyrm/templates/notifications/items/item_layout.html b/bookwyrm/templates/notifications/items/item_layout.html
index 382978d47..8db68dafb 100644
--- a/bookwyrm/templates/notifications/items/item_layout.html
+++ b/bookwyrm/templates/notifications/items/item_layout.html
@@ -1,4 +1,3 @@
-{% load humanize %}
{% load bookwyrm_tags %}
{% related_status notification as related_status %}
@@ -10,10 +9,8 @@
{% if notification.related_user %}
-
- {% include 'snippets/avatar.html' with user=notification.related_user %}
- {{ notification.related_user.display_name }}
-
+ {% include 'snippets/avatar.html' with user=notification.related_user %}
+ {{ notification.related_user.display_name }}
{% endif %}
{% block description %}{% endblock %}
diff --git a/bookwyrm/templates/notifications/items/join.html b/bookwyrm/templates/notifications/items/join.html
new file mode 100644
index 000000000..c10def456
--- /dev/null
+++ b/bookwyrm/templates/notifications/items/join.html
@@ -0,0 +1,20 @@
+{% extends 'notifications/items/item_layout.html' %}
+
+{% load i18n %}
+{% load utilities %}
+
+{% block primary_link %}{% spaceless %}
+ {{ notification.related_group.local_path }}
+{% endspaceless %}{% endblock %}
+
+{% block icon %}
+
+{% endblock %}
+
+{% block description %}
+
+{% blocktrans trimmed with group_name=notification.related_group.name group_path=notification.related_group.local_path %}
+has joined your group "
{{ group_name }} "
+{% endblocktrans %}
+
+{% endblock %}
diff --git a/bookwyrm/templates/notifications/items/leave.html b/bookwyrm/templates/notifications/items/leave.html
new file mode 100644
index 000000000..422a31dea
--- /dev/null
+++ b/bookwyrm/templates/notifications/items/leave.html
@@ -0,0 +1,20 @@
+{% extends 'notifications/items/item_layout.html' %}
+
+{% load i18n %}
+{% load utilities %}
+
+{% block primary_link %}{% spaceless %}
+ {{ notification.related_group.local_path }}
+{% endspaceless %}{% endblock %}
+
+{% block icon %}
+
+{% endblock %}
+
+{% block description %}
+
+ {% blocktrans trimmed with group_name=notification.related_group.name group_path=notification.related_group.local_path %}
+ has left your group "
{{ group_name }} "
+ {% endblocktrans %}
+
+{% endblock %}
diff --git a/bookwyrm/templates/notifications/items/remove.html b/bookwyrm/templates/notifications/items/remove.html
new file mode 100644
index 000000000..eba18fd89
--- /dev/null
+++ b/bookwyrm/templates/notifications/items/remove.html
@@ -0,0 +1,29 @@
+{% extends 'notifications/items/item_layout.html' %}
+
+{% load i18n %}
+{% load utilities %}
+
+{% block primary_link %}{% spaceless %}
+ {{ notification.related_group.local_path }}
+{% endspaceless %}{% endblock %}
+
+{% block icon %}
+
+{% endblock %}
+
+{% block description %}
+{% if notification.related_user %}
+
+ {% blocktrans trimmed with group_name=notification.related_group.name group_path=notification.related_group.local_path %}
+ has been removed from your group "
{{ group_name }} "
+ {% endblocktrans %}
+
+{% else %}
+
+ {% blocktrans trimmed with group_name=notification.related_group.name group_path=notification.related_group.local_path %}
+ You have been removed from the "
{{ group_name }} " group
+ {% endblocktrans %}
+
+{% endif %}
+{% endblock %}
+
diff --git a/bookwyrm/templates/notifications/items/update.html b/bookwyrm/templates/notifications/items/update.html
new file mode 100644
index 000000000..be796b785
--- /dev/null
+++ b/bookwyrm/templates/notifications/items/update.html
@@ -0,0 +1,28 @@
+{% extends 'notifications/items/item_layout.html' %}
+
+{% load i18n %}
+{% load utilities %}
+
+{% block primary_link %}{% spaceless %}
+ {{ notification.related_group.local_path }}
+{% endspaceless %}{% endblock %}
+
+{% block icon %}
+
+{% endblock %}
+
+{% block description %}
+ {% if notification.notification_type == 'GROUP_PRIVACY' %}
+ {% blocktrans trimmed with group_name=notification.related_group.name group_path=notification.related_group.local_path %}
+ has changed the privacy level for
{{ group_name }}
+ {% endblocktrans %}
+ {% elif notification.notification_type == 'GROUP_NAME' %}
+ {% blocktrans trimmed with group_name=notification.related_group.name group_path=notification.related_group.local_path %}
+ has changed the name of
{{ group_name }}
+ {% endblocktrans %}
+ {% else %}
+ {% blocktrans trimmed with group_name=notification.related_group.name group_path=notification.related_group.local_path %}
+ has changed the description of
{{ group_name }}
+ {% endblocktrans %}
+ {% endif %}
+{% endblock %}
diff --git a/bookwyrm/templates/settings/site.html b/bookwyrm/templates/settings/site.html
index da5b7705f..94a4dd454 100644
--- a/bookwyrm/templates/settings/site.html
+++ b/bookwyrm/templates/settings/site.html
@@ -34,7 +34,7 @@
{% trans "Short description:" %}
-
{% trans "Used when the instance is previewed on joinbookwyrm.com. Does not support html or markdown." %}
+
{% trans "Used when the instance is previewed on joinbookwyrm.com. Does not support HTML or Markdown." %}
{{ site_form.instance_short_description }}
diff --git a/bookwyrm/templates/shelf/shelf.html b/bookwyrm/templates/shelf/shelf.html
index fa1e91f98..662d75073 100644
--- a/bookwyrm/templates/shelf/shelf.html
+++ b/bookwyrm/templates/shelf/shelf.html
@@ -19,45 +19,58 @@
-
-
+
+
{% if is_self %}
+
+
{% trans "Create shelf" as button_text %}
{% include 'snippets/toggle/open_button.html' with text=button_text icon_with_text="plus" controls_text="create_shelf_form" focus="create_shelf_form_header" %}
-
{% trans "Import Books" %}
{% endif %}
-
+
{% include 'shelf/create_shelf_form.html' with controls_text='create_shelf_form' %}
diff --git a/bookwyrm/templates/snippets/add_to_group_button.html b/bookwyrm/templates/snippets/add_to_group_button.html
new file mode 100644
index 000000000..2785d7c01
--- /dev/null
+++ b/bookwyrm/templates/snippets/add_to_group_button.html
@@ -0,0 +1,34 @@
+{% load i18n %}
+{% load bookwyrm_group_tags %}
+{% if request.user == user or not request.user == group.user or not request.user.is_authenticated %}
+{% elif user in request.user.blocks.all %}
+{% include 'snippets/block_button.html' with blocks=True %}
+{% else %}
+
+
+
+
+ {% csrf_token %}
+
+
+
+ {% trans "Invite" %}
+
+
+
+ {% csrf_token %}
+
+
+ {% if not group|is_member:user %}
+
+ {% trans "Uninvite" %}
+
+ {% else %}
+
+ {% blocktrans with username=user.localname %}Remove @{{ username }}{% endblocktrans %}
+
+ {% endif %}
+
+
+
+{% endif %}
diff --git a/bookwyrm/templates/snippets/join_invitation_buttons.html b/bookwyrm/templates/snippets/join_invitation_buttons.html
new file mode 100644
index 000000000..46c4071d4
--- /dev/null
+++ b/bookwyrm/templates/snippets/join_invitation_buttons.html
@@ -0,0 +1,16 @@
+{% load i18n %}
+{% load bookwyrm_group_tags %}
+{% if group|is_invited:request.user %}
+
+
+ {% csrf_token %}
+
+ {% trans "Accept" %}
+
+
+ {% csrf_token %}
+
+ {% trans "Delete" %}
+
+
+{% endif %}
diff --git a/bookwyrm/templates/snippets/privacy_select_no_followers.html b/bookwyrm/templates/snippets/privacy_select_no_followers.html
new file mode 100644
index 000000000..2c601e7ff
--- /dev/null
+++ b/bookwyrm/templates/snippets/privacy_select_no_followers.html
@@ -0,0 +1,21 @@
+{% load i18n %}
+{% load utilities %}
+
+ {% firstof privacy_uuid 0|uuid as uuid %}
+ {% if not no_label %}
+ {% trans "Post privacy" %}
+ {% endif %}
+ {% firstof current user.default_post_privacy "public" as privacy %}
+
+
+ {% trans "Public" %}
+
+
+ {% trans "Unlisted" %}
+
+
+ {% trans "Private" %}
+
+
+
+
diff --git a/bookwyrm/templates/snippets/remove_from_group_button.html b/bookwyrm/templates/snippets/remove_from_group_button.html
new file mode 100644
index 000000000..1672e0388
--- /dev/null
+++ b/bookwyrm/templates/snippets/remove_from_group_button.html
@@ -0,0 +1,24 @@
+{% load i18n %}
+{% load bookwyrm_group_tags %}
+{% if request.user == user or not request.user == group.user or not request.user.is_authenticated %}
+{% else %}
+{% if user in request.user.blocks.all %}
+{% include 'snippets/block_button.html' with blocks=True %}
+
+{% endif %}
+
+
+
+ {% csrf_token %}
+
+
+
+ {% trans "Confirm" %}
+
+
+ {% trans "Remove" %}
+
+
+
+
+{% endif %}
diff --git a/bookwyrm/templates/user/groups.html b/bookwyrm/templates/user/groups.html
new file mode 100644
index 000000000..6f3619fd3
--- /dev/null
+++ b/bookwyrm/templates/user/groups.html
@@ -0,0 +1,37 @@
+{% extends 'user/layout.html' %}
+{% load i18n %}
+
+{% block header %}
+
+
+
+ {% if is_self %}
+ {% trans "Your Groups" %}
+ {% else %}
+ {% blocktrans with username=user.display_name %}Groups: {{ username }}{% endblocktrans %}
+ {% endif %}
+
+
+ {% if is_self %}
+
+ {% trans "Create group" as button_text %}
+ {% include 'snippets/toggle/open_button.html' with controls_text="create_group" icon_with_text="plus" text=button_text %}
+
+ {% endif %}
+
+{% endblock %}
+
+
+{% block panel %}
+
+
+
+ {% include 'groups/create_form.html' with controls_text="create_group" %}
+
+
+ {% include 'groups/user_groups.html' with memberships=memberships %}
+
+
+ {% include 'snippets/pagination.html' with page=user.memberships path=path %}
+
+{% endblock %}
diff --git a/bookwyrm/templates/user/layout.html b/bookwyrm/templates/user/layout.html
index 8ca3bd180..d7557ae7b 100755
--- a/bookwyrm/templates/user/layout.html
+++ b/bookwyrm/templates/user/layout.html
@@ -4,6 +4,7 @@
{% load utilities %}
{% load markdown %}
{% load layout %}
+{% load bookwyrm_group_tags %}
{% block title %}{{ user.display_name }}{% endblock %}
@@ -69,6 +70,12 @@
{% trans "Reading Goal" %}
{% endif %}
+ {% if is_self or user|has_groups %}
+ {% url 'user-groups' user|username as url %}
+
+ {% trans "Groups" %}
+
+ {% endif %}
{% if is_self or user.list_set.exists %}
{% url 'user-lists' user|username as url %}
diff --git a/bookwyrm/templatetags/bookwyrm_group_tags.py b/bookwyrm/templatetags/bookwyrm_group_tags.py
new file mode 100644
index 000000000..fde7997e8
--- /dev/null
+++ b/bookwyrm/templatetags/bookwyrm_group_tags.py
@@ -0,0 +1,27 @@
+""" template filters """
+from django import template
+
+from bookwyrm import models
+
+register = template.Library()
+
+
+@register.filter(name="has_groups")
+def has_groups(user):
+ """whether or not the user has a pending invitation to join this group"""
+
+ return models.GroupMember.objects.filter(user=user).exists()
+
+
+@register.filter(name="is_member")
+def is_member(group, user):
+ """whether or not the user is a member of this group"""
+
+ return models.GroupMember.objects.filter(group=group, user=user).exists()
+
+
+@register.filter(name="is_invited")
+def is_invited(group, user):
+ """whether or not the user has a pending invitation to join this group"""
+
+ return models.GroupMemberInvitation.objects.filter(group=group, user=user).exists()
diff --git a/bookwyrm/tests/models/test_group.py b/bookwyrm/tests/models/test_group.py
new file mode 100644
index 000000000..33341d192
--- /dev/null
+++ b/bookwyrm/tests/models/test_group.py
@@ -0,0 +1,126 @@
+""" testing models """
+from unittest.mock import patch
+from django.test import TestCase
+
+from bookwyrm import models, settings
+
+
+@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
+class Group(TestCase):
+ """some activitypub oddness ahead"""
+
+ def setUp(self):
+ """Set up for tests"""
+
+ with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
+ "bookwyrm.activitystreams.populate_stream_task.delay"
+ ):
+ self.owner_user = models.User.objects.create_user(
+ "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
+ )
+
+ with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
+ "bookwyrm.activitystreams.populate_stream_task.delay"
+ ):
+ self.rat = models.User.objects.create_user(
+ "rat", "rat@rat.rat", "ratword", local=True, localname="rat"
+ )
+
+ with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
+ "bookwyrm.activitystreams.populate_stream_task.delay"
+ ):
+ self.badger = models.User.objects.create_user(
+ "badger",
+ "badger@badger.badger",
+ "badgerword",
+ local=True,
+ localname="badger",
+ )
+
+ with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
+ "bookwyrm.activitystreams.populate_stream_task.delay"
+ ):
+ self.capybara = models.User.objects.create_user(
+ "capybara",
+ "capybara@capybara.capybara",
+ "capybaraword",
+ local=True,
+ localname="capybara",
+ )
+
+ self.public_group = models.Group.objects.create(
+ name="Public Group",
+ description="Initial description",
+ user=self.owner_user,
+ privacy="public",
+ )
+
+ self.private_group = models.Group.objects.create(
+ name="Private Group",
+ description="Top secret",
+ user=self.owner_user,
+ privacy="direct",
+ )
+
+ self.followers_only_group = models.Group.objects.create(
+ name="Followers Group",
+ description="No strangers",
+ user=self.owner_user,
+ privacy="followers",
+ )
+
+ models.GroupMember.objects.create(group=self.private_group, user=self.badger)
+ models.GroupMember.objects.create(
+ group=self.followers_only_group, user=self.badger
+ )
+ models.GroupMember.objects.create(group=self.public_group, user=self.capybara)
+
+ def test_group_members_can_see_private_groups(self, _):
+ """direct privacy group should not be excluded from group listings for group members viewing"""
+
+ rat_groups = models.Group.privacy_filter(self.rat).all()
+ badger_groups = models.Group.privacy_filter(self.badger).all()
+
+ self.assertFalse(self.private_group in rat_groups)
+ self.assertTrue(self.private_group in badger_groups)
+
+ def test_group_members_can_see_followers_only_lists(self, _):
+ """follower-only group booklists should not be excluded from group booklist listing for group members who do not follower list owner"""
+
+ with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
+ followers_list = models.List.objects.create(
+ name="Followers List",
+ curation="group",
+ privacy="followers",
+ group=self.public_group,
+ user=self.owner_user,
+ )
+
+ rat_lists = models.List.privacy_filter(self.rat).all()
+ badger_lists = models.List.privacy_filter(self.badger).all()
+ capybara_lists = models.List.privacy_filter(self.capybara).all()
+
+ self.assertFalse(followers_list in rat_lists)
+ self.assertFalse(followers_list in badger_lists)
+ self.assertTrue(followers_list in capybara_lists)
+
+ def test_group_members_can_see_private_lists(self, _):
+ """private group booklists should not be excluded from group booklist listing for group members"""
+
+ with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
+
+ private_list = models.List.objects.create(
+ name="Private List",
+ privacy="direct",
+ curation="group",
+ group=self.public_group,
+ user=self.owner_user,
+ )
+
+ rat_lists = models.List.privacy_filter(self.rat).all()
+ badger_lists = models.List.privacy_filter(self.badger).all()
+ capybara_lists = models.List.privacy_filter(self.capybara).all()
+
+ self.assertFalse(private_list in rat_lists)
+ self.assertFalse(private_list in badger_lists)
+ self.assertTrue(private_list in capybara_lists)
diff --git a/bookwyrm/tests/test_suggested_users.py b/bookwyrm/tests/test_suggested_users.py
index 6b794b5dc..f625ac10c 100644
--- a/bookwyrm/tests/test_suggested_users.py
+++ b/bookwyrm/tests/test_suggested_users.py
@@ -35,11 +35,18 @@ class SuggestedUsers(TestCase):
rank = suggested_users.get_rank(annotated_user_mock)
self.assertEqual(rank, 3) # 3.9642857142857144)
- def test_store_id(self, *_):
- """redis key generation"""
+ def test_store_id_from_obj(self, *_):
+ """redis key generation by user obj"""
self.assertEqual(
suggested_users.store_id(self.local_user),
- "{:d}-suggestions".format(self.local_user.id),
+ f"{self.local_user.id}-suggestions",
+ )
+
+ def test_store_id_from_id(self, *_):
+ """redis key generation by user id"""
+ self.assertEqual(
+ suggested_users.store_id(self.local_user.id),
+ f"{self.local_user.id}-suggestions",
)
def test_get_counts_from_rank(self, *_):
@@ -69,21 +76,74 @@ class SuggestedUsers(TestCase):
suggestable_user.followers.add(mutual_user)
results = suggested_users.get_objects_for_store(
- "{:d}-suggestions".format(self.local_user.id)
+ f"{self.local_user.id}-suggestions"
)
self.assertEqual(results.count(), 1)
match = results.first()
self.assertEqual(match.id, suggestable_user.id)
self.assertEqual(match.mutuals, 1)
- def test_create_user_signal(self, *_):
- """build suggestions for new users"""
- with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") as mock:
- models.User.objects.create_user(
- "nutria", "nutria@nu.tria", "password", local=True, localname="nutria"
- )
+ def test_get_stores_for_object(self, *_):
+ """possible follows"""
+ mutual_user = models.User.objects.create_user(
+ "rat", "rat@local.rat", "password", local=True, localname="rat"
+ )
+ suggestable_user = models.User.objects.create_user(
+ "nutria",
+ "nutria@nutria.nutria",
+ "password",
+ local=True,
+ localname="nutria",
+ discoverable=True,
+ )
- self.assertEqual(mock.call_count, 1)
+ # you follow rat
+ mutual_user.followers.add(self.local_user)
+ # rat follows the suggested user
+ suggestable_user.followers.add(mutual_user)
+
+ results = suggested_users.get_stores_for_object(self.local_user)
+ self.assertEqual(len(results), 1)
+ self.assertEqual(results[0], f"{suggestable_user.id}-suggestions")
+
+ def test_get_users_for_object(self, *_):
+ """given a user, who might want to follow them"""
+ mutual_user = models.User.objects.create_user(
+ "rat", "rat@local.rat", "password", local=True, localname="rat"
+ )
+ suggestable_user = models.User.objects.create_user(
+ "nutria",
+ "nutria@nutria.nutria",
+ "password",
+ local=True,
+ localname="nutria",
+ discoverable=True,
+ )
+ # you follow rat
+ mutual_user.followers.add(self.local_user)
+ # rat follows the suggested user
+ suggestable_user.followers.add(mutual_user)
+
+ results = suggested_users.get_users_for_object(self.local_user)
+ self.assertEqual(len(results), 1)
+ self.assertEqual(results[0], suggestable_user)
+
+ def test_rerank_user_suggestions(self, *_):
+ """does it call the populate store function correctly"""
+ with patch(
+ "bookwyrm.suggested_users.SuggestedUsers.populate_store"
+ ) as store_mock:
+ suggested_users.rerank_user_suggestions(self.local_user)
+ args = store_mock.call_args[0]
+ self.assertEqual(args[0], f"{self.local_user.id}-suggestions")
+
+ def test_get_suggestions(self, *_):
+ """load from store"""
+ with patch("bookwyrm.suggested_users.SuggestedUsers.get_store") as mock:
+ mock.return_value = [(self.local_user.id, 7.9)]
+ results = suggested_users.get_suggestions(self.local_user)
+ self.assertEqual(results[0], self.local_user)
+ self.assertEqual(results[0].mutuals, 7)
def test_get_annotated_users(self, *_):
"""list of people you might know"""
@@ -144,8 +204,8 @@ class SuggestedUsers(TestCase):
)
for i in range(3):
user = models.User.objects.create_user(
- "{:d}@local.com".format(i),
- "{:d}@nutria.com".format(i),
+ f"{i}@local.com",
+ f"{i}@nutria.com",
"password",
local=True,
localname=i,
@@ -175,3 +235,12 @@ class SuggestedUsers(TestCase):
)
user_1_annotated = result.get(id=user_1.id)
self.assertEqual(user_1_annotated.mutuals, 3)
+
+ def test_create_user_signal(self, *_):
+ """build suggestions for new users"""
+ with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") as mock:
+ models.User.objects.create_user(
+ "nutria", "nutria@nu.tria", "password", local=True, localname="nutria"
+ )
+
+ self.assertEqual(mock.call_count, 1)
diff --git a/bookwyrm/tests/views/books/test_edit_book.py b/bookwyrm/tests/views/books/test_edit_book.py
index 85bbc032c..7bf5708f8 100644
--- a/bookwyrm/tests/views/books/test_edit_book.py
+++ b/bookwyrm/tests/views/books/test_edit_book.py
@@ -58,6 +58,17 @@ class EditBookViews(TestCase):
validate_html(result.render())
self.assertEqual(result.status_code, 200)
+ def test_edit_book_create_page(self):
+ """there are so many views, this just makes sure it LOADS"""
+ view = views.EditBook.as_view()
+ request = self.factory.get("")
+ request.user = self.local_user
+ request.user.is_superuser = True
+ result = view(request)
+ self.assertIsInstance(result, TemplateResponse)
+ validate_html(result.render())
+ self.assertEqual(result.status_code, 200)
+
def test_edit_book(self):
"""lets a user edit a book"""
view = views.EditBook.as_view()
diff --git a/bookwyrm/tests/views/landing/__init__.py b/bookwyrm/tests/views/landing/__init__.py
new file mode 100644
index 000000000..b6e690fd5
--- /dev/null
+++ b/bookwyrm/tests/views/landing/__init__.py
@@ -0,0 +1 @@
+from . import *
diff --git a/bookwyrm/tests/views/test_invite.py b/bookwyrm/tests/views/landing/test_invite.py
similarity index 94%
rename from bookwyrm/tests/views/test_invite.py
rename to bookwyrm/tests/views/landing/test_invite.py
index c1e425c8c..a93821a9e 100644
--- a/bookwyrm/tests/views/test_invite.py
+++ b/bookwyrm/tests/views/landing/test_invite.py
@@ -8,6 +8,7 @@ from django.test.client import RequestFactory
from bookwyrm import forms, models
from bookwyrm import views
+from bookwyrm.tests.validate_html import validate_html
class InviteViews(TestCase):
@@ -40,7 +41,7 @@ class InviteViews(TestCase):
invite.return_value = True
result = view(request, "hi")
self.assertIsInstance(result, TemplateResponse)
- result.render()
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_manage_invites(self):
@@ -51,7 +52,7 @@ class InviteViews(TestCase):
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
- result.render()
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_manage_invites_post(self):
@@ -67,7 +68,7 @@ class InviteViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
- result.render()
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
invite = models.SiteInvite.objects.get()
@@ -83,7 +84,7 @@ class InviteViews(TestCase):
request = self.factory.post("", form.data)
result = view(request)
- result.render()
+ validate_html(result.render())
req = models.InviteRequest.objects.get()
self.assertEqual(req.email, "new@user.email")
@@ -97,7 +98,7 @@ class InviteViews(TestCase):
request = self.factory.post("", form.data)
result = view(request)
- result.render()
+ validate_html(result.render())
# no request created
self.assertFalse(models.InviteRequest.objects.exists())
@@ -110,14 +111,14 @@ class InviteViews(TestCase):
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
- result.render()
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
# now with data
models.InviteRequest.objects.create(email="fish@example.com")
result = view(request)
self.assertIsInstance(result, TemplateResponse)
- result.render()
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_manage_invite_requests_send(self):
diff --git a/bookwyrm/tests/views/test_landing.py b/bookwyrm/tests/views/landing/test_landing.py
similarity index 93%
rename from bookwyrm/tests/views/test_landing.py
rename to bookwyrm/tests/views/landing/test_landing.py
index f3a50fbc2..829919177 100644
--- a/bookwyrm/tests/views/test_landing.py
+++ b/bookwyrm/tests/views/landing/test_landing.py
@@ -7,6 +7,7 @@ from django.test.client import RequestFactory
from bookwyrm import models
from bookwyrm import views
+from bookwyrm.tests.validate_html import validate_html
class LandingViews(TestCase):
@@ -38,13 +39,13 @@ class LandingViews(TestCase):
with patch("bookwyrm.activitystreams.ActivityStream.get_activity_stream"):
result = view(request)
self.assertEqual(result.status_code, 200)
- result.render()
+ validate_html(result.render())
request.user = self.anonymous_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
self.assertEqual(result.status_code, 200)
- result.render()
+ validate_html(result.render())
def test_about_page(self):
"""there are so many views, this just makes sure it LOADS"""
@@ -53,7 +54,7 @@ class LandingViews(TestCase):
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
- result.render()
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_landing(self):
diff --git a/bookwyrm/tests/views/test_login.py b/bookwyrm/tests/views/landing/test_login.py
similarity index 91%
rename from bookwyrm/tests/views/test_login.py
rename to bookwyrm/tests/views/landing/test_login.py
index c37eaa514..0f86fb791 100644
--- a/bookwyrm/tests/views/test_login.py
+++ b/bookwyrm/tests/views/landing/test_login.py
@@ -7,6 +7,7 @@ from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
+from bookwyrm.tests.validate_html import validate_html
# pylint: disable=too-many-public-methods
@@ -41,7 +42,7 @@ class LoginViews(TestCase):
result = login(request)
self.assertIsInstance(result, TemplateResponse)
- result.render()
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
request.user = self.local_user
@@ -58,7 +59,7 @@ class LoginViews(TestCase):
request = self.factory.post("", form.data)
request.user = self.anonymous_user
- with patch("bookwyrm.views.login.login"):
+ with patch("bookwyrm.views.landing.login.login"):
result = view(request)
self.assertEqual(result.url, "/")
self.assertEqual(result.status_code, 302)
@@ -72,7 +73,7 @@ class LoginViews(TestCase):
request = self.factory.post("", form.data)
request.user = self.anonymous_user
- with patch("bookwyrm.views.login.login"):
+ with patch("bookwyrm.views.landing.login.login"):
result = view(request)
self.assertEqual(result.url, "/")
self.assertEqual(result.status_code, 302)
@@ -86,7 +87,7 @@ class LoginViews(TestCase):
request = self.factory.post("", form.data)
request.user = self.anonymous_user
- with patch("bookwyrm.views.login.login"):
+ with patch("bookwyrm.views.landing.login.login"):
result = view(request)
self.assertEqual(result.url, "/")
self.assertEqual(result.status_code, 302)
@@ -100,9 +101,9 @@ class LoginViews(TestCase):
request = self.factory.post("", form.data)
request.user = self.anonymous_user
- with patch("bookwyrm.views.login.login"):
+ with patch("bookwyrm.views.landing.login.login"):
result = view(request)
- result.render()
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertEqual(
result.context_data["login_form"].non_field_errors,
diff --git a/bookwyrm/tests/views/test_password.py b/bookwyrm/tests/views/landing/test_password.py
similarity index 69%
rename from bookwyrm/tests/views/test_password.py
rename to bookwyrm/tests/views/landing/test_password.py
index 47d8bb27b..f01565ef7 100644
--- a/bookwyrm/tests/views/test_password.py
+++ b/bookwyrm/tests/views/landing/test_password.py
@@ -1,12 +1,16 @@
""" test for app action functionality """
+from datetime import timedelta
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
+from django.core.exceptions import PermissionDenied
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
+from django.utils import timezone
from bookwyrm import models, views
+from bookwyrm.tests.validate_html import validate_html
class PasswordViews(TestCase):
@@ -37,7 +41,7 @@ class PasswordViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
- result.render()
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_password_reset_request_post(self):
@@ -47,13 +51,13 @@ class PasswordViews(TestCase):
view = views.PasswordResetRequest.as_view()
resp = view(request)
self.assertEqual(resp.status_code, 200)
- resp.render()
+ validate_html(resp.render())
request = self.factory.post("", {"email": "mouse@mouse.com"})
request.user = self.anonymous_user
with patch("bookwyrm.emailing.send_email.delay"):
resp = view(request)
- resp.render()
+ validate_html(resp.render())
self.assertEqual(models.PasswordReset.objects.get().user, self.local_user)
@@ -65,15 +69,43 @@ class PasswordViews(TestCase):
request.user = self.anonymous_user
result = view(request, code.code)
self.assertIsInstance(result, TemplateResponse)
- result.render()
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
+ def test_password_reset_nonexistant_code(self):
+ """there are so many views, this just makes sure it LOADS"""
+ view = views.PasswordReset.as_view()
+ request = self.factory.get("")
+ request.user = self.anonymous_user
+ with self.assertRaises(PermissionDenied):
+ view(request, "beep")
+
+ def test_password_reset_invalid_code(self):
+ """there are so many views, this just makes sure it LOADS"""
+ view = views.PasswordReset.as_view()
+ code = models.PasswordReset.objects.create(
+ user=self.local_user, expiry=timezone.now() - timedelta(days=2)
+ )
+ request = self.factory.get("")
+ request.user = self.anonymous_user
+ with self.assertRaises(PermissionDenied):
+ view(request, code.code)
+
+ def test_password_reset_logged_in(self):
+ """redirect logged in users"""
+ view = views.PasswordReset.as_view()
+ code = models.PasswordReset.objects.create(user=self.local_user)
+ request = self.factory.get("")
+ request.user = self.local_user
+ result = view(request, code.code)
+ self.assertEqual(result.status_code, 302)
+
def test_password_reset_post(self):
"""reset from code"""
view = views.PasswordReset.as_view()
code = models.PasswordReset.objects.create(user=self.local_user)
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
- with patch("bookwyrm.views.password.login"):
+ with patch("bookwyrm.views.landing.password.login"):
resp = view(request, code.code)
self.assertEqual(resp.status_code, 302)
self.assertFalse(models.PasswordReset.objects.exists())
@@ -84,7 +116,7 @@ class PasswordViews(TestCase):
models.PasswordReset.objects.create(user=self.local_user)
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
resp = view(request, "jhgdkfjgdf")
- resp.render()
+ validate_html(resp.render())
self.assertTrue(models.PasswordReset.objects.exists())
def test_password_reset_mismatch(self):
@@ -93,5 +125,5 @@ class PasswordViews(TestCase):
code = models.PasswordReset.objects.create(user=self.local_user)
request = self.factory.post("", {"password": "hi", "confirm-password": "hihi"})
resp = view(request, code.code)
- resp.render()
+ validate_html(resp.render())
self.assertTrue(models.PasswordReset.objects.exists())
diff --git a/bookwyrm/tests/views/test_register.py b/bookwyrm/tests/views/landing/test_register.py
similarity index 77%
rename from bookwyrm/tests/views/test_register.py
rename to bookwyrm/tests/views/landing/test_register.py
index 764081ef9..99f38da21 100644
--- a/bookwyrm/tests/views/test_register.py
+++ b/bookwyrm/tests/views/landing/test_register.py
@@ -10,6 +10,7 @@ from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.settings import DOMAIN
+from bookwyrm.tests.validate_html import validate_html
# pylint: disable=too-many-public-methods
@@ -38,6 +39,13 @@ class RegisterViews(TestCase):
id=1, require_confirm_email=False
)
+ def test_get_redirect(self, *_):
+ """there's no dedicated registration page"""
+ view = views.Register.as_view()
+ request = self.factory.get("register/")
+ response = view(request)
+ self.assertEqual(response.status_code, 302)
+
def test_register(self, *_):
"""create a user"""
view = views.Register.as_view()
@@ -50,12 +58,12 @@ class RegisterViews(TestCase):
"email": "aa@bb.cccc",
},
)
- with patch("bookwyrm.views.register.login"):
+ with patch("bookwyrm.views.landing.register.login"):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)
self.assertEqual(response.status_code, 302)
nutria = models.User.objects.last()
- self.assertEqual(nutria.username, "nutria-user.user_nutria@%s" % DOMAIN)
+ self.assertEqual(nutria.username, f"nutria-user.user_nutria@{DOMAIN}")
self.assertEqual(nutria.localname, "nutria-user.user_nutria")
self.assertEqual(nutria.local, True)
@@ -75,11 +83,11 @@ class RegisterViews(TestCase):
"email": "aa@bb.cccc",
},
)
- with patch("bookwyrm.views.register.login"):
+ with patch("bookwyrm.views.landing.register.login"):
response = view(request)
self.assertEqual(response.status_code, 302)
nutria = models.User.objects.get(localname="nutria")
- self.assertEqual(nutria.username, "nutria@%s" % DOMAIN)
+ self.assertEqual(nutria.username, f"nutria@{DOMAIN}")
self.assertEqual(nutria.local, True)
self.assertFalse(nutria.is_active)
@@ -93,12 +101,12 @@ class RegisterViews(TestCase):
"register/",
{"localname": "nutria ", "password": "mouseword", "email": "aa@bb.ccc"},
)
- with patch("bookwyrm.views.register.login"):
+ with patch("bookwyrm.views.landing.register.login"):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)
self.assertEqual(response.status_code, 302)
nutria = models.User.objects.last()
- self.assertEqual(nutria.username, "nutria@%s" % DOMAIN)
+ self.assertEqual(nutria.username, f"nutria@{DOMAIN}")
self.assertEqual(nutria.localname, "nutria")
self.assertEqual(nutria.local, True)
@@ -111,7 +119,43 @@ class RegisterViews(TestCase):
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
- response.render()
+ validate_html(response.render())
+
+ def test_register_error_and_invite(self, *_):
+ """redirect to the invite page"""
+ view = views.Register.as_view()
+ self.settings.allow_registration = False
+ self.settings.save()
+ models.SiteInvite.objects.create(
+ code="testcode", user=self.local_user, use_limit=1
+ )
+ self.assertEqual(models.SiteInvite.objects.get().times_used, 0)
+
+ request = self.factory.post(
+ "register/",
+ {
+ "localname": "nutria",
+ "password": "mouseword",
+ "email": "",
+ "invite_code": "testcode",
+ },
+ )
+ with patch("bookwyrm.views.landing.register.login"):
+ response = view(request)
+ response = view(request)
+ validate_html(response.render())
+
+ def test_register_username_in_use(self, *_):
+ """that username is taken"""
+ view = views.Register.as_view()
+ self.assertEqual(models.User.objects.count(), 1)
+ request = self.factory.post(
+ "register/",
+ {"localname": "mouse", "password": "mouseword", "email": "aa@bb.ccc"},
+ )
+ response = view(request)
+ self.assertEqual(models.User.objects.count(), 1)
+ validate_html(response.render())
def test_register_invalid_username(self, *_):
"""gotta have an email"""
@@ -123,7 +167,7 @@ class RegisterViews(TestCase):
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
- response.render()
+ validate_html(response.render())
request = self.factory.post(
"register/",
@@ -131,7 +175,7 @@ class RegisterViews(TestCase):
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
- response.render()
+ validate_html(response.render())
request = self.factory.post(
"register/",
@@ -139,7 +183,7 @@ class RegisterViews(TestCase):
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
- response.render()
+ validate_html(response.render())
def test_register_closed_instance(self, *_):
"""you can't just register"""
@@ -172,7 +216,7 @@ class RegisterViews(TestCase):
"register/",
{"localname": "nutria ", "password": "mouseword", "email": "aa@bleep.com"},
)
- with patch("bookwyrm.views.register.login"):
+ with patch("bookwyrm.views.landing.register.login"):
result = view(request)
self.assertEqual(result.status_code, 302)
self.assertTrue(models.User.objects.filter(email="aa@bleep.com").exists())
@@ -196,7 +240,7 @@ class RegisterViews(TestCase):
"invite_code": "testcode",
},
)
- with patch("bookwyrm.views.register.login"):
+ with patch("bookwyrm.views.landing.register.login"):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)
self.assertEqual(response.status_code, 302)
@@ -277,7 +321,7 @@ class RegisterViews(TestCase):
result = view(request, "abcde")
self.assertIsInstance(result, TemplateResponse)
- result.render()
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertFalse(self.local_user.is_active)
self.assertEqual(self.local_user.deactivation_reason, "pending")
@@ -293,10 +337,32 @@ class RegisterViews(TestCase):
result = login(request)
self.assertIsInstance(result, TemplateResponse)
- result.render()
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
request.user = self.local_user
result = login(request)
self.assertEqual(result.url, "/")
self.assertEqual(result.status_code, 302)
+
+ def test_confirm_email_post(self, *_):
+ """send the email"""
+ self.settings.require_confirm_email = True
+ self.settings.save()
+ view = views.ConfirmEmail.as_view()
+ models.SiteInvite.objects.create(
+ code="testcode", user=self.local_user, use_limit=1
+ )
+ request = self.factory.post("", {"code": "testcode"})
+ request.user = self.anonymous_user
+
+ result = view(request)
+ validate_html(result.render())
+
+ def test_resend_link(self, *_):
+ """try again"""
+ request = self.factory.post("", {"email": "mouse@mouse.com"})
+ request.user = self.anonymous_user
+ with patch("bookwyrm.emailing.send_email.delay") as mock:
+ views.resend_link(request)
+ self.assertEqual(mock.call_count, 1)
diff --git a/bookwyrm/tests/views/shelf/__init__.py b/bookwyrm/tests/views/shelf/__init__.py
new file mode 100644
index 000000000..b6e690fd5
--- /dev/null
+++ b/bookwyrm/tests/views/shelf/__init__.py
@@ -0,0 +1 @@
+from . import *
diff --git a/bookwyrm/tests/views/shelf/test_shelf.py b/bookwyrm/tests/views/shelf/test_shelf.py
new file mode 100644
index 000000000..71df3631f
--- /dev/null
+++ b/bookwyrm/tests/views/shelf/test_shelf.py
@@ -0,0 +1,165 @@
+""" test for app action functionality """
+from unittest.mock import patch
+
+from django.contrib.auth.models import AnonymousUser
+from django.template.response import TemplateResponse
+from django.test import TestCase
+from django.test.client import RequestFactory
+
+from bookwyrm import models, views
+from bookwyrm.activitypub import ActivitypubResponse
+from bookwyrm.tests.validate_html import validate_html
+
+
+@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
+@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
+@patch("bookwyrm.activitystreams.populate_stream_task.delay")
+@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
+@patch("bookwyrm.activitystreams.remove_book_statuses_task.delay")
+class ShelfViews(TestCase):
+ """tag views"""
+
+ def setUp(self):
+ """we need basic test data and mocks"""
+ self.factory = RequestFactory()
+ with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
+ "bookwyrm.activitystreams.populate_stream_task.delay"
+ ):
+ self.local_user = models.User.objects.create_user(
+ "mouse@local.com",
+ "mouse@mouse.com",
+ "mouseword",
+ local=True,
+ localname="mouse",
+ remote_id="https://example.com/users/mouse",
+ )
+ self.work = models.Work.objects.create(title="Test Work")
+ self.book = models.Edition.objects.create(
+ title="Example Edition",
+ remote_id="https://example.com/book/1",
+ parent_work=self.work,
+ )
+ with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
+ self.shelf = models.Shelf.objects.create(
+ name="Test Shelf", identifier="test-shelf", user=self.local_user
+ )
+ models.SiteSettings.objects.create()
+
+ self.anonymous_user = AnonymousUser
+ self.anonymous_user.is_authenticated = False
+
+ def test_shelf_page_all_books(self, *_):
+ """there are so many views, this just makes sure it LOADS"""
+ view = views.Shelf.as_view()
+ request = self.factory.get("")
+ request.user = self.local_user
+ with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api:
+ is_api.return_value = False
+ result = view(request, self.local_user.username)
+ self.assertIsInstance(result, TemplateResponse)
+ validate_html(result.render())
+ self.assertEqual(result.status_code, 200)
+
+ def test_shelf_page_all_books_anonymous(self, *_):
+ """there are so many views, this just makes sure it LOADS"""
+ view = views.Shelf.as_view()
+ request = self.factory.get("")
+ request.user = self.anonymous_user
+ with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api:
+ is_api.return_value = False
+ result = view(request, self.local_user.username)
+ self.assertIsInstance(result, TemplateResponse)
+ validate_html(result.render())
+ self.assertEqual(result.status_code, 200)
+
+ def test_shelf_page_sorted(self, *_):
+ """there are so many views, this just makes sure it LOADS"""
+ view = views.Shelf.as_view()
+ shelf = self.local_user.shelf_set.first()
+ request = self.factory.get("", {"sort": "author"})
+ request.user = self.local_user
+ with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api:
+ is_api.return_value = False
+ result = view(request, self.local_user.username, shelf.identifier)
+ self.assertIsInstance(result, TemplateResponse)
+ validate_html(result.render())
+ self.assertEqual(result.status_code, 200)
+
+ def test_shelf_page(self, *_):
+ """there are so many views, this just makes sure it LOADS"""
+ view = views.Shelf.as_view()
+ shelf = self.local_user.shelf_set.first()
+ request = self.factory.get("")
+ request.user = self.local_user
+ with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api:
+ is_api.return_value = False
+ result = view(request, self.local_user.username, shelf.identifier)
+ self.assertIsInstance(result, TemplateResponse)
+ validate_html(result.render())
+ self.assertEqual(result.status_code, 200)
+
+ with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api:
+ is_api.return_value = True
+ result = view(request, self.local_user.username, shelf.identifier)
+ self.assertIsInstance(result, ActivitypubResponse)
+ self.assertEqual(result.status_code, 200)
+
+ request = self.factory.get("/?page=1")
+ request.user = self.local_user
+ with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api:
+ is_api.return_value = True
+ result = view(request, self.local_user.username, shelf.identifier)
+ self.assertIsInstance(result, ActivitypubResponse)
+ self.assertEqual(result.status_code, 200)
+
+ def test_edit_shelf_privacy(self, *_):
+ """set name or privacy on shelf"""
+ view = views.Shelf.as_view()
+ shelf = self.local_user.shelf_set.get(identifier="to-read")
+ self.assertEqual(shelf.privacy, "public")
+
+ request = self.factory.post(
+ "",
+ {
+ "privacy": "unlisted",
+ "user": self.local_user.id,
+ "name": "To Read",
+ },
+ )
+ request.user = self.local_user
+ view(request, self.local_user.username, shelf.identifier)
+ shelf.refresh_from_db()
+
+ self.assertEqual(shelf.privacy, "unlisted")
+
+ def test_edit_shelf_name(self, *_):
+ """change the name of an editable shelf"""
+ view = views.Shelf.as_view()
+ shelf = models.Shelf.objects.create(name="Test Shelf", user=self.local_user)
+ self.assertEqual(shelf.privacy, "public")
+
+ request = self.factory.post(
+ "", {"privacy": "public", "user": self.local_user.id, "name": "cool name"}
+ )
+ request.user = self.local_user
+ with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
+ view(request, request.user.username, shelf.identifier)
+ shelf.refresh_from_db()
+
+ self.assertEqual(shelf.name, "cool name")
+ self.assertEqual(shelf.identifier, f"testshelf-{shelf.id}")
+
+ def test_edit_shelf_name_not_editable(self, *_):
+ """can't change the name of an non-editable shelf"""
+ view = views.Shelf.as_view()
+ shelf = self.local_user.shelf_set.get(identifier="to-read")
+ self.assertEqual(shelf.privacy, "public")
+
+ request = self.factory.post(
+ "", {"privacy": "public", "user": self.local_user.id, "name": "cool name"}
+ )
+ request.user = self.local_user
+ with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
+ view(request, request.user.username, shelf.identifier)
+
+ self.assertEqual(shelf.name, "To Read")
diff --git a/bookwyrm/tests/views/test_shelf.py b/bookwyrm/tests/views/shelf/test_shelf_actions.py
similarity index 70%
rename from bookwyrm/tests/views/test_shelf.py
rename to bookwyrm/tests/views/shelf/test_shelf_actions.py
index b78e241cc..3efae0f45 100644
--- a/bookwyrm/tests/views/test_shelf.py
+++ b/bookwyrm/tests/views/shelf/test_shelf_actions.py
@@ -3,13 +3,10 @@ import json
from unittest.mock import patch
from django.core.exceptions import PermissionDenied
-from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
-from bookwyrm.activitypub import ActivitypubResponse
-from bookwyrm.tests.validate_html import validate_html
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@@ -17,7 +14,7 @@ from bookwyrm.tests.validate_html import validate_html
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
@patch("bookwyrm.activitystreams.remove_book_statuses_task.delay")
-class ShelfViews(TestCase):
+class ShelfActionViews(TestCase):
"""tag views"""
def setUp(self):
@@ -46,85 +43,6 @@ class ShelfViews(TestCase):
)
models.SiteSettings.objects.create()
- def test_shelf_page(self, *_):
- """there are so many views, this just makes sure it LOADS"""
- view = views.Shelf.as_view()
- shelf = self.local_user.shelf_set.first()
- request = self.factory.get("")
- request.user = self.local_user
- with patch("bookwyrm.views.shelf.is_api_request") as is_api:
- is_api.return_value = False
- result = view(request, self.local_user.username, shelf.identifier)
- self.assertIsInstance(result, TemplateResponse)
- validate_html(result.render())
- self.assertEqual(result.status_code, 200)
-
- with patch("bookwyrm.views.shelf.is_api_request") as is_api:
- is_api.return_value = True
- result = view(request, self.local_user.username, shelf.identifier)
- self.assertIsInstance(result, ActivitypubResponse)
- self.assertEqual(result.status_code, 200)
-
- request = self.factory.get("/?page=1")
- request.user = self.local_user
- with patch("bookwyrm.views.shelf.is_api_request") as is_api:
- is_api.return_value = True
- result = view(request, self.local_user.username, shelf.identifier)
- self.assertIsInstance(result, ActivitypubResponse)
- self.assertEqual(result.status_code, 200)
-
- def test_edit_shelf_privacy(self, *_):
- """set name or privacy on shelf"""
- view = views.Shelf.as_view()
- shelf = self.local_user.shelf_set.get(identifier="to-read")
- self.assertEqual(shelf.privacy, "public")
-
- request = self.factory.post(
- "",
- {
- "privacy": "unlisted",
- "user": self.local_user.id,
- "name": "To Read",
- },
- )
- request.user = self.local_user
- view(request, self.local_user.username, shelf.identifier)
- shelf.refresh_from_db()
-
- self.assertEqual(shelf.privacy, "unlisted")
-
- def test_edit_shelf_name(self, *_):
- """change the name of an editable shelf"""
- view = views.Shelf.as_view()
- shelf = models.Shelf.objects.create(name="Test Shelf", user=self.local_user)
- self.assertEqual(shelf.privacy, "public")
-
- request = self.factory.post(
- "", {"privacy": "public", "user": self.local_user.id, "name": "cool name"}
- )
- request.user = self.local_user
- with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
- view(request, request.user.username, shelf.identifier)
- shelf.refresh_from_db()
-
- self.assertEqual(shelf.name, "cool name")
- self.assertEqual(shelf.identifier, f"testshelf-{shelf.id}")
-
- def test_edit_shelf_name_not_editable(self, *_):
- """can't change the name of an non-editable shelf"""
- view = views.Shelf.as_view()
- shelf = self.local_user.shelf_set.get(identifier="to-read")
- self.assertEqual(shelf.privacy, "public")
-
- request = self.factory.post(
- "", {"privacy": "public", "user": self.local_user.id, "name": "cool name"}
- )
- request.user = self.local_user
- with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
- view(request, request.user.username, shelf.identifier)
-
- self.assertEqual(shelf.name, "To Read")
-
def test_shelve(self, *_):
"""shelve a book"""
request = self.factory.post(
@@ -182,6 +100,30 @@ class ShelfViews(TestCase):
# make sure the book is on the shelf
self.assertEqual(shelf.books.get(), self.book)
+ def test_shelve_read_with_change_shelf(self, *_):
+ """special behavior for the read shelf"""
+ previous_shelf = models.Shelf.objects.get(identifier="reading")
+ models.ShelfBook.objects.create(
+ shelf=previous_shelf, user=self.local_user, book=self.book
+ )
+ shelf = models.Shelf.objects.get(identifier="read")
+
+ request = self.factory.post(
+ "",
+ {
+ "book": self.book.id,
+ "shelf": shelf.identifier,
+ "change-shelf-from": previous_shelf.identifier,
+ },
+ )
+ request.user = self.local_user
+
+ with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
+ views.shelve(request)
+ # make sure the book is on the shelf
+ self.assertEqual(shelf.books.get(), self.book)
+ self.assertEqual(list(previous_shelf.books.all()), [])
+
def test_unshelve(self, *_):
"""remove a book from a shelf"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
diff --git a/bookwyrm/tests/views/test_author.py b/bookwyrm/tests/views/test_author.py
index 7a0065c9e..ccbfe5493 100644
--- a/bookwyrm/tests/views/test_author.py
+++ b/bookwyrm/tests/views/test_author.py
@@ -1,6 +1,7 @@
""" test for app action functionality """
from unittest.mock import patch
-from django.contrib.auth.models import Group, Permission
+
+from django.contrib.auth.models import AnonymousUser, Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
from django.template.response import TemplateResponse
@@ -9,6 +10,7 @@ from django.test.client import RequestFactory
from bookwyrm import forms, models, views
from bookwyrm.activitypub import ActivitypubResponse
+from bookwyrm.tests.validate_html import validate_html
class AuthorViews(TestCase):
@@ -43,6 +45,8 @@ class AuthorViews(TestCase):
parent_work=self.work,
)
+ self.anonymous_user = AnonymousUser
+ self.anonymous_user.is_authenticated = False
models.SiteSettings.objects.create()
def test_author_page(self):
@@ -50,15 +54,33 @@ class AuthorViews(TestCase):
view = views.Author.as_view()
author = models.Author.objects.create(name="Jessica")
request = self.factory.get("")
+ request.user = self.local_user
with patch("bookwyrm.views.author.is_api_request") as is_api:
is_api.return_value = False
result = view(request, author.id)
self.assertIsInstance(result, TemplateResponse)
- result.render()
- self.assertEqual(result.status_code, 200)
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
+ def test_author_page_logged_out(self):
+ """there are so many views, this just makes sure it LOADS"""
+ view = views.Author.as_view()
+ author = models.Author.objects.create(name="Jessica")
request = self.factory.get("")
+ request.user = self.anonymous_user
+ with patch("bookwyrm.views.author.is_api_request") as is_api:
+ is_api.return_value = False
+ result = view(request, author.id)
+ self.assertIsInstance(result, TemplateResponse)
+ validate_html(result.render())
+ self.assertEqual(result.status_code, 200)
+
+ def test_author_page_api_response(self):
+ """there are so many views, this just makes sure it LOADS"""
+ view = views.Author.as_view()
+ author = models.Author.objects.create(name="Jessica")
+ request = self.factory.get("")
+ request.user = self.local_user
with patch("bookwyrm.views.author.is_api_request") as is_api:
is_api.return_value = True
result = view(request, author.id)
@@ -75,8 +97,7 @@ class AuthorViews(TestCase):
result = view(request, author.id)
self.assertIsInstance(result, TemplateResponse)
- result.render()
- self.assertEqual(result.status_code, 200)
+ validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_edit_author(self):
@@ -125,5 +146,5 @@ class AuthorViews(TestCase):
resp = view(request, author.id)
author.refresh_from_db()
self.assertEqual(author.name, "Test Author")
- resp.render()
+ validate_html(resp.render())
self.assertEqual(resp.status_code, 200)
diff --git a/bookwyrm/tests/views/test_group.py b/bookwyrm/tests/views/test_group.py
new file mode 100644
index 000000000..c7e0a0f76
--- /dev/null
+++ b/bookwyrm/tests/views/test_group.py
@@ -0,0 +1,119 @@
+""" test for app action functionality """
+from unittest.mock import patch
+from django.contrib.auth import decorators
+
+from django.template.response import TemplateResponse
+from django.test import TestCase
+from django.test.client import RequestFactory
+
+from bookwyrm import models, views, forms
+from bookwyrm.tests.validate_html import validate_html
+
+
+@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
+class GroupViews(TestCase):
+ """view group and edit details"""
+
+ def setUp(self):
+ """we need basic test data and mocks"""
+ self.factory = RequestFactory()
+ with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
+ "bookwyrm.activitystreams.populate_stream_task.delay"
+ ):
+ self.local_user = models.User.objects.create_user(
+ "mouse@local.com",
+ "mouse@mouse.mouse",
+ "password",
+ local=True,
+ localname="mouse",
+ )
+
+ self.testgroup = models.Group.objects.create(
+ name="Test Group",
+ description="Initial description",
+ user=self.local_user,
+ privacy="public",
+ )
+ self.membership = models.GroupMember.objects.create(
+ group=self.testgroup, user=self.local_user
+ )
+
+ models.SiteSettings.objects.create()
+
+ def test_group_get(self, _):
+ """there are so many views, this just makes sure it LOADS"""
+ view = views.Group.as_view()
+ request = self.factory.get("")
+ request.user = self.local_user
+ result = view(request, group_id=self.testgroup.id)
+ self.assertIsInstance(result, TemplateResponse)
+ validate_html(result.render())
+ self.assertEqual(result.status_code, 200)
+
+ def test_usergroups_get(self, _):
+ """there are so many views, this just makes sure it LOADS"""
+ view = views.UserGroups.as_view()
+ request = self.factory.get("")
+ request.user = self.local_user
+ result = view(request, username="mouse@local.com")
+ self.assertIsInstance(result, TemplateResponse)
+ validate_html(result.render())
+ self.assertEqual(result.status_code, 200)
+
+ @patch("bookwyrm.suggested_users.SuggestedUsers.get_suggestions")
+ def test_findusers_get(self, *_):
+ """there are so many views, this just makes sure it LOADS"""
+ view = views.FindUsers.as_view()
+ request = self.factory.get("")
+ request.user = self.local_user
+ result = view(request, group_id=self.testgroup.id)
+ self.assertIsInstance(result, TemplateResponse)
+ validate_html(result.render())
+ self.assertEqual(result.status_code, 200)
+
+ def test_group_create(self, _):
+ """create group view"""
+ view = views.UserGroups.as_view()
+ request = self.factory.post(
+ "",
+ {
+ "name": "A group",
+ "description": "wowzers",
+ "privacy": "unlisted",
+ "user": self.local_user.id,
+ },
+ )
+ request.user = self.local_user
+ result = view(request, "username")
+
+ self.assertEqual(result.status_code, 302)
+ new_group = models.Group.objects.filter(name="A group").get()
+ self.assertEqual(new_group.description, "wowzers")
+ self.assertEqual(new_group.privacy, "unlisted")
+ self.assertTrue(
+ models.GroupMember.objects.filter(
+ group=new_group, user=self.local_user
+ ).exists()
+ )
+
+ def test_group_edit(self, _):
+ """test editing a "group" database entry"""
+
+ view = views.Group.as_view()
+ request = self.factory.post(
+ "",
+ {
+ "name": "Updated Group name",
+ "description": "wow",
+ "privacy": "direct",
+ "user": self.local_user.id,
+ },
+ )
+ request.user = self.local_user
+
+ result = view(request, group_id=self.testgroup.id)
+ self.assertEqual(result.status_code, 302)
+ self.testgroup.refresh_from_db()
+ self.assertEqual(self.testgroup.name, "Updated Group name")
+ self.assertEqual(self.testgroup.description, "wow")
+ self.assertEqual(self.testgroup.privacy, "direct")
diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py
index e6c9ad0b4..839d783fd 100644
--- a/bookwyrm/urls.py
+++ b/bookwyrm/urls.py
@@ -253,6 +253,33 @@ urlpatterns = [
name="user-following",
),
re_path(r"^hide-suggestions/?$", views.hide_suggestions, name="hide-suggestions"),
+ # groups
+ re_path(rf"{USER_PATH}/groups/?$", views.UserGroups.as_view(), name="user-groups"),
+ re_path(
+ r"^group/(?P\d+)(.json)?/?$", views.Group.as_view(), name="group"
+ ),
+ re_path(
+ r"^group/delete/(?P\d+)/?$", views.delete_group, name="delete-group"
+ ),
+ re_path(
+ r"^group/(?P\d+)/add-users/?$",
+ views.FindUsers.as_view(),
+ name="group-find-users",
+ ),
+ re_path(r"^add-group-member/?$", views.invite_member, name="invite-group-member"),
+ re_path(
+ r"^remove-group-member/?$", views.remove_member, name="remove-group-member"
+ ),
+ re_path(
+ r"^accept-group-invitation/?$",
+ views.accept_membership,
+ name="accept-group-invitation",
+ ),
+ re_path(
+ r"^reject-group-invitation/?$",
+ views.reject_membership,
+ name="reject-group-invitation",
+ ),
# lists
re_path(rf"{USER_PATH}/lists/?$", views.UserLists.as_view(), name="user-lists"),
re_path(r"^list/?$", views.Lists.as_view(), name="lists"),
diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py
index 0ac231996..e1dd83557 100644
--- a/bookwyrm/views/__init__.py
+++ b/bookwyrm/views/__init__.py
@@ -32,6 +32,17 @@ from .books.books import Book, upload_cover, add_description, resolve_book
from .books.edit_book import EditBook, ConfirmEditBook
from .books.editions import Editions, switch_edition
+# landing
+from .landing.landing import About, Home, Landing
+from .landing.login import Login, Logout
+from .landing.register import Register, ConfirmEmail, ConfirmEmailCode, resend_link
+from .landing.password import PasswordResetRequest, PasswordReset
+
+# shelves
+from .shelf.shelf import Shelf
+from .shelf.shelf_actions import create_shelf, delete_shelf
+from .shelf.shelf_actions import shelve, unshelve
+
# misc views
from .author import Author, EditAuthor
from .directory import Directory
@@ -41,25 +52,28 @@ from .follow import follow, unfollow
from .follow import accept_follow_request, delete_follow_request
from .get_started import GetStartedBooks, GetStartedProfile, GetStartedUsers
from .goal import Goal, hide_goal
+from .group import (
+ Group,
+ UserGroups,
+ FindUsers,
+ delete_group,
+ invite_member,
+ remove_member,
+ accept_membership,
+ reject_membership,
+)
from .import_data import Import, ImportStatus
from .inbox import Inbox
from .interaction import Favorite, Unfavorite, Boost, Unboost
from .isbn import Isbn
-from .landing import About, Home, Landing
from .list import Lists, SavedLists, List, Curate, UserLists
from .list import save_list, unsave_list, delete_list
-from .login import Login, Logout
from .notifications import Notifications
from .outbox import Outbox
from .reading import create_readthrough, delete_readthrough, delete_progressupdate
from .reading import ReadingStatus
-from .register import Register, ConfirmEmail, ConfirmEmailCode, resend_link
from .rss_feed import RssFeed
-from .password import PasswordResetRequest, PasswordReset
from .search import Search
-from .shelf import Shelf
-from .shelf import create_shelf, delete_shelf
-from .shelf import shelve, unshelve
from .status import CreateStatus, EditStatus, DeleteStatus, update_progress
from .status import edit_readthrough
from .updates import get_notification_count, get_unread_status_count
diff --git a/bookwyrm/views/admin/invite.py b/bookwyrm/views/admin/invite.py
index 8a3db61a9..8fd68b705 100644
--- a/bookwyrm/views/admin/invite.py
+++ b/bookwyrm/views/admin/invite.py
@@ -81,7 +81,7 @@ class Invite(View):
"invite": invite,
"valid": invite.valid() if invite else True,
}
- return TemplateResponse(request, "invite.html", data)
+ return TemplateResponse(request, "landing/invite.html", data)
# post handling is in views.register.Register
diff --git a/bookwyrm/views/author.py b/bookwyrm/views/author.py
index e1e9247de..6c3ee36ff 100644
--- a/bookwyrm/views/author.py
+++ b/bookwyrm/views/author.py
@@ -1,6 +1,7 @@
""" the good people stuff! the authors! """
from django.contrib.auth.decorators import login_required, permission_required
-from django.db.models import Q
+from django.core.paginator import Paginator
+from django.db.models import OuterRef, Subquery, F, Q
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
@@ -8,7 +9,8 @@ from django.views import View
from bookwyrm import forms, models
from bookwyrm.activitypub import ActivitypubResponse
-from .helpers import is_api_request
+from bookwyrm.settings import PAGE_LENGTH
+from bookwyrm.views.helpers import is_api_request
# pylint: disable= no-self-use
@@ -22,12 +24,27 @@ class Author(View):
if is_api_request(request):
return ActivitypubResponse(author.to_activity())
- books = models.Work.objects.filter(
- Q(authors=author) | Q(editions__authors=author)
- ).distinct()
+ default_editions = models.Edition.objects.filter(
+ parent_work=OuterRef("parent_work")
+ ).order_by("-edition_rank")
+
+ books = (
+ models.Edition.viewer_aware_objects(request.user)
+ .filter(Q(authors=author) | Q(parent_work__authors=author))
+ .annotate(default_id=Subquery(default_editions.values("id")[:1]))
+ .filter(default_id=F("id"))
+ .order_by("-first_published_date", "-published_date", "-created_date")
+ .prefetch_related("authors")
+ )
+
+ paginated = Paginator(books, PAGE_LENGTH)
+ page = paginated.get_page(request.GET.get("page"))
data = {
"author": author,
- "books": [b.default_edition for b in books],
+ "books": page,
+ "page_range": paginated.get_elided_page_range(
+ page.number, on_each_side=2, on_ends=1
+ ),
}
return TemplateResponse(request, "author/author.html", data)
diff --git a/bookwyrm/views/group.py b/bookwyrm/views/group.py
new file mode 100644
index 000000000..9ee99bffa
--- /dev/null
+++ b/bookwyrm/views/group.py
@@ -0,0 +1,311 @@
+"""group views"""
+from django.apps import apps
+from django.contrib.auth.decorators import login_required
+from django.db import IntegrityError
+from django.core.paginator import Paginator
+from django.http import HttpResponseBadRequest
+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 django.contrib.postgres.search import TrigramSimilarity
+from django.db.models.functions import Greatest
+
+from bookwyrm import forms, models
+from bookwyrm.suggested_users import suggested_users
+from .helpers import get_user_from_username
+
+# pylint: disable=no-self-use
+class Group(View):
+ """group page"""
+
+ def get(self, request, group_id):
+ """display a group"""
+
+ group = get_object_or_404(models.Group, id=group_id)
+ group.raise_visible_to_user(request.user)
+ lists = (
+ models.List.privacy_filter(request.user)
+ .filter(group=group)
+ .order_by("-updated_date")
+ )
+
+ data = {
+ "group": group,
+ "lists": lists,
+ "group_form": forms.GroupForm(instance=group),
+ "path": "/group",
+ }
+ return TemplateResponse(request, "groups/group.html", data)
+
+ @method_decorator(login_required, name="dispatch")
+ def post(self, request, group_id):
+ """edit a group"""
+ user_group = get_object_or_404(models.Group, id=group_id)
+ form = forms.GroupForm(request.POST, instance=user_group)
+ if not form.is_valid():
+ return redirect("group", user_group.id)
+ user_group = form.save()
+
+ # let the other members know something about the group changed
+ memberships = models.GroupMember.objects.filter(group=user_group)
+ model = apps.get_model("bookwyrm.Notification", require_ready=True)
+ for field in form.changed_data:
+ notification_type = (
+ "GROUP_PRIVACY"
+ if field == "privacy"
+ else "GROUP_NAME"
+ if field == "name"
+ else "GROUP_DESCRIPTION"
+ if field == "description"
+ else None
+ )
+ if notification_type:
+ for membership in memberships:
+ member = membership.user
+ if member != request.user:
+ model.objects.create(
+ user=member,
+ related_user=request.user,
+ related_group=user_group,
+ notification_type=notification_type,
+ )
+
+ return redirect("group", user_group.id)
+
+
+@method_decorator(login_required, name="dispatch")
+class UserGroups(View):
+ """a user's groups page"""
+
+ def get(self, request, username):
+ """display a group"""
+ user = get_user_from_username(request.user, username)
+ groups = (
+ models.Group.privacy_filter(request.user)
+ .filter(memberships__user=user)
+ .order_by("-updated_date")
+ )
+ paginated = Paginator(groups, 12)
+
+ data = {
+ "groups": paginated.get_page(request.GET.get("page")),
+ "is_self": request.user.id == user.id,
+ "user": user,
+ "group_form": forms.GroupForm(),
+ "path": user.local_path + "/group",
+ }
+ return TemplateResponse(request, "user/groups.html", data)
+
+ @method_decorator(login_required, name="dispatch")
+ # pylint: disable=unused-argument
+ def post(self, request, username):
+ """create a user group"""
+ form = forms.GroupForm(request.POST)
+ if not form.is_valid():
+ return redirect(request.user.local_path + "/groups")
+ group = form.save()
+ # add the creator as a group member
+ models.GroupMember.objects.create(group=group, user=request.user)
+ return redirect("group", group.id)
+
+
+@method_decorator(login_required, name="dispatch")
+class FindUsers(View):
+ """find friends to add to your group"""
+
+ # this is mostly borrowed from the Get Started friend finder
+
+ def get(self, request, group_id):
+ """basic profile info"""
+ user_query = request.GET.get("user_query")
+ group = get_object_or_404(models.Group, id=group_id)
+
+ if not group:
+ return HttpResponseBadRequest()
+
+ if not group.user == request.user:
+ return HttpResponseBadRequest()
+
+ user_results = (
+ models.User.viewer_aware_objects(request.user)
+ .exclude(
+ memberships__in=group.memberships.all()
+ ) # don't suggest users who are already members
+ .annotate(
+ similarity=Greatest(
+ TrigramSimilarity("username", user_query),
+ TrigramSimilarity("localname", user_query),
+ )
+ )
+ .filter(similarity__gt=0.5, local=True)
+ .order_by("-similarity")[:5]
+ )
+ data = {"no_results": not user_results}
+
+ if user_results.count() < 5:
+ user_results = list(user_results) + suggested_users.get_suggestions(
+ request.user, local=True
+ )
+
+ data = {
+ "suggested_users": user_results,
+ "group": group,
+ "group_form": forms.GroupForm(instance=group),
+ "user_query": user_query,
+ "requestor_is_manager": request.user == group.user,
+ }
+ return TemplateResponse(request, "groups/find_users.html", data)
+
+
+@require_POST
+@login_required
+def delete_group(request, group_id):
+ """delete a group"""
+ group = get_object_or_404(models.Group, id=group_id)
+
+ # only the owner can delete a group
+ group.raise_not_deletable(request.user)
+
+ # deal with any group lists
+ models.List.objects.filter(group=group).update(curation="closed", group=None)
+
+ group.delete()
+ return redirect(request.user.local_path + "/groups")
+
+
+@require_POST
+@login_required
+def invite_member(request):
+ """invite a member to the group"""
+
+ group = get_object_or_404(models.Group, id=request.POST.get("group"))
+ if not group:
+ return HttpResponseBadRequest()
+
+ user = get_user_from_username(request.user, request.POST["user"])
+ if not user:
+ return HttpResponseBadRequest()
+
+ if not group.user == request.user:
+ return HttpResponseBadRequest()
+
+ try:
+ models.GroupMemberInvitation.objects.create(user=user, group=group)
+
+ except IntegrityError:
+ pass
+
+ return redirect(user.local_path)
+
+
+@require_POST
+@login_required
+def remove_member(request):
+ """remove a member from the group"""
+
+ group = get_object_or_404(models.Group, id=request.POST.get("group"))
+ if not group:
+ return HttpResponseBadRequest()
+
+ user = get_user_from_username(request.user, request.POST["user"])
+ if not user:
+ return HttpResponseBadRequest()
+
+ # you can't be removed from your own group
+ if request.POST["user"] == group.user:
+ return HttpResponseBadRequest()
+
+ is_member = models.GroupMember.objects.filter(group=group, user=user).exists()
+ is_invited = models.GroupMemberInvitation.objects.filter(
+ group=group, user=user
+ ).exists()
+
+ if is_invited:
+ try:
+ invitation = models.GroupMemberInvitation.objects.get(
+ user=user, group=group
+ )
+
+ invitation.reject()
+
+ except IntegrityError:
+ pass
+
+ if is_member:
+
+ try:
+ models.List.remove_from_group(group.user, user)
+ models.GroupMember.remove(group.user, user)
+
+ except IntegrityError:
+ pass
+
+ memberships = models.GroupMember.objects.filter(group=group)
+ model = apps.get_model("bookwyrm.Notification", require_ready=True)
+ notification_type = "LEAVE" if user == request.user else "REMOVE"
+ # let the other members know about it
+ for membership in memberships:
+ member = membership.user
+ if member != request.user:
+ model.objects.create(
+ user=member,
+ related_user=user,
+ related_group=group,
+ notification_type=notification_type,
+ )
+
+ # let the user (now ex-member) know as well, if they were removed
+ if notification_type == "REMOVE":
+ model.objects.create(
+ user=user,
+ related_group=group,
+ notification_type=notification_type,
+ )
+
+ return redirect(group.local_path)
+
+
+@require_POST
+@login_required
+def accept_membership(request):
+ """accept an invitation to join a group"""
+
+ group = models.Group.objects.get(id=request.POST["group"])
+ if not group:
+ return HttpResponseBadRequest()
+
+ invite = models.GroupMemberInvitation.objects.get(group=group, user=request.user)
+ if not invite:
+ return HttpResponseBadRequest()
+
+ try:
+ invite.accept()
+
+ except IntegrityError:
+ pass
+
+ return redirect(group.local_path)
+
+
+@require_POST
+@login_required
+def reject_membership(request):
+ """reject an invitation to join a group"""
+
+ group = models.Group.objects.get(id=request.POST["group"])
+ if not group:
+ return HttpResponseBadRequest()
+
+ invite = models.GroupMemberInvitation.objects.get(group=group, user=request.user)
+ if not invite:
+ return HttpResponseBadRequest()
+
+ try:
+ invite.reject()
+
+ except IntegrityError:
+ pass
+
+ return redirect(request.user.local_path)
diff --git a/bookwyrm/views/import_data.py b/bookwyrm/views/import_data.py
index fe54c39a9..5e113be88 100644
--- a/bookwyrm/views/import_data.py
+++ b/bookwyrm/views/import_data.py
@@ -51,7 +51,7 @@ class Import(View):
elif source == "Storygraph":
importer = StorygraphImporter()
else:
- # Default : GoodReads
+ # Default : Goodreads
importer = GoodreadsImporter()
try:
diff --git a/bookwyrm/views/landing/__init__.py b/bookwyrm/views/landing/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/bookwyrm/views/landing.py b/bookwyrm/views/landing/landing.py
similarity index 93%
rename from bookwyrm/views/landing.py
rename to bookwyrm/views/landing/landing.py
index 6f480b70f..c8bba0664 100644
--- a/bookwyrm/views/landing.py
+++ b/bookwyrm/views/landing/landing.py
@@ -3,8 +3,8 @@ from django.template.response import TemplateResponse
from django.views import View
from bookwyrm import forms
-from .feed import Feed
-from . import helpers
+from bookwyrm.views import helpers
+from bookwyrm.views.feed import Feed
# pylint: disable= no-self-use
diff --git a/bookwyrm/views/login.py b/bookwyrm/views/landing/login.py
similarity index 95%
rename from bookwyrm/views/login.py
rename to bookwyrm/views/landing/login.py
index 91fda35a3..5c25e30e2 100644
--- a/bookwyrm/views/login.py
+++ b/bookwyrm/views/landing/login.py
@@ -29,7 +29,7 @@ class Login(View):
"login_form": forms.LoginForm(),
"register_form": forms.RegisterForm(),
}
- return TemplateResponse(request, "login.html", data)
+ return TemplateResponse(request, "landing/login.html", data)
@sensitive_variables("password")
@method_decorator(sensitive_post_parameters("password"))
@@ -69,7 +69,7 @@ class Login(View):
login_form.non_field_errors = _("Username or password are incorrect")
register_form = forms.RegisterForm()
data = {"login_form": login_form, "register_form": register_form}
- return TemplateResponse(request, "login.html", data)
+ return TemplateResponse(request, "landing/login.html", data)
@method_decorator(login_required, name="dispatch")
diff --git a/bookwyrm/views/password.py b/bookwyrm/views/landing/password.py
similarity index 83%
rename from bookwyrm/views/password.py
rename to bookwyrm/views/landing/password.py
index d3104ad46..90713e29d 100644
--- a/bookwyrm/views/password.py
+++ b/bookwyrm/views/landing/password.py
@@ -18,7 +18,7 @@ class PasswordResetRequest(View):
"""password reset page"""
return TemplateResponse(
request,
- "password_reset_request.html",
+ "landing/password_reset_request.html",
)
def post(self, request):
@@ -30,7 +30,9 @@ class PasswordResetRequest(View):
)
except models.User.DoesNotExist:
data = {"error": _("No user with that email address was found.")}
- return TemplateResponse(request, "password_reset_request.html", data)
+ return TemplateResponse(
+ request, "landing/password_reset_request.html", data
+ )
# remove any existing password reset cods for this user
models.PasswordReset.objects.filter(user=user).all().delete()
@@ -39,7 +41,7 @@ class PasswordResetRequest(View):
code = models.PasswordReset.objects.create(user=user)
password_reset_email(code)
data = {"message": _(f"A password reset link was sent to {email}")}
- return TemplateResponse(request, "password_reset_request.html", data)
+ return TemplateResponse(request, "landing/password_reset_request.html", data)
class PasswordReset(View):
@@ -56,7 +58,7 @@ class PasswordReset(View):
except models.PasswordReset.DoesNotExist:
raise PermissionDenied()
- return TemplateResponse(request, "password_reset.html", {"code": code})
+ return TemplateResponse(request, "landing/password_reset.html", {"code": code})
def post(self, request, code):
"""allow a user to change their password through an emailed token"""
@@ -64,7 +66,7 @@ class PasswordReset(View):
reset_code = models.PasswordReset.objects.get(code=code)
except models.PasswordReset.DoesNotExist:
data = {"errors": ["Invalid password reset link"]}
- return TemplateResponse(request, "password_reset.html", data)
+ return TemplateResponse(request, "landing/password_reset.html", data)
user = reset_code.user
@@ -73,7 +75,7 @@ class PasswordReset(View):
if new_password != confirm_password:
data = {"errors": ["Passwords do not match"]}
- return TemplateResponse(request, "password_reset.html", data)
+ return TemplateResponse(request, "landing/password_reset.html", data)
user.set_password(new_password)
user.save(broadcast=False, update_fields=["password"])
diff --git a/bookwyrm/views/register.py b/bookwyrm/views/landing/register.py
similarity index 97%
rename from bookwyrm/views/register.py
rename to bookwyrm/views/landing/register.py
index dd8249203..b91d1b5a9 100644
--- a/bookwyrm/views/register.py
+++ b/bookwyrm/views/landing/register.py
@@ -65,8 +65,8 @@ class Register(View):
"valid": invite.valid() if invite else True,
}
if invite:
- return TemplateResponse(request, "invite.html", data)
- return TemplateResponse(request, "login.html", data)
+ return TemplateResponse(request, "landing/invite.html", data)
+ return TemplateResponse(request, "landing/login.html", data)
username = f"{localname}@{DOMAIN}"
user = models.User.objects.create_user(
diff --git a/bookwyrm/views/list.py b/bookwyrm/views/list.py
index b01a0e0e3..97eaf9d6f 100644
--- a/bookwyrm/views/list.py
+++ b/bookwyrm/views/list.py
@@ -40,7 +40,6 @@ class Lists(View):
.order_by("-updated_date")
.distinct()
)
-
paginated = Paginator(lists, 12)
data = {
"lists": paginated.get_page(request.GET.get("page")),
@@ -57,6 +56,10 @@ class Lists(View):
if not form.is_valid():
return redirect("lists")
book_list = form.save()
+ # list should not have a group if it is not group curated
+ if not book_list.curation == "group":
+ book_list.group = None
+ book_list.save(broadcast=False)
return redirect(book_list.local_path)
@@ -181,7 +184,6 @@ class List(View):
return TemplateResponse(request, "lists/list.html", data)
@method_decorator(login_required, name="dispatch")
- # pylint: disable=unused-argument
def post(self, request, list_id):
"""edit a list"""
book_list = get_object_or_404(models.List, id=list_id)
@@ -191,6 +193,10 @@ class List(View):
if not form.is_valid():
return redirect("list", book_list.id)
book_list = form.save()
+ if not book_list.curation == "group":
+ book_list.group = None
+ book_list.save(broadcast=False)
+
return redirect(book_list.local_path)
@@ -275,12 +281,22 @@ def delete_list(request, list_id):
def add_book(request):
"""put a book on a list"""
book_list = get_object_or_404(models.List, id=request.POST.get("list"))
+ is_group_member = False
+ if book_list.curation == "group":
+ is_group_member = models.GroupMember.objects.filter(
+ group=book_list.group, user=request.user
+ ).exists()
+
book_list.raise_visible_to_user(request.user)
book = get_object_or_404(models.Edition, id=request.POST.get("book"))
# do you have permission to add to the list?
try:
- if request.user == book_list.user or book_list.curation == "open":
+ if (
+ request.user == book_list.user
+ or is_group_member
+ or book_list.curation == "open"
+ ):
# add the book at the latest order of approved books, before pending books
order_max = (
book_list.listitem_set.filter(approved=True).aggregate(Max("order"))[
@@ -323,14 +339,17 @@ def add_book(request):
@login_required
def remove_book(request, list_id):
"""remove a book from a list"""
+
book_list = get_object_or_404(models.List, id=list_id)
item = get_object_or_404(models.ListItem, id=request.POST.get("item"))
+
item.raise_not_deletable(request.user)
with transaction.atomic():
deleted_order = item.order
item.delete()
normalize_book_list_ordering(book_list.id, start=deleted_order)
+
return redirect("list", list_id)
diff --git a/bookwyrm/views/preferences/block.py b/bookwyrm/views/preferences/block.py
index 1eccf4612..2ccd3c065 100644
--- a/bookwyrm/views/preferences/block.py
+++ b/bookwyrm/views/preferences/block.py
@@ -23,6 +23,10 @@ class Block(View):
models.UserBlocks.objects.create(
user_subject=request.user, user_object=to_block
)
+ # remove the blocked users's lists from the groups
+ models.List.remove_from_group(request.user, to_block)
+ # remove the blocked user from all blocker's owned groups
+ models.GroupMember.remove(request.user, to_block)
return redirect("prefs-block")
diff --git a/bookwyrm/views/shelf/__init__.py b/bookwyrm/views/shelf/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/bookwyrm/views/shelf.py b/bookwyrm/views/shelf/shelf.py
similarity index 60%
rename from bookwyrm/views/shelf.py
rename to bookwyrm/views/shelf/shelf.py
index 0b830d906..f8cffe93f 100644
--- a/bookwyrm/views/shelf.py
+++ b/bookwyrm/views/shelf/shelf.py
@@ -1,7 +1,6 @@
""" shelf views """
from collections import namedtuple
-from django.db import IntegrityError, transaction
from django.db.models import OuterRef, Subquery, F
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
@@ -11,12 +10,11 @@ from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.utils.translation import gettext_lazy as _
from django.views import View
-from django.views.decorators.http import require_POST
from bookwyrm import forms, models
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.settings import PAGE_LENGTH
-from .helpers import is_api_request, get_user_from_username
+from bookwyrm.views.helpers import is_api_request, get_user_from_username
# pylint: disable=no-self-use
@@ -128,102 +126,6 @@ class Shelf(View):
return redirect(shelf.local_path)
-@login_required
-@require_POST
-def create_shelf(request):
- """user generated shelves"""
- form = forms.ShelfForm(request.POST)
- if not form.is_valid():
- return redirect(request.headers.get("Referer", "/"))
-
- shelf = form.save()
- return redirect(shelf.local_path)
-
-
-@login_required
-@require_POST
-def delete_shelf(request, shelf_id):
- """user generated shelves"""
- shelf = get_object_or_404(models.Shelf, id=shelf_id)
- shelf.raise_not_deletable(request.user)
-
- shelf.delete()
- return redirect("user-shelves", request.user.localname)
-
-
-@login_required
-@require_POST
-@transaction.atomic
-def shelve(request):
- """put a book on a user's shelf"""
- book = get_object_or_404(models.Edition, id=request.POST.get("book"))
- desired_shelf = get_object_or_404(
- request.user.shelf_set, identifier=request.POST.get("shelf")
- )
-
- # first we need to remove from the specified shelf
- change_from_current_identifier = request.POST.get("change-shelf-from")
- if change_from_current_identifier:
- # find the shelfbook obj and delete it
- get_object_or_404(
- models.ShelfBook,
- book=book,
- user=request.user,
- shelf__identifier=change_from_current_identifier,
- ).delete()
-
- # A book can be on multiple shelves, but only on one read status shelf at a time
- if desired_shelf.identifier in models.Shelf.READ_STATUS_IDENTIFIERS:
- # figure out where state shelf it's currently on (if any)
- current_read_status_shelfbook = (
- models.ShelfBook.objects.select_related("shelf")
- .filter(
- shelf__identifier__in=models.Shelf.READ_STATUS_IDENTIFIERS,
- user=request.user,
- book=book,
- )
- .first()
- )
- if current_read_status_shelfbook is not None:
- if (
- current_read_status_shelfbook.shelf.identifier
- != desired_shelf.identifier
- ):
- current_read_status_shelfbook.delete()
- else: # It is already on the shelf
- return redirect(request.headers.get("Referer", "/"))
-
- # create the new shelf-book entry
- models.ShelfBook.objects.create(
- book=book, shelf=desired_shelf, user=request.user
- )
- else:
- # we're putting it on a custom shelf
- try:
- models.ShelfBook.objects.create(
- book=book, shelf=desired_shelf, user=request.user
- )
- # The book is already on this shelf.
- # Might be good to alert, or reject the action?
- except IntegrityError:
- pass
- return redirect(request.headers.get("Referer", "/"))
-
-
-@login_required
-@require_POST
-def unshelve(request):
- """put a on a user's shelf"""
- book = get_object_or_404(models.Edition, id=request.POST.get("book"))
- shelf_book = get_object_or_404(
- models.ShelfBook, book=book, shelf__id=request.POST["shelf"]
- )
- shelf_book.raise_not_deletable(request.user)
-
- shelf_book.delete()
- return redirect(request.headers.get("Referer", "/"))
-
-
def sort_books(books, sort):
"""Books in shelf sorting"""
sort_fields = [
diff --git a/bookwyrm/views/shelf/shelf_actions.py b/bookwyrm/views/shelf/shelf_actions.py
new file mode 100644
index 000000000..702b72c13
--- /dev/null
+++ b/bookwyrm/views/shelf/shelf_actions.py
@@ -0,0 +1,103 @@
+""" shelf views """
+from django.db import IntegrityError, transaction
+from django.contrib.auth.decorators import login_required
+from django.shortcuts import get_object_or_404, redirect
+from django.views.decorators.http import require_POST
+
+from bookwyrm import forms, models
+
+
+@login_required
+@require_POST
+def create_shelf(request):
+ """user generated shelves"""
+ form = forms.ShelfForm(request.POST)
+ if not form.is_valid():
+ return redirect(request.headers.get("Referer", "/"))
+
+ shelf = form.save()
+ return redirect(shelf.local_path)
+
+
+@login_required
+@require_POST
+def delete_shelf(request, shelf_id):
+ """user generated shelves"""
+ shelf = get_object_or_404(models.Shelf, id=shelf_id)
+ shelf.raise_not_deletable(request.user)
+
+ shelf.delete()
+ return redirect("user-shelves", request.user.localname)
+
+
+@login_required
+@require_POST
+@transaction.atomic
+def shelve(request):
+ """put a book on a user's shelf"""
+ book = get_object_or_404(models.Edition, id=request.POST.get("book"))
+ desired_shelf = get_object_or_404(
+ request.user.shelf_set, identifier=request.POST.get("shelf")
+ )
+
+ # first we need to remove from the specified shelf
+ change_from_current_identifier = request.POST.get("change-shelf-from")
+ if change_from_current_identifier:
+ # find the shelfbook obj and delete it
+ get_object_or_404(
+ models.ShelfBook,
+ book=book,
+ user=request.user,
+ shelf__identifier=change_from_current_identifier,
+ ).delete()
+
+ # A book can be on multiple shelves, but only on one read status shelf at a time
+ if desired_shelf.identifier in models.Shelf.READ_STATUS_IDENTIFIERS:
+ # figure out where state shelf it's currently on (if any)
+ current_read_status_shelfbook = (
+ models.ShelfBook.objects.select_related("shelf")
+ .filter(
+ shelf__identifier__in=models.Shelf.READ_STATUS_IDENTIFIERS,
+ user=request.user,
+ book=book,
+ )
+ .first()
+ )
+ if current_read_status_shelfbook is not None:
+ if (
+ current_read_status_shelfbook.shelf.identifier
+ != desired_shelf.identifier
+ ):
+ current_read_status_shelfbook.delete()
+ else: # It is already on the shelf
+ return redirect(request.headers.get("Referer", "/"))
+
+ # create the new shelf-book entry
+ models.ShelfBook.objects.create(
+ book=book, shelf=desired_shelf, user=request.user
+ )
+ else:
+ # we're putting it on a custom shelf
+ try:
+ models.ShelfBook.objects.create(
+ book=book, shelf=desired_shelf, user=request.user
+ )
+ # The book is already on this shelf.
+ # Might be good to alert, or reject the action?
+ except IntegrityError:
+ pass
+ return redirect(request.headers.get("Referer", "/"))
+
+
+@login_required
+@require_POST
+def unshelve(request):
+ """remove a book from a user's shelf"""
+ book = get_object_or_404(models.Edition, id=request.POST.get("book"))
+ shelf_book = get_object_or_404(
+ models.ShelfBook, book=book, shelf__id=request.POST["shelf"]
+ )
+ shelf_book.raise_not_deletable(request.user)
+
+ shelf_book.delete()
+ return redirect(request.headers.get("Referer", "/"))
diff --git a/bookwyrm/views/user.py b/bookwyrm/views/user.py
index 0d8d385b1..b7ab1d3cf 100644
--- a/bookwyrm/views/user.py
+++ b/bookwyrm/views/user.py
@@ -137,6 +137,25 @@ class Following(View):
return TemplateResponse(request, "user/relationships/following.html", data)
+class Groups(View):
+ """list of user's groups view"""
+
+ def get(self, request, username):
+ """list of groups"""
+ user = get_user_from_username(request.user, username)
+
+ paginated = Paginator(
+ models.Group.memberships.filter(user=user).order_by("-created_date"),
+ PAGE_LENGTH,
+ )
+ data = {
+ "user": user,
+ "is_self": request.user.id == user.id,
+ "group_list": paginated.get_page(request.GET.get("page")),
+ }
+ return TemplateResponse(request, "user/groups.html", data)
+
+
@require_POST
@login_required
def hide_suggestions(request):
diff --git a/locale/de_DE/LC_MESSAGES/django.mo b/locale/de_DE/LC_MESSAGES/django.mo
index 682f599d5..516685a0e 100644
Binary files a/locale/de_DE/LC_MESSAGES/django.mo and b/locale/de_DE/LC_MESSAGES/django.mo differ
diff --git a/locale/de_DE/LC_MESSAGES/django.po b/locale/de_DE/LC_MESSAGES/django.po
index de0fd4a48..8fd930fee 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: 2021-10-06 23:57+0000\n"
-"PO-Revision-Date: 2021-10-13 13:32\n"
+"POT-Creation-Date: 2021-10-15 22:03+0000\n"
+"PO-Revision-Date: 2021-10-20 17:38\n"
"Last-Translator: Mouse Reeve \n"
"Language-Team: German\n"
"Language: de\n"
@@ -54,8 +54,8 @@ msgstr "Reihenfolge der Liste"
msgid "Book Title"
msgstr "Buchtitel"
-#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:134
-#: bookwyrm/templates/shelf/shelf.html:165
+#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:136
+#: bookwyrm/templates/shelf/shelf.html:168
#: bookwyrm/templates/snippets/create_status/review.html:33
msgid "Rating"
msgstr "Bewertung"
@@ -90,11 +90,11 @@ msgstr "Selbstlöschung"
#: bookwyrm/models/base_model.py:19
msgid "Moderator suspension"
-msgstr "Moderator suspendieren"
+msgstr "Moderator*in suspendieren"
#: bookwyrm/models/base_model.py:20
msgid "Moderator deletion"
-msgstr "Moderatoren löschen"
+msgstr "Moderator*in löschen"
#: bookwyrm/models/base_model.py:21
msgid "Domain block"
@@ -151,45 +151,49 @@ msgstr "Username"
msgid "A user with that username already exists."
msgstr "Dieser Benutzename ist bereits vergeben."
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home Timeline"
msgstr "Start-Zeitleiste"
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home"
msgstr "Startseite"
-#: bookwyrm/settings.py:118
+#: bookwyrm/settings.py:119
msgid "Books Timeline"
msgstr "Bücher-Zeitachse"
-#: bookwyrm/settings.py:118 bookwyrm/templates/search/layout.html:21
+#: bookwyrm/settings.py:119 bookwyrm/templates/search/layout.html:21
#: bookwyrm/templates/search/layout.html:42
#: bookwyrm/templates/user/layout.html:81
msgid "Books"
msgstr "Bücher"
-#: bookwyrm/settings.py:164
+#: bookwyrm/settings.py:165
msgid "English"
msgstr "English (Englisch)"
-#: bookwyrm/settings.py:165
+#: bookwyrm/settings.py:166
msgid "Deutsch (German)"
msgstr "Deutsch"
-#: bookwyrm/settings.py:166
+#: bookwyrm/settings.py:167
msgid "Español (Spanish)"
msgstr "Español (Spanisch)"
-#: bookwyrm/settings.py:167
+#: bookwyrm/settings.py:168
msgid "Français (French)"
msgstr "Français (Französisch)"
-#: bookwyrm/settings.py:168
+#: bookwyrm/settings.py:169
+msgid "Português - Brasil (Brazilian Portuguese)"
+msgstr "Português (Portugiesisch)"
+
+#: bookwyrm/settings.py:170
msgid "简体中文 (Simplified Chinese)"
msgstr "简体中文 (Vereinfachtes Chinesisch)"
-#: bookwyrm/settings.py:169
+#: bookwyrm/settings.py:171
msgid "繁體中文 (Traditional Chinese)"
msgstr "繁體中文 (Chinesisch, traditionell)"
@@ -292,7 +296,7 @@ msgstr "Name:"
#: bookwyrm/templates/book/edit/edit_book_form.html:79
#: bookwyrm/templates/book/edit/edit_book_form.html:124
msgid "Separate multiple values with commas."
-msgstr "Geben Sie mehrere Werte durch Kommas getrennt ein."
+msgstr "Mehrere Werte durch Kommas getrennt eingeben."
#: bookwyrm/templates/author/edit_author.html:50
msgid "Bio:"
@@ -316,20 +320,20 @@ msgstr "Autor*innenidentifikatoren"
#: bookwyrm/templates/author/edit_author.html:81
msgid "Openlibrary key:"
-msgstr "Openlibrary Schlüssel:"
+msgstr "Openlibrary-Schlüssel:"
#: bookwyrm/templates/author/edit_author.html:89
#: bookwyrm/templates/book/edit/edit_book_form.html:224
msgid "Inventaire ID:"
-msgstr "Inventaire ID:"
+msgstr "Inventaire-ID:"
#: bookwyrm/templates/author/edit_author.html:97
msgid "Librarything key:"
-msgstr "Librarything Schlüssel:"
+msgstr "Librarything-Schlüssel:"
#: bookwyrm/templates/author/edit_author.html:105
msgid "Goodreads key:"
-msgstr "Goodreads Schlüssel:"
+msgstr "Goodreads-Schlüssel:"
#: bookwyrm/templates/author/edit_author.html:116
#: bookwyrm/templates/book/book.html:140
@@ -378,7 +382,7 @@ msgstr "Cover hinzufügen"
#: bookwyrm/templates/book/book.html:77
msgid "Failed to load cover"
-msgstr "Fehler beim Laden des Covers"
+msgstr "Fehler beim Laden des Titelbilds"
#: bookwyrm/templates/book/book.html:117
#, python-format
@@ -430,11 +434,11 @@ msgstr "Du hast keine Leseaktivität für dieses Buch."
#: bookwyrm/templates/book/book.html:218
msgid "Reviews"
-msgstr "Rezensionen"
+msgstr "Besprechungen"
#: bookwyrm/templates/book/book.html:223
msgid "Your reviews"
-msgstr "Deine Rezensionen"
+msgstr "Deine Besprechungen"
#: bookwyrm/templates/book/book.html:229
msgid "Your comments"
@@ -519,7 +523,7 @@ msgstr "Existiert \"%(name)s\" bereits als Autor:in?"
#: bookwyrm/templates/book/edit/edit_book.html:64
#, python-format
msgid "Author of %(book_title)s "
-msgstr "Autor von %(book_title)s "
+msgstr "Autor*in von %(book_title)s "
#: bookwyrm/templates/book/edit/edit_book.html:68
msgid "This is a new author"
@@ -587,7 +591,7 @@ msgstr "Veröffentlichungsdatum:"
#: bookwyrm/templates/book/edit/edit_book_form.html:104
msgid "Authors"
-msgstr "Autoren"
+msgstr "Autor*innen"
#: bookwyrm/templates/book/edit/edit_book_form.html:112
#, python-format
@@ -597,11 +601,11 @@ msgstr "%(name)s entfernen"
#: bookwyrm/templates/book/edit/edit_book_form.html:115
#, python-format
msgid "Author page for %(name)s"
-msgstr "Autorenseite für %(name)s"
+msgstr "Autor*innenseite für %(name)s"
#: bookwyrm/templates/book/edit/edit_book_form.html:122
msgid "Add Authors:"
-msgstr "Autoren hinzufügen:"
+msgstr "Autor*innen hinzufügen:"
#: bookwyrm/templates/book/edit/edit_book_form.html:123
msgid "John Doe, Jane Smith"
@@ -610,7 +614,7 @@ msgstr "Max Mustermann, Maria Musterfrau"
#: bookwyrm/templates/book/edit/edit_book_form.html:132
#: bookwyrm/templates/shelf/shelf.html:127
msgid "Cover"
-msgstr "Einband"
+msgstr "Titelbild"
#: bookwyrm/templates/book/edit/edit_book_form.html:161
msgid "Physical Properties"
@@ -643,7 +647,7 @@ msgstr "ISBN 10:"
#: bookwyrm/templates/book/edit/edit_book_form.html:216
msgid "Openlibrary ID:"
-msgstr "OpenLibrary ID:"
+msgstr "OpenLibrary-ID:"
#: bookwyrm/templates/book/editions/editions.html:4
#, python-format
@@ -669,11 +673,6 @@ msgstr "Sprache"
msgid "Search editions"
msgstr "Ausgaben suchen"
-#: bookwyrm/templates/book/publisher_info.html:21
-#, python-format
-msgid "%(format)s"
-msgstr "Formate: %(format)s"
-
#: bookwyrm/templates/book/publisher_info.html:23
#, python-format
msgid "%(format)s, %(pages)s pages"
@@ -687,7 +686,7 @@ msgstr "%(pages)s Seiten"
#: bookwyrm/templates/book/publisher_info.html:38
#, python-format
msgid "%(languages)s language"
-msgstr "%(languages)s Sprache"
+msgstr "%(languages)s-sprachig"
#: bookwyrm/templates/book/publisher_info.html:65
#, python-format
@@ -697,7 +696,7 @@ msgstr "Am %(date)s von %(publisher)s veröffentlicht."
#: bookwyrm/templates/book/publisher_info.html:67
#, python-format
msgid "Published %(date)s"
-msgstr "Erscheinungsdatum %(date)s"
+msgstr "Erschienen am %(date)s"
#: bookwyrm/templates/book/publisher_info.html:69
#, python-format
@@ -753,8 +752,8 @@ msgid "Help"
msgstr "Hilfe"
#: bookwyrm/templates/compose.html:5 bookwyrm/templates/compose.html:8
-msgid "Compose status"
-msgstr "Status verfassen"
+msgid "Edit status"
+msgstr "Status bearbeiten"
#: bookwyrm/templates/confirm_email/confirm_email.html:4
msgid "Confirm email"
@@ -762,7 +761,7 @@ msgstr "E-Mail bestätigen"
#: bookwyrm/templates/confirm_email/confirm_email.html:7
msgid "Confirm your email address"
-msgstr "Bestätigen Sie Ihre E-Mail-Adresse"
+msgstr "Bestätige deine E-Mail-Adresse"
#: bookwyrm/templates/confirm_email/confirm_email.html:13
msgid "A confirmation code has been sent to the email address you used to register your account."
@@ -854,13 +853,13 @@ msgstr "Empfohlen"
#: bookwyrm/templates/user/user_preview.html:16
#: bookwyrm/templates/user/user_preview.html:17
msgid "Locked account"
-msgstr "Gesperrter Account"
+msgstr "Gesperrtes Benutzer*inkonto"
#: bookwyrm/templates/directory/user_card.html:40
msgid "follower you follow"
msgid_plural "followers you follow"
-msgstr[0] "gegenseitiger Follower"
-msgstr[1] "gegenseitige Followers"
+msgstr[0] "Follower*in, dem*der du folgst"
+msgstr[1] "Follower*innen, denen du folgst"
#: bookwyrm/templates/directory/user_card.html:47
msgid "book on your shelves"
@@ -878,7 +877,7 @@ msgstr "zuletzt aktiv"
#: bookwyrm/templates/directory/user_type_filter.html:5
msgid "User type"
-msgstr "Art der Benutzer*innen"
+msgstr "Benutzer*in-Typ"
#: bookwyrm/templates/directory/user_type_filter.html:8
msgid "BookWyrm users"
@@ -888,6 +887,26 @@ msgstr "Bookwyrmnutzer*innen"
msgid "All known users"
msgstr "Alle bekannten Nutzer*innen"
+#: bookwyrm/templates/discover/card-header.html:9
+#, python-format
+msgid "%(username)s rated %(book_title)s "
+msgstr "%(username)s hat %(book_title)s bewertet "
+
+#: bookwyrm/templates/discover/card-header.html:13
+#, python-format
+msgid "%(username)s reviewed %(book_title)s "
+msgstr "%(username)s hat %(book_title)s besprochen "
+
+#: bookwyrm/templates/discover/card-header.html:17
+#, python-format
+msgid "%(username)s commented on %(book_title)s "
+msgstr "%(username)s hat %(book_title)s kommentiert "
+
+#: bookwyrm/templates/discover/card-header.html:21
+#, python-format
+msgid "%(username)s quoted %(book_title)s "
+msgstr "%(username)s hat %(book_title)s zitiert "
+
#: bookwyrm/templates/discover/discover.html:4
#: bookwyrm/templates/discover/discover.html:10
#: bookwyrm/templates/layout.html:78
@@ -899,28 +918,8 @@ msgstr "Entdecken"
msgid "See what's new in the local %(site_name)s community"
msgstr "Schau, was in der %(site_name)s Community neu ist"
-#: bookwyrm/templates/discover/large-book.html:46
-#: bookwyrm/templates/discover/small-book.html:32
-msgid "rated"
-msgstr "bewertet"
-
-#: bookwyrm/templates/discover/large-book.html:48
-#: bookwyrm/templates/discover/small-book.html:34
-msgid "reviewed"
-msgstr "bewertete"
-
-#: bookwyrm/templates/discover/large-book.html:50
-#: bookwyrm/templates/discover/small-book.html:36
-msgid "commented on"
-msgstr "kommentierte"
-
#: bookwyrm/templates/discover/large-book.html:52
-#: bookwyrm/templates/discover/small-book.html:38
-msgid "quoted"
-msgstr "zitierte"
-
-#: bookwyrm/templates/discover/large-book.html:68
-#: bookwyrm/templates/discover/small-book.html:52
+#: bookwyrm/templates/discover/small-book.html:36
msgid "View status"
msgstr "Status ansehen"
@@ -932,7 +931,7 @@ msgstr "Als letzten Schritt bevor du %(site_name)s beitrittst - bestätige bitte
#: bookwyrm/templates/email/confirm/html_content.html:11
msgid "Confirm Email"
-msgstr "E-Mail bestätigen"
+msgstr "E-Mail-Adresse bestätigen"
#: bookwyrm/templates/email/confirm/html_content.html:15
#, python-format
@@ -966,7 +965,7 @@ msgstr "E-Mail Einstellungen"
#: bookwyrm/templates/email/invite/subject.html:2
#, python-format
msgid "You're invited to join %(site_name)s!"
-msgstr "Du bist eingeladen %(site_name)s beizutreten!"
+msgstr "Du bist eingeladen, %(site_name)s beizutreten!"
#: bookwyrm/templates/email/invite/html_content.html:9
msgid "Join Now"
@@ -974,8 +973,8 @@ msgstr "Tritt jetzt bei"
#: bookwyrm/templates/email/invite/html_content.html:15
#, python-format
-msgid "Learn more about this instance ."
-msgstr "Erfahre mehr über diese Instanz ."
+msgid "Learn more about %(site_name)s ."
+msgstr "Erfahre mehr über %(site_name)s ."
#: bookwyrm/templates/email/invite/text_content.html:4
#, python-format
@@ -983,8 +982,9 @@ msgid "You're invited to join %(site_name)s! Click the link below to create an a
msgstr "Du bist eingeladen, %(site_name)s beizutreten! Klicke auf den Link unten um einen Account zu erstellen."
#: bookwyrm/templates/email/invite/text_content.html:8
-msgid "Learn more about this instance:"
-msgstr "Lerne mehr über diese Instanz:"
+#, python-format
+msgid "Learn more about %(site_name)s:"
+msgstr "Erfahre mehr über %(site_name)s:"
#: bookwyrm/templates/email/password_reset/html_content.html:6
#: bookwyrm/templates/email/password_reset/text_content.html:4
@@ -1070,7 +1070,7 @@ msgstr "Zu lesen"
#: bookwyrm/templates/feed/layout.html:26
#: bookwyrm/templates/shelf/shelf.html:40
msgid "Currently Reading"
-msgstr "Gegenwärtiger Lesestoff"
+msgstr "Lese ich gerade"
#: bookwyrm/templates/feed/layout.html:27
#: bookwyrm/templates/shelf/shelf.html:42
@@ -1134,7 +1134,7 @@ msgstr "Empfohlene Bücher"
#: bookwyrm/templates/get_started/books.html:46
#, python-format
msgid "Popular on %(site_name)s"
-msgstr "Beliebt auf %(site_name)s"
+msgstr "Auf %(site_name)s beliebt"
#: bookwyrm/templates/get_started/books.html:58
#: bookwyrm/templates/lists/list.html:154
@@ -1179,7 +1179,7 @@ msgstr "Schritt überspringen"
#: bookwyrm/templates/get_started/layout.html:49
msgid "Finish"
-msgstr "Fertig stellen"
+msgstr "Fertigstellen"
#: bookwyrm/templates/get_started/profile.html:15
#: bookwyrm/templates/preferences/edit_user.html:42
@@ -1216,7 +1216,7 @@ msgstr "Dein Account wird im Verzeichnis gezeigt und möglicherweise anderen Use
#: bookwyrm/templates/get_started/users.html:11
msgid "Search for a user"
-msgstr "Nach Benutzer*in suchen"
+msgstr "Benutzer*in suchen"
#: bookwyrm/templates/get_started/users.html:13
#, python-format
@@ -1265,7 +1265,7 @@ msgstr "Importstatus"
#: bookwyrm/templates/import/import_status.html:11
msgid "Back to imports"
-msgstr ""
+msgstr "Zurück zu Importen"
#: bookwyrm/templates/import/import_status.html:15
msgid "Import started:"
@@ -1299,7 +1299,7 @@ msgstr "Zum Ende der Liste springen, um die %(failed_count)s Einträge, deren Im
#: bookwyrm/templates/import/import_status.html:62
#, python-format
msgid "Line %(index)s: %(title)s by %(author)s"
-msgstr ""
+msgstr "Zeile %(index)s: %(title)s von %(author)s"
#: bookwyrm/templates/import/import_status.html:82
msgid "Select all"
@@ -1315,7 +1315,7 @@ msgstr "Erfolgreich importiert"
#: bookwyrm/templates/import/import_status.html:114
msgid "Import Progress"
-msgstr ""
+msgstr "Import-Fortschritt"
#: bookwyrm/templates/import/import_status.html:119
msgid "Book"
@@ -1323,13 +1323,13 @@ msgstr "Buch"
#: bookwyrm/templates/import/import_status.html:122
#: bookwyrm/templates/shelf/shelf.html:128
-#: bookwyrm/templates/shelf/shelf.html:148
+#: bookwyrm/templates/shelf/shelf.html:150
msgid "Title"
msgstr "Titel"
#: bookwyrm/templates/import/import_status.html:125
#: bookwyrm/templates/shelf/shelf.html:129
-#: bookwyrm/templates/shelf/shelf.html:151
+#: bookwyrm/templates/shelf/shelf.html:153
msgid "Author"
msgstr "Autor*in"
@@ -1338,8 +1338,8 @@ msgid "Imported"
msgstr "Importiert"
#: bookwyrm/templates/import/tooltip.html:6
-msgid "You can download your GoodReads data from the Import/Export page of your GoodReads account."
-msgstr "Du kannst dir deine GoodReads Daten von Import/Export page in deinem GoodReads Account runterladen."
+msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account."
+msgstr "Du kannst deine Goodreads-Daten von der Import/Export-Seite deines Goodreads-Kontos downloaden."
#: bookwyrm/templates/invite.html:4 bookwyrm/templates/invite.html:8
#: bookwyrm/templates/login.html:49
@@ -1354,7 +1354,7 @@ msgstr "Zugiff verweigert"
msgid "Sorry! This invite code is no longer valid."
msgstr "Sorry! Dieser Einladecode ist mehr gültig."
-#: bookwyrm/templates/landing/about.html:7
+#: bookwyrm/templates/landing/about.html:7 bookwyrm/templates/layout.html:230
#, python-format
msgid "About %(site_name)s"
msgstr "Über %(site_name)s"
@@ -1383,7 +1383,7 @@ msgstr "Freundlich"
#: bookwyrm/templates/landing/layout.html:29
msgid "Anti-Corporate"
-msgstr "Unkommerziell"
+msgstr "Nichtkommerziell"
#: bookwyrm/templates/landing/layout.html:45
#, python-format
@@ -1397,7 +1397,7 @@ msgstr "Einladung beantragen"
#: bookwyrm/templates/landing/layout.html:49
#, python-format
msgid "%(name)s registration is closed"
-msgstr "%(name)s Registrierung ist geschlossen"
+msgstr "%(name)s erlaubt keine Selbtregistrierung"
#: bookwyrm/templates/landing/layout.html:60
msgid "Thank you! Your request has been received."
@@ -1410,11 +1410,11 @@ msgstr "Dein Account"
#: bookwyrm/templates/layout.html:13
#, python-format
msgid "%(site_name)s search"
-msgstr "%(site_name)s Suche"
+msgstr "%(site_name)s-Suche"
#: bookwyrm/templates/layout.html:43
msgid "Search for a book, user, or list"
-msgstr "Nach einem Buch, einem Benutzer oder einer Liste suchen"
+msgstr "Nach einem Buch, einem*r Benutzer*in oder einer Liste suchen"
#: bookwyrm/templates/layout.html:61 bookwyrm/templates/layout.html:62
msgid "Main navigation menu"
@@ -1442,7 +1442,7 @@ msgstr "Einladungen"
#: bookwyrm/templates/layout.html:132
msgid "Admin"
-msgstr "Administrator"
+msgstr "Administration"
#: bookwyrm/templates/layout.html:139
msgid "Log out"
@@ -1458,7 +1458,7 @@ msgstr "Benachrichtigungen"
#: bookwyrm/templates/login.html:21
#: bookwyrm/templates/snippets/register_form.html:4
msgid "Username:"
-msgstr "Benutzername:"
+msgstr "Benutzer*inname:"
#: bookwyrm/templates/layout.html:175
msgid "password"
@@ -1479,16 +1479,12 @@ msgstr "Beitreten"
#: bookwyrm/templates/layout.html:221
msgid "Successfully posted status"
-msgstr "Status erfolgreich veröffentlicht"
+msgstr "Status veröffentlicht"
#: bookwyrm/templates/layout.html:222
msgid "Error posting status"
msgstr "Fehler beim veröffentlichen des Status"
-#: bookwyrm/templates/layout.html:230
-msgid "About this instance"
-msgstr "Über diese Instanz"
-
#: bookwyrm/templates/layout.html:234
msgid "Contact site admin"
msgstr "Admin kontaktieren"
@@ -1709,7 +1705,7 @@ msgstr "%(book_title)s zu deiner Liste \"
#: bookwyrm/templates/notifications/items/add.html:31
#, python-format
msgid "suggested adding %(book_title)s to your list \"%(list_name)s \""
-msgstr "%(book_title)s zu deiner Liste \"%(list_name)s \" vorgeschlagen"
+msgstr "hat vorgeschlagen, %(book_title)s zu deiner Liste „%(list_name)s “ hinzuzufügen"
#: bookwyrm/templates/notifications/items/boost.html:19
#, python-format
@@ -1733,22 +1729,22 @@ msgstr "hat deinen Status geteilt"
#: bookwyrm/templates/notifications/items/fav.html:19
#, python-format
-msgid "favorited your review of %(book_title)s "
-msgstr "hat deine Bewertung von %(book_title)s favorisiert"
+msgid "liked your review of %(book_title)s "
+msgstr "hat deine Besprechung von %(book_title)s favorisiert "
#: bookwyrm/templates/notifications/items/fav.html:25
#, python-format
-msgid "favorited your comment on%(book_title)s "
-msgstr "favorisierte deinen Kommentar zu%(book_title)s "
+msgid "liked your comment on%(book_title)s "
+msgstr "hat deinen Kommentar zu %(book_title)s favorisiert "
#: bookwyrm/templates/notifications/items/fav.html:31
#, python-format
-msgid "favorited your quote from %(book_title)s "
-msgstr " hat dein Zitat aus %(book_title)s favorisiert"
+msgid "liked your quote from %(book_title)s "
+msgstr "hat dein Zitat aus %(book_title)s favorisiert "
#: bookwyrm/templates/notifications/items/fav.html:37
#, python-format
-msgid "favorited your status "
+msgid "liked your status "
msgstr "hat deinen Status favorisiert"
#: bookwyrm/templates/notifications/items/follow.html:15
@@ -1815,7 +1811,7 @@ msgstr "Benachrichtigungen löschen"
#: bookwyrm/templates/notifications/notifications_page.html:29
msgid "All"
-msgstr "Alle"
+msgstr "Alle(s)"
#: bookwyrm/templates/notifications/notifications_page.html:33
msgid "Mentions"
@@ -1866,7 +1862,7 @@ msgstr "Neues Passwort:"
#: bookwyrm/templates/preferences/layout.html:24
#: bookwyrm/templates/settings/users/delete_user_form.html:23
msgid "Delete Account"
-msgstr "Account löschen"
+msgstr "Benutzer*inkonto löschen"
#: bookwyrm/templates/preferences/delete_user.html:12
msgid "Permanently delete account"
@@ -1900,7 +1896,7 @@ msgstr "Privatsphäre"
#: bookwyrm/templates/preferences/edit_user.html:72
msgid "Show reading goal prompt in feed:"
-msgstr "Zeige Lesezielabfrage im Feed:"
+msgstr "Zeige Leseziel-Abfrage im Feed:"
#: bookwyrm/templates/preferences/edit_user.html:76
msgid "Show suggested users:"
@@ -1921,7 +1917,7 @@ msgstr "Voreinstellung für Beitragssichtbarkeit:"
#: bookwyrm/templates/preferences/layout.html:11
msgid "Account"
-msgstr "Account"
+msgstr "Benutzer*inkonto"
#: bookwyrm/templates/preferences/layout.html:27
msgid "Relationships"
@@ -1940,7 +1936,7 @@ msgstr "\"%(book_title)s\" beginnen"
#: bookwyrm/templates/reading_progress/want.html:5
#, python-format
msgid "Want to Read \"%(book_title)s\""
-msgstr ""
+msgstr "\"%(book_title)s\" auf Leseliste setzen"
#: bookwyrm/templates/search/book.html:47
#: bookwyrm/templates/settings/reports/reports.html:25
@@ -1954,7 +1950,7 @@ msgstr "Buch importieren"
#: bookwyrm/templates/search/book.html:107
msgid "Load results from other catalogues"
-msgstr ""
+msgstr "Ergebnisse aus anderen Katalogen laden"
#: bookwyrm/templates/search/book.html:111
msgid "Manually add book"
@@ -1970,7 +1966,7 @@ msgstr "Suchanfrage"
#: bookwyrm/templates/search/layout.html:19
msgid "Search type"
-msgstr ""
+msgstr "Suchart"
#: bookwyrm/templates/search/layout.html:23
#: bookwyrm/templates/search/layout.html:46
@@ -1985,7 +1981,7 @@ msgstr "Benutzer*innen"
#: bookwyrm/templates/search/layout.html:58
#, python-format
msgid "No results found for \"%(query)s\""
-msgstr "Für \"%(query)s\" wurden keine Ergebnisse gefunden"
+msgstr "Keine Ergebnisse für „%(query)s“ gefunden"
#: bookwyrm/templates/settings/announcements/announcement.html:3
#: bookwyrm/templates/settings/announcements/announcement.html:6
@@ -2018,18 +2014,18 @@ msgstr "Nein"
#: bookwyrm/templates/settings/announcements/announcement_form.html:40
#: bookwyrm/templates/settings/dashboard/dashboard.html:71
msgid "Start date:"
-msgstr ""
+msgstr "Startdatum:"
#: bookwyrm/templates/settings/announcements/announcement.html:54
#: bookwyrm/templates/settings/announcements/announcement_form.html:49
#: bookwyrm/templates/settings/dashboard/dashboard.html:77
msgid "End date:"
-msgstr ""
+msgstr "Enddatum:"
#: bookwyrm/templates/settings/announcements/announcement.html:60
#: bookwyrm/templates/settings/announcements/announcement_form.html:58
msgid "Active:"
-msgstr ""
+msgstr "Aktiv:"
#: bookwyrm/templates/settings/announcements/announcement_form.html:8
#: bookwyrm/templates/settings/announcements/announcements.html:8
@@ -2046,7 +2042,7 @@ msgstr "Inhalt:"
#: bookwyrm/templates/settings/announcements/announcement_form.html:30
msgid "Event date:"
-msgstr ""
+msgstr "Ereignisdatum:"
#: bookwyrm/templates/settings/announcements/announcements.html:3
#: bookwyrm/templates/settings/announcements/announcements.html:5
@@ -2065,11 +2061,11 @@ msgstr "Vorschau"
#: bookwyrm/templates/settings/announcements/announcements.html:30
msgid "Start date"
-msgstr ""
+msgstr "Startdatum"
#: bookwyrm/templates/settings/announcements/announcements.html:34
msgid "End date"
-msgstr ""
+msgstr "Enddatum"
#: bookwyrm/templates/settings/announcements/announcements.html:38
#: bookwyrm/templates/settings/federation/instance_list.html:46
@@ -2082,11 +2078,11 @@ msgstr "Status"
#: bookwyrm/templates/settings/announcements/announcements.html:48
msgid "active"
-msgstr ""
+msgstr "aktiv"
#: bookwyrm/templates/settings/announcements/announcements.html:48
msgid "inactive"
-msgstr ""
+msgstr "inaktiv"
#: bookwyrm/templates/settings/announcements/announcements.html:52
msgid "No announcements found"
@@ -2101,7 +2097,7 @@ msgstr "Übersicht"
#: bookwyrm/templates/settings/dashboard/dashboard.html:15
#: bookwyrm/templates/settings/dashboard/dashboard.html:100
msgid "Total users"
-msgstr ""
+msgstr "Benutzer*innen insgesamt"
#: bookwyrm/templates/settings/dashboard/dashboard.html:21
#: bookwyrm/templates/settings/dashboard/user_chart.html:16
@@ -2110,12 +2106,12 @@ msgstr "Diesen Monat aktiv"
#: bookwyrm/templates/settings/dashboard/dashboard.html:27
msgid "Statuses"
-msgstr "Statusse"
+msgstr "Statusmeldungen"
#: bookwyrm/templates/settings/dashboard/dashboard.html:33
#: bookwyrm/templates/settings/dashboard/works_chart.html:11
msgid "Works"
-msgstr ""
+msgstr "Werke"
#: bookwyrm/templates/settings/dashboard/dashboard.html:43
#, python-format
@@ -2149,11 +2145,11 @@ msgstr "Wochen"
#: bookwyrm/templates/settings/dashboard/dashboard.html:106
msgid "User signup activity"
-msgstr ""
+msgstr "Neuanmeldungen"
#: bookwyrm/templates/settings/dashboard/dashboard.html:112
msgid "Status activity"
-msgstr ""
+msgstr "Statusaktivitäten"
#: bookwyrm/templates/settings/dashboard/dashboard.html:118
msgid "Works created"
@@ -2161,15 +2157,15 @@ msgstr "Erstellte Werke"
#: bookwyrm/templates/settings/dashboard/registration_chart.html:10
msgid "Registrations"
-msgstr "Anmeldungen"
+msgstr "Registrierungen"
#: bookwyrm/templates/settings/dashboard/status_chart.html:11
msgid "Statuses posted"
-msgstr "Statusse veröffentlicht"
+msgstr "Statusmeldungen veröffentlicht"
#: bookwyrm/templates/settings/dashboard/user_chart.html:11
msgid "Total"
-msgstr ""
+msgstr "Gesamt"
#: bookwyrm/templates/settings/email_blocklist/domain_form.html:5
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:10
@@ -2178,13 +2174,13 @@ msgstr "Domain hinzufügen"
#: bookwyrm/templates/settings/email_blocklist/domain_form.html:11
msgid "Domain:"
-msgstr ""
+msgstr "Domain:"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:5
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:7
#: bookwyrm/templates/settings/layout.html:59
msgid "Email Blocklist"
-msgstr "E-Mail-Blockliste"
+msgstr "E-Mail-Sperrliste"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:18
msgid "When someone tries to register with an email from this domain, no account will be created. The registration process will appear to have worked."
@@ -2192,12 +2188,12 @@ msgstr "Wenn sich jemand mit einer E-Mail-Adresse von dieser Domain zu registrie
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:25
msgid "Domain"
-msgstr ""
+msgstr "Domain"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:29
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:27
msgid "Options"
-msgstr ""
+msgstr "Optionen"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:38
#, python-format
@@ -2208,7 +2204,7 @@ msgstr[1] "%(display_count)s Benutzer*innen"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:59
msgid "No email domains currently blocked"
-msgstr ""
+msgstr "Derzeit sind keine E-Mail-Domains gesperrt"
#: bookwyrm/templates/settings/federation/edit_instance.html:3
#: bookwyrm/templates/settings/federation/edit_instance.html:6
@@ -2223,12 +2219,12 @@ msgstr "Instanz hinzufügen"
#: bookwyrm/templates/settings/federation/edit_instance.html:7
#: bookwyrm/templates/settings/federation/instance_blocklist.html:7
msgid "Back to instance list"
-msgstr "Zurück zur Instanzliste"
+msgstr "Zurück zur Instanzenliste"
#: bookwyrm/templates/settings/federation/edit_instance.html:16
#: bookwyrm/templates/settings/federation/instance_blocklist.html:16
msgid "Import block list"
-msgstr "Blockliste importieren"
+msgstr "Sperrliste importieren"
#: bookwyrm/templates/settings/federation/edit_instance.html:30
msgid "Instance:"
@@ -2254,7 +2250,7 @@ msgstr "Version:"
#: bookwyrm/templates/settings/federation/edit_instance.html:70
msgid "Notes:"
-msgstr "Hinweise:"
+msgstr "Anmerkungen:"
#: bookwyrm/templates/settings/federation/instance.html:19
msgid "Details"
@@ -2267,7 +2263,7 @@ msgstr "Aktivität"
#: bookwyrm/templates/settings/federation/instance.html:38
msgid "Users:"
-msgstr "Benutzer:"
+msgstr "Benutzer*innen:"
#: bookwyrm/templates/settings/federation/instance.html:41
#: bookwyrm/templates/settings/federation/instance.html:47
@@ -2281,55 +2277,56 @@ msgstr "Meldungen:"
#: bookwyrm/templates/settings/federation/instance.html:50
msgid "Followed by us:"
-msgstr ""
+msgstr "Folgen wir:"
#: bookwyrm/templates/settings/federation/instance.html:55
msgid "Followed by them:"
-msgstr ""
+msgstr "Folgen:"
#: bookwyrm/templates/settings/federation/instance.html:60
msgid "Blocked by us:"
-msgstr ""
+msgstr "Von uns gesperrt:"
#: bookwyrm/templates/settings/federation/instance.html:72
#: bookwyrm/templates/settings/users/user_info.html:110
msgid "Notes"
-msgstr "Hinweise"
+msgstr "Anmerkungen"
#: bookwyrm/templates/settings/federation/instance.html:75
+#: bookwyrm/templates/snippets/status/status_options.html:24
msgid "Edit"
msgstr "Ändern"
#: bookwyrm/templates/settings/federation/instance.html:79
msgid "No notes "
-msgstr ""
+msgstr "Keine Anmerkungen "
#: bookwyrm/templates/settings/federation/instance.html:94
#: bookwyrm/templates/settings/users/user_moderation_actions.html:8
msgid "Actions"
-msgstr ""
+msgstr "Aktionen"
#: bookwyrm/templates/settings/federation/instance.html:98
#: bookwyrm/templates/snippets/block_button.html:5
msgid "Block"
-msgstr "Blockieren"
+msgstr "Sperren"
#: bookwyrm/templates/settings/federation/instance.html:99
msgid "All users from this instance will be deactivated."
-msgstr "Alle Benutzer dieser Instanz werden deaktiviert."
+msgstr "Alle Benutzer*innen dieser Instanz werden deaktiviert."
#: bookwyrm/templates/settings/federation/instance.html:104
#: bookwyrm/templates/snippets/block_button.html:10
msgid "Un-block"
-msgstr "Entblocken"
+msgstr "Entsperren"
#: bookwyrm/templates/settings/federation/instance.html:105
msgid "All users from this instance will be re-activated."
-msgstr "Alle Benutzer dieser Instanz werden wieder aktiviert."
+msgstr "Alle Benutzer*innen dieser Instanz werden wieder aktiviert."
#: bookwyrm/templates/settings/federation/instance_blocklist.html:6
msgid "Import Blocklist"
-msgstr "Blockliste importieren"
+msgstr "Sperrliste importieren"
#: bookwyrm/templates/settings/federation/instance_blocklist.html:26
#: bookwyrm/templates/snippets/goal_progress.html:7
@@ -2338,7 +2335,7 @@ msgstr "Erfolg!"
#: bookwyrm/templates/settings/federation/instance_blocklist.html:30
msgid "Successfully blocked:"
-msgstr "Erfolgreich blockiert:"
+msgstr "Erfolgreich gesperrt:"
#: bookwyrm/templates/settings/federation/instance_blocklist.html:32
msgid "Failed:"
@@ -2380,7 +2377,7 @@ msgstr "Datum der Anfrage"
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:39
msgid "Date accepted"
-msgstr "Datum der Annahme"
+msgstr "Datum der Bestätigung"
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:42
msgid "Email"
@@ -2397,7 +2394,7 @@ msgstr "Keine Anfragen"
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:59
#: bookwyrm/templates/settings/invites/status_filter.html:16
msgid "Accepted"
-msgstr "Akzeptiert"
+msgstr "Bestätigt"
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:61
#: bookwyrm/templates/settings/invites/status_filter.html:12
@@ -2427,7 +2424,7 @@ msgstr "Un-ignorieren"
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:108
msgid "Back to pending requests"
-msgstr "Keine ausstehenden Anfragen"
+msgstr "Zurück zu ausstehenden Anfragen"
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:110
msgid "View ignored requests"
@@ -2476,7 +2473,7 @@ msgstr "IP-Adresse hinzufügen"
#: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:11
msgid "Use IP address blocks with caution, and consider using blocks only temporarily, as IP addresses are often shared or change hands. If you block your own IP, you will not be able to access this page."
-msgstr ""
+msgstr "Lass bei der Sperrung von IP-Adressen Vorsicht walten. Erwäge, IP-Adressen nur vorübergehend zu sperren, da sie oft geteilt werden oder neu zugeordnet werden. Wenn du deine eigene IP blockierst, kannst du nicht mehr auf diese Seite zugreifen."
#: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:18
msgid "IP Address:"
@@ -2486,27 +2483,27 @@ msgstr "IP-Adresse:"
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:7
#: bookwyrm/templates/settings/layout.html:63
msgid "IP Address Blocklist"
-msgstr ""
+msgstr "IP-Addressen-Sperrliste"
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:18
msgid "Any traffic from this IP address will get a 404 response when trying to access any part of the application."
-msgstr ""
+msgstr "Jeder Datenverkehr von dieser IP-Adresse erhält eine 404-Antwort, wenn versucht wird, auf einen beliebigen Teil der Anwendung zuzugreifen."
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:24
msgid "Address"
-msgstr ""
+msgstr "Adresse"
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:46
msgid "No IP addresses currently blocked"
-msgstr ""
+msgstr "Derzeit sind keine IP-Adressen gesperrt"
#: bookwyrm/templates/settings/ip_blocklist/ip_tooltip.html:6
msgid "You can block IP ranges using CIDR syntax."
-msgstr ""
+msgstr "Du kannst IP-Bereiche mittels CIDR-Syntax blockieren."
#: bookwyrm/templates/settings/layout.html:4
msgid "Administration"
-msgstr ""
+msgstr "Administration"
#: bookwyrm/templates/settings/layout.html:29
msgid "Manage Users"
@@ -2514,7 +2511,7 @@ msgstr "Nutzer*innen verwalten"
#: bookwyrm/templates/settings/layout.html:51
msgid "Moderation"
-msgstr ""
+msgstr "Moderation"
#: bookwyrm/templates/settings/layout.html:55
#: bookwyrm/templates/settings/reports/reports.html:8
@@ -2554,7 +2551,7 @@ msgstr "Kommentieren"
#: bookwyrm/templates/settings/reports/report.html:46
msgid "Reported statuses"
-msgstr ""
+msgstr "Gemeldete Statusmeldungen"
#: bookwyrm/templates/settings/reports/report.html:48
msgid "No statuses reported"
@@ -2562,7 +2559,7 @@ msgstr "Keine Beiträge gemeldet"
#: bookwyrm/templates/settings/reports/report.html:54
msgid "Status has been deleted"
-msgstr ""
+msgstr "Statusmeldung gelöscht"
#: bookwyrm/templates/settings/reports/report_preview.html:13
msgid "No notes provided"
@@ -2593,11 +2590,11 @@ msgstr "Meldungen: %(instance_name)s "
#: bookwyrm/templates/settings/reports/reports.html:28
msgid "Resolved"
-msgstr ""
+msgstr "Behoben"
#: bookwyrm/templates/settings/reports/reports.html:37
msgid "No reports found."
-msgstr ""
+msgstr "Keine Meldungen gefunden."
#: bookwyrm/templates/settings/site.html:10
#: bookwyrm/templates/settings/site.html:21
@@ -2625,7 +2622,7 @@ msgstr "Instanzname"
#: bookwyrm/templates/settings/site.html:28
msgid "Tagline:"
-msgstr ""
+msgstr "Motto:"
#: bookwyrm/templates/settings/site.html:32
msgid "Instance description:"
@@ -2633,15 +2630,15 @@ msgstr "Instanzbeschreibung"
#: bookwyrm/templates/settings/site.html:36
msgid "Short description:"
-msgstr ""
+msgstr "Kurzbeschreibung:"
#: bookwyrm/templates/settings/site.html:37
-msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support html or markdown."
-msgstr ""
+msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support HTML or Markdown."
+msgstr "Wird verwendet, wenn die Instanz auf joinbookwyrm.com in der Vorschau angezeigt wird. Unterstützt weder HTML noch Markdown."
#: bookwyrm/templates/settings/site.html:41
msgid "Code of conduct:"
-msgstr ""
+msgstr "Verhaltenskodex:"
#: bookwyrm/templates/settings/site.html:45
msgid "Privacy Policy:"
@@ -2669,7 +2666,7 @@ msgstr "Unterstützungstitel"
#: bookwyrm/templates/settings/site.html:85
msgid "Admin email:"
-msgstr ""
+msgstr "E-Mail-Adresse des*r Administrator*in:"
#: bookwyrm/templates/settings/site.html:89
msgid "Additional info:"
@@ -2677,11 +2674,11 @@ msgstr "Zusätzliche Info:"
#: bookwyrm/templates/settings/site.html:103
msgid "Allow registration"
-msgstr ""
+msgstr "Selbstregistrierung zulassen"
#: bookwyrm/templates/settings/site.html:109
msgid "Allow invite requests"
-msgstr ""
+msgstr "Einladungsanfragen zulassen"
#: bookwyrm/templates/settings/site.html:115
msgid "Require users to confirm email address"
@@ -2697,7 +2694,7 @@ msgstr "Registrierungen geschlossen text"
#: bookwyrm/templates/settings/site.html:124
msgid "Invite request text:"
-msgstr ""
+msgstr "Hinweis für Einladungsanfragen:"
#: bookwyrm/templates/settings/users/delete_user_form.html:5
#: bookwyrm/templates/settings/users/user_moderation_actions.html:31
@@ -2715,21 +2712,21 @@ msgstr "Dein Passwort:"
#: bookwyrm/templates/settings/users/user.html:7
msgid "Back to users"
-msgstr ""
+msgstr "Zurück zu Benutzer*innen"
#: bookwyrm/templates/settings/users/user_admin.html:7
#, python-format
msgid "Users: %(instance_name)s "
-msgstr ""
+msgstr "Benutzer*innen: %(instance_name)s "
#: bookwyrm/templates/settings/users/user_admin.html:22
#: bookwyrm/templates/settings/users/username_filter.html:5
msgid "Username"
-msgstr "Benutzername"
+msgstr "Benutzer*inname"
#: bookwyrm/templates/settings/users/user_admin.html:26
msgid "Date Added"
-msgstr ""
+msgstr "Hinzugefügt am"
#: bookwyrm/templates/settings/users/user_admin.html:30
msgid "Last Active"
@@ -2737,12 +2734,12 @@ msgstr "Zuletzt aktiv"
#: bookwyrm/templates/settings/users/user_admin.html:38
msgid "Remote instance"
-msgstr ""
+msgstr "Entfernte Instanz"
#: bookwyrm/templates/settings/users/user_admin.html:47
#: bookwyrm/templates/settings/users/user_info.html:24
msgid "Active"
-msgstr ""
+msgstr "Aktiv"
#: bookwyrm/templates/settings/users/user_admin.html:47
#: bookwyrm/templates/settings/users/user_info.html:28
@@ -2756,7 +2753,7 @@ msgstr "Nicht gesetzt"
#: bookwyrm/templates/settings/users/user_info.html:16
msgid "View user profile"
-msgstr ""
+msgstr "Benutzer*inprofil anzeigen"
#: bookwyrm/templates/settings/users/user_info.html:36
msgid "Local"
@@ -2764,11 +2761,11 @@ msgstr "Lokal"
#: bookwyrm/templates/settings/users/user_info.html:38
msgid "Remote"
-msgstr ""
+msgstr "Entfernt"
#: bookwyrm/templates/settings/users/user_info.html:47
msgid "User details"
-msgstr "Benutzerdetails"
+msgstr "Benutzer*indetails"
#: bookwyrm/templates/settings/users/user_info.html:51
msgid "Email:"
@@ -2776,19 +2773,19 @@ msgstr "E-Mail:"
#: bookwyrm/templates/settings/users/user_info.html:61
msgid "(View reports)"
-msgstr ""
+msgstr "(Meldungen anzeigen)"
#: bookwyrm/templates/settings/users/user_info.html:67
msgid "Blocked by count:"
-msgstr ""
+msgstr "Gesperrt durch (Anzahl):"
#: bookwyrm/templates/settings/users/user_info.html:70
msgid "Last active date:"
-msgstr ""
+msgstr "Zuletzt aktiv:"
#: bookwyrm/templates/settings/users/user_info.html:73
msgid "Manually approved followers:"
-msgstr ""
+msgstr "Manuell zugelassene Follower*innen:"
#: bookwyrm/templates/settings/users/user_info.html:76
msgid "Discoverable:"
@@ -2796,11 +2793,11 @@ msgstr "Entdeckbar:"
#: bookwyrm/templates/settings/users/user_info.html:80
msgid "Deactivation reason:"
-msgstr ""
+msgstr "Grund der Deaktivierung:"
#: bookwyrm/templates/settings/users/user_info.html:95
msgid "Instance details"
-msgstr ""
+msgstr "Instanzdetails"
#: bookwyrm/templates/settings/users/user_info.html:117
msgid "View instance"
@@ -2811,22 +2808,22 @@ msgid "Permanently deleted"
msgstr "Permanent gelöscht"
#: bookwyrm/templates/settings/users/user_moderation_actions.html:13
-#: bookwyrm/templates/snippets/status/status_options.html:35
+#: bookwyrm/templates/snippets/status/status_options.html:32
#: bookwyrm/templates/snippets/user_options.html:13
msgid "Send direct message"
msgstr "Direktnachricht senden"
#: bookwyrm/templates/settings/users/user_moderation_actions.html:20
msgid "Suspend user"
-msgstr ""
+msgstr "Benutzer*in vorläufig sperren"
#: bookwyrm/templates/settings/users/user_moderation_actions.html:25
msgid "Un-suspend user"
-msgstr ""
+msgstr "Vorläufige Sperre für Benutzer*in aufheben"
#: bookwyrm/templates/settings/users/user_moderation_actions.html:47
msgid "Access level:"
-msgstr ""
+msgstr "Zugriffsstufe:"
#: bookwyrm/templates/shelf/create_shelf_form.html:5
msgid "Create Shelf"
@@ -2864,36 +2861,36 @@ msgstr "Regal bearbeiten"
msgid "Delete shelf"
msgstr "Regal löschen"
-#: bookwyrm/templates/shelf/shelf.html:130
-#: bookwyrm/templates/shelf/shelf.html:154
+#: bookwyrm/templates/shelf/shelf.html:132
+#: bookwyrm/templates/shelf/shelf.html:158
msgid "Shelved"
msgstr "Ins Regal gestellt"
-#: bookwyrm/templates/shelf/shelf.html:131
-#: bookwyrm/templates/shelf/shelf.html:158
+#: bookwyrm/templates/shelf/shelf.html:133
+#: bookwyrm/templates/shelf/shelf.html:161
msgid "Started"
msgstr "Gestartet"
-#: bookwyrm/templates/shelf/shelf.html:132
-#: bookwyrm/templates/shelf/shelf.html:161
+#: bookwyrm/templates/shelf/shelf.html:134
+#: bookwyrm/templates/shelf/shelf.html:164
msgid "Finished"
msgstr "Abgeschlossen"
-#: bookwyrm/templates/shelf/shelf.html:187
+#: bookwyrm/templates/shelf/shelf.html:190
msgid "This shelf is empty."
msgstr "Dieses Regal ist leer."
#: bookwyrm/templates/snippets/announcement.html:31
#, python-format
msgid "Posted by %(username)s "
-msgstr ""
+msgstr "Von %(username)s veröffentlicht"
#: bookwyrm/templates/snippets/authors.html:22
#, python-format
msgid "and %(remainder_count_display)s other"
msgid_plural "and %(remainder_count_display)s others"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "und %(remainder_count_display)s Andere*r"
+msgstr[1] "und %(remainder_count_display)s Andere"
#: bookwyrm/templates/snippets/book_cover.html:61
msgid "No cover"
@@ -2902,17 +2899,17 @@ msgstr "Kein Titelbild"
#: bookwyrm/templates/snippets/book_titleby.html:6
#, python-format
msgid "%(title)s by"
-msgstr ""
+msgstr "%(title)s von"
#: bookwyrm/templates/snippets/boost_button.html:20
#: bookwyrm/templates/snippets/boost_button.html:21
msgid "Boost"
-msgstr ""
+msgstr "Teilen"
#: bookwyrm/templates/snippets/boost_button.html:33
#: bookwyrm/templates/snippets/boost_button.html:34
msgid "Un-boost"
-msgstr ""
+msgstr "Teilen zurücknehmen"
#: bookwyrm/templates/snippets/create_status.html:17
msgid "Review"
@@ -2926,22 +2923,22 @@ msgstr "Zitieren"
msgid "Some thoughts on the book"
msgstr "Ein paar Gedanken zum Buch"
-#: bookwyrm/templates/snippets/create_status/comment.html:26
+#: bookwyrm/templates/snippets/create_status/comment.html:27
#: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:15
msgid "Progress:"
msgstr "Fortschritt:"
-#: bookwyrm/templates/snippets/create_status/comment.html:52
+#: bookwyrm/templates/snippets/create_status/comment.html:53
#: bookwyrm/templates/snippets/progress_field.html:18
msgid "pages"
msgstr "Seiten"
-#: bookwyrm/templates/snippets/create_status/comment.html:58
+#: bookwyrm/templates/snippets/create_status/comment.html:59
#: bookwyrm/templates/snippets/progress_field.html:23
msgid "percent"
msgstr "Prozent"
-#: bookwyrm/templates/snippets/create_status/comment.html:65
+#: bookwyrm/templates/snippets/create_status/comment.html:66
#, python-format
msgid "of %(pages)s pages"
msgstr "von %(pages)s Seiten"
@@ -2955,11 +2952,11 @@ msgstr "Antwort"
#: bookwyrm/templates/snippets/create_status/content_field.html:17
msgid "Content"
-msgstr ""
+msgstr "Inhalt"
#: bookwyrm/templates/snippets/create_status/content_warning_field.html:10
msgid "Content warning:"
-msgstr ""
+msgstr "Inhaltswarnung:"
#: bookwyrm/templates/snippets/create_status/content_warning_field.html:18
msgid "Spoilers ahead!"
@@ -2969,7 +2966,7 @@ msgstr "Spoileralarm!"
msgid "Include spoiler alert"
msgstr "Spoileralarm aktivieren"
-#: bookwyrm/templates/snippets/create_status/layout.html:41
+#: bookwyrm/templates/snippets/create_status/layout.html:48
#: bookwyrm/templates/snippets/reading_modals/form.html:7
msgid "Comment:"
msgstr "Kommentar:"
@@ -2992,11 +2989,11 @@ msgstr "Zitat:"
#: bookwyrm/templates/snippets/create_status/quotation.html:25
#, python-format
msgid "An excerpt from '%(book_title)s'"
-msgstr ""
+msgstr "Ein Auszug aus „%(book_title)s“"
#: bookwyrm/templates/snippets/create_status/quotation.html:32
msgid "Position:"
-msgstr ""
+msgstr "Position:"
#: bookwyrm/templates/snippets/create_status/quotation.html:45
msgid "On page:"
@@ -3004,16 +3001,16 @@ msgstr "Auf Seite:"
#: bookwyrm/templates/snippets/create_status/quotation.html:51
msgid "At percent:"
-msgstr ""
+msgstr "Bei Prozentsatz:"
#: bookwyrm/templates/snippets/create_status/review.html:25
#, python-format
msgid "Your review of '%(book_title)s'"
-msgstr "Deine Rezension von '%(book_title)s'"
+msgstr "Deine Besprechung von „%(book_title)s“"
#: bookwyrm/templates/snippets/create_status/review.html:40
msgid "Review:"
-msgstr ""
+msgstr "Besprechung:"
#: bookwyrm/templates/snippets/delete_readthrough_modal.html:4
msgid "Delete these read dates?"
@@ -3032,7 +3029,7 @@ msgstr "Favorisieren"
#: bookwyrm/templates/snippets/fav_button.html:30
#: bookwyrm/templates/snippets/fav_button.html:31
msgid "Un-like"
-msgstr ""
+msgstr "Favorisierung zurücknehmen"
#: bookwyrm/templates/snippets/filters_panel/filters_panel.html:7
msgid "Show filters"
@@ -3048,12 +3045,12 @@ msgstr "Filter anwenden"
#: bookwyrm/templates/snippets/filters_panel/filters_panel.html:26
msgid "Clear filters"
-msgstr ""
+msgstr "Filter zurücksetzen"
#: bookwyrm/templates/snippets/follow_button.html:14
#, python-format
msgid "Follow @%(username)s"
-msgstr ""
+msgstr "@%(username)s folgen"
#: bookwyrm/templates/snippets/follow_button.html:16
msgid "Follow"
@@ -3061,12 +3058,12 @@ msgstr "Folgen"
#: bookwyrm/templates/snippets/follow_button.html:25
msgid "Undo follow request"
-msgstr ""
+msgstr "Folgeanfrage zurücknehmen"
#: bookwyrm/templates/snippets/follow_button.html:30
#, python-format
msgid "Unfollow @%(username)s"
-msgstr ""
+msgstr "@%(username)s entfolgen"
#: bookwyrm/templates/snippets/follow_button.html:32
msgid "Unfollow"
@@ -3085,16 +3082,16 @@ msgstr "Kein Rating"
#, python-format
msgid "%(half_rating)s star"
msgid_plural "%(half_rating)s stars"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%(half_rating)s Stern"
+msgstr[1] "%(half_rating)s Sterne"
#: bookwyrm/templates/snippets/form_rate_stars.html:64
#: bookwyrm/templates/snippets/stars.html:7
#, python-format
msgid "%(rating)s star"
msgid_plural "%(rating)s stars"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%(rating)s Stern"
+msgstr[1] "%(rating)s Sterne"
#: bookwyrm/templates/snippets/generated_status/goal.html:2
#, python-format
@@ -3107,15 +3104,15 @@ msgstr[1] "Setze das Ziel, %(year)s %(counter)s Bücher zu lesen"
#, python-format
msgid "rated %(title)s : %(display_rating)s star"
msgid_plural "rated %(title)s : %(display_rating)s stars"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "hat %(title)s mit %(display_rating)s Stern bewertet"
+msgstr[1] "hat %(title)s mit %(display_rating)s Sternen bewertet"
#: bookwyrm/templates/snippets/generated_status/review_pure_name.html:4
#, python-format
msgid "Review of \"%(book_title)s\" (%(display_rating)s star): %(review_title)s"
msgid_plural "Review of \"%(book_title)s\" (%(display_rating)s stars): %(review_title)s"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Besprechung von „%(book_title)s“ (%(display_rating)s Stern): %(review_title)s"
+msgstr[1] "Besprechung von „%(book_title)s“ (%(display_rating)s Sterne): %(review_title)s"
#: bookwyrm/templates/snippets/generated_status/review_pure_name.html:8
#, python-format
@@ -3163,15 +3160,15 @@ msgstr "Du hast %(read_count)s von %(goal_count)s Büchern<
msgid "%(username)s has read %(read_count)s of %(goal_count)s books ."
msgstr "%(username)s hat %(read_count)s von %(goal_count)s Büchern gelesen."
-#: bookwyrm/templates/snippets/page_text.html:4
+#: bookwyrm/templates/snippets/page_text.html:8
#, python-format
msgid "page %(page)s of %(total_pages)s"
-msgstr ""
+msgstr "Seite %(page)s von %(total_pages)s"
-#: bookwyrm/templates/snippets/page_text.html:6
+#: bookwyrm/templates/snippets/page_text.html:14
#, python-format
msgid "page %(page)s"
-msgstr ""
+msgstr "Seite %(page)s"
#: bookwyrm/templates/snippets/pagination.html:12
msgid "Previous"
@@ -3213,7 +3210,7 @@ msgstr "Raten"
#: bookwyrm/templates/snippets/rate_action.html:19
msgid "Rate"
-msgstr ""
+msgstr "Bewerten"
#: bookwyrm/templates/snippets/reading_modals/finish_reading_modal.html:6
#, python-format
@@ -3233,12 +3230,12 @@ msgstr "Zu Ende gelesen"
#: bookwyrm/templates/snippets/reading_modals/form.html:9
msgid "(Optional)"
-msgstr ""
+msgstr "(Optional)"
#: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:5
#: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:50
msgid "Update progress"
-msgstr ""
+msgstr "Update-Fortschritt"
#: bookwyrm/templates/snippets/reading_modals/start_reading_modal.html:6
#, python-format
@@ -3260,12 +3257,12 @@ msgstr "Registrieren"
#: bookwyrm/templates/snippets/report_button.html:6
msgid "Report"
-msgstr ""
+msgstr "Melden"
#: bookwyrm/templates/snippets/report_modal.html:6
#, python-format
msgid "Report @%(username)s"
-msgstr ""
+msgstr "@%(username)s melden"
#: bookwyrm/templates/snippets/report_modal.html:23
#, python-format
@@ -3274,11 +3271,11 @@ msgstr "Diese Meldung wird an die Moderator:innen von %(site_name)s weitergeleti
#: bookwyrm/templates/snippets/report_modal.html:24
msgid "More info about this report:"
-msgstr ""
+msgstr "Weitere Angeben zu dieser Meldung:"
#: bookwyrm/templates/snippets/shelf_selector.html:4
msgid "Move book"
-msgstr ""
+msgstr "Buch verschieben"
#: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown.html:5
msgid "More shelves"
@@ -3297,7 +3294,7 @@ msgstr "Auf Leseliste setzen"
#: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:62
#, python-format
msgid "Remove from %(name)s"
-msgstr ""
+msgstr "Aus %(name)s entfernen"
#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:30
msgid "Finish reading"
@@ -3305,21 +3302,21 @@ msgstr "Lesen abschließen"
#: bookwyrm/templates/snippets/status/content_status.html:72
msgid "Content warning"
-msgstr ""
+msgstr "Inhaltswarnung"
#: bookwyrm/templates/snippets/status/content_status.html:79
msgid "Show status"
-msgstr ""
+msgstr "Status anzeigen"
#: bookwyrm/templates/snippets/status/content_status.html:101
#, python-format
msgid "(Page %(page)s)"
-msgstr ""
+msgstr "(Seite %(page)s)"
#: bookwyrm/templates/snippets/status/content_status.html:103
#, python-format
msgid "(%(percent)s%%)"
-msgstr ""
+msgstr "(%(percent)s%%)"
#: bookwyrm/templates/snippets/status/content_status.html:125
msgid "Open image in new window"
@@ -3327,47 +3324,52 @@ msgstr "Bild in neuem Fenster öffnen"
#: bookwyrm/templates/snippets/status/content_status.html:144
msgid "Hide status"
-msgstr ""
+msgstr "Status ausblenden"
+
+#: bookwyrm/templates/snippets/status/header.html:45
+#, python-format
+msgid "edited %(date)s"
+msgstr "%(date)s bearbeitet"
#: bookwyrm/templates/snippets/status/headers/comment.html:2
#, python-format
msgid "commented on %(book)s "
-msgstr ""
+msgstr "hat %(book)s kommentiert"
#: bookwyrm/templates/snippets/status/headers/note.html:15
#, python-format
msgid "replied to %(username)s 's status "
-msgstr ""
+msgstr "hat auf die Statusmeldung von %(username)s geantwortet"
#: bookwyrm/templates/snippets/status/headers/quotation.html:2
#, python-format
msgid "quoted %(book)s "
-msgstr ""
+msgstr "hat %(book)s zitiert"
#: bookwyrm/templates/snippets/status/headers/rating.html:3
#, python-format
msgid "rated %(book)s :"
-msgstr ""
+msgstr "hat %(book)s bewertet:"
#: bookwyrm/templates/snippets/status/headers/read.html:7
#, python-format
msgid "finished reading %(book)s "
-msgstr ""
+msgstr "hat %(book)s ausgelesen"
#: bookwyrm/templates/snippets/status/headers/reading.html:7
#, python-format
msgid "started reading %(book)s "
-msgstr ""
+msgstr "hat angefangen, %(book)s zu lesen"
#: bookwyrm/templates/snippets/status/headers/review.html:3
#, python-format
msgid "reviewed %(book)s "
-msgstr ""
+msgstr "hat %(book)s besprochen"
#: bookwyrm/templates/snippets/status/headers/to_read.html:7
#, python-format
msgid "%(username)s wants to read %(book)s "
-msgstr ""
+msgstr "%(username)s hat %(book)s auf die Leseliste gesetzt "
#: bookwyrm/templates/snippets/status/layout.html:24
#: bookwyrm/templates/snippets/status/status_options.html:17
@@ -3393,28 +3395,24 @@ msgstr "teilt"
msgid "More options"
msgstr "Mehr Optionen"
-#: bookwyrm/templates/snippets/status/status_options.html:26
-msgid "Delete & re-draft"
-msgstr ""
-
#: bookwyrm/templates/snippets/suggested_users.html:16
#, python-format
msgid "%(mutuals)s follower you follow"
msgid_plural "%(mutuals)s followers you follow"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%(mutuals)s Follower*in, der*die du folgst"
+msgstr[1] "%(mutuals)s Follower*innen, denen du folgst"
#: bookwyrm/templates/snippets/suggested_users.html:23
#, python-format
msgid "%(shared_books)s book on your shelves"
msgid_plural "%(shared_books)s books on your shelves"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%(shared_books)s Buch in deinen Regalen"
+msgstr[1] "%(shared_books)s Bücher in deinen Regalen"
#: bookwyrm/templates/snippets/suggested_users.html:31
#: bookwyrm/templates/user/user_preview.html:36
msgid "Follows you"
-msgstr ""
+msgstr "Folgt dir"
#: bookwyrm/templates/snippets/switch_edition_button.html:5
msgid "Switch to this edition"
@@ -3422,11 +3420,11 @@ msgstr "Zu dieser Edition wechseln"
#: bookwyrm/templates/snippets/table-sort-header.html:6
msgid "Sorted ascending"
-msgstr ""
+msgstr "Aufsteigend sortiert"
#: bookwyrm/templates/snippets/table-sort-header.html:10
msgid "Sorted descending"
-msgstr ""
+msgstr "Absteigend sortiert"
#: bookwyrm/templates/snippets/trimmed_text.html:17
msgid "Show more"
@@ -3439,7 +3437,7 @@ msgstr "Weniger anzeigen"
#: bookwyrm/templates/user/books_header.html:5
#, python-format
msgid "%(username)s's books"
-msgstr ""
+msgstr "Bücher von %(username)s"
#: bookwyrm/templates/user/goal.html:8
#, python-format
@@ -3508,7 +3506,7 @@ msgstr "Profil bearbeiten"
#: bookwyrm/templates/user/user.html:33
#, python-format
msgid "View all %(size)s"
-msgstr ""
+msgstr "Alle %(size)s anzeigen"
#: bookwyrm/templates/user/user.html:46
msgid "View all books"
@@ -3520,7 +3518,7 @@ msgstr "Nutzer*innenaktivität"
#: bookwyrm/templates/user/user.html:63
msgid "RSS feed"
-msgstr ""
+msgstr "RSS-Feed"
#: bookwyrm/templates/user/user.html:74
msgid "No activities yet!"
@@ -3547,21 +3545,21 @@ msgstr "Folgt %(counter)s"
#, python-format
msgid "%(mutuals_display)s follower you follow"
msgid_plural "%(mutuals_display)s followers you follow"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%(mutuals_display)s Follower*in, der*die du folgst"
+msgstr[1] "%(mutuals_display)s Follower*innen, denen du folgst"
#: bookwyrm/templates/user/user_preview.html:38
msgid "No followers you follow"
-msgstr ""
+msgstr "Keine Follower*innen, denen du folgst"
#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:28
msgid "File exceeds maximum size: 10MB"
-msgstr ""
+msgstr "Datei überschreitet die maximale Größe von 10MB"
#: bookwyrm/templatetags/utilities.py:31
#, python-format
msgid "%(title)s: %(subtitle)s"
-msgstr ""
+msgstr "%(title)s: %(subtitle)s"
#: bookwyrm/views/import_data.py:67
msgid "Not a valid csv file"
@@ -3573,7 +3571,7 @@ msgstr "Username oder Passwort sind falsch"
#: bookwyrm/views/password.py:32
msgid "No user with that email address was found."
-msgstr ""
+msgstr "Es wurde kein*e Benutzer*in mit dieser E-Mail-Adresse gefunden."
#: bookwyrm/views/password.py:41
#, python-brace-format
diff --git a/locale/en_US/LC_MESSAGES/django.po b/locale/en_US/LC_MESSAGES/django.po
index b67d50c53..7d8fc801a 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: 2021-10-06 23:57+0000\n"
+"POT-Creation-Date: 2021-10-24 14:09+0000\n"
"PO-Revision-Date: 2021-02-28 17:19-0800\n"
"Last-Translator: Mouse Reeve \n"
"Language-Team: English \n"
@@ -47,29 +47,29 @@ msgstr ""
msgid "Unlimited"
msgstr ""
-#: bookwyrm/forms.py:326
+#: bookwyrm/forms.py:332
msgid "List Order"
msgstr ""
-#: bookwyrm/forms.py:327
+#: bookwyrm/forms.py:333
msgid "Book Title"
msgstr ""
-#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:134
-#: bookwyrm/templates/shelf/shelf.html:165
+#: bookwyrm/forms.py:334 bookwyrm/templates/shelf/shelf.html:149
+#: bookwyrm/templates/shelf/shelf.html:181
#: bookwyrm/templates/snippets/create_status/review.html:33
msgid "Rating"
msgstr ""
-#: bookwyrm/forms.py:330 bookwyrm/templates/lists/list.html:109
+#: bookwyrm/forms.py:336 bookwyrm/templates/lists/list.html:110
msgid "Sort By"
msgstr ""
-#: bookwyrm/forms.py:334
+#: bookwyrm/forms.py:340
msgid "Ascending"
msgstr ""
-#: bookwyrm/forms.py:335
+#: bookwyrm/forms.py:341
msgid "Descending"
msgstr ""
@@ -152,45 +152,49 @@ msgstr ""
msgid "A user with that username already exists."
msgstr ""
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home Timeline"
msgstr ""
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home"
msgstr ""
-#: bookwyrm/settings.py:118
+#: bookwyrm/settings.py:119
msgid "Books Timeline"
msgstr ""
-#: bookwyrm/settings.py:118 bookwyrm/templates/search/layout.html:21
+#: bookwyrm/settings.py:119 bookwyrm/templates/search/layout.html:21
#: bookwyrm/templates/search/layout.html:42
-#: bookwyrm/templates/user/layout.html:81
+#: bookwyrm/templates/user/layout.html:88
msgid "Books"
msgstr ""
-#: bookwyrm/settings.py:164
+#: bookwyrm/settings.py:165
msgid "English"
msgstr ""
-#: bookwyrm/settings.py:165
+#: bookwyrm/settings.py:166
msgid "Deutsch (German)"
msgstr ""
-#: bookwyrm/settings.py:166
+#: bookwyrm/settings.py:167
msgid "Español (Spanish)"
msgstr ""
-#: bookwyrm/settings.py:167
+#: bookwyrm/settings.py:168
msgid "Français (French)"
msgstr ""
-#: bookwyrm/settings.py:168
+#: bookwyrm/settings.py:169
+msgid "Português - Brasil (Brazilian Portuguese)"
+msgstr ""
+
+#: bookwyrm/settings.py:170
msgid "简体中文 (Simplified Chinese)"
msgstr ""
-#: bookwyrm/settings.py:169
+#: bookwyrm/settings.py:171
msgid "繁體中文 (Traditional Chinese)"
msgstr ""
@@ -220,7 +224,7 @@ msgid "Edit Author"
msgstr ""
#: bookwyrm/templates/author/author.html:34
-#: bookwyrm/templates/author/edit_author.html:41
+#: bookwyrm/templates/author/edit_author.html:43
msgid "Aliases:"
msgstr ""
@@ -273,71 +277,72 @@ msgstr ""
msgid "Updated:"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:15
+#: bookwyrm/templates/author/edit_author.html:16
#: bookwyrm/templates/book/edit/edit_book.html:25
msgid "Last edited by:"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:31
+#: bookwyrm/templates/author/edit_author.html:33
#: bookwyrm/templates/book/edit/edit_book_form.html:15
msgid "Metadata"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:33
-#: bookwyrm/templates/lists/form.html:8 bookwyrm/templates/shelf/form.html:9
+#: bookwyrm/templates/author/edit_author.html:35
+#: bookwyrm/templates/lists/form.html:9 bookwyrm/templates/shelf/form.html:9
msgid "Name:"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:43
+#: bookwyrm/templates/author/edit_author.html:45
#: bookwyrm/templates/book/edit/edit_book_form.html:65
#: bookwyrm/templates/book/edit/edit_book_form.html:79
#: bookwyrm/templates/book/edit/edit_book_form.html:124
msgid "Separate multiple values with commas."
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:50
+#: bookwyrm/templates/author/edit_author.html:52
msgid "Bio:"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:57
+#: bookwyrm/templates/author/edit_author.html:59
msgid "Wikipedia link:"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:63
+#: bookwyrm/templates/author/edit_author.html:65
msgid "Birth date:"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:71
+#: bookwyrm/templates/author/edit_author.html:73
msgid "Death date:"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:79
+#: bookwyrm/templates/author/edit_author.html:81
msgid "Author Identifiers"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:81
+#: bookwyrm/templates/author/edit_author.html:83
msgid "Openlibrary key:"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:89
+#: bookwyrm/templates/author/edit_author.html:91
#: bookwyrm/templates/book/edit/edit_book_form.html:224
msgid "Inventaire ID:"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:97
+#: bookwyrm/templates/author/edit_author.html:99
msgid "Librarything key:"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:105
+#: bookwyrm/templates/author/edit_author.html:107
msgid "Goodreads key:"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:116
+#: bookwyrm/templates/author/edit_author.html:118
#: bookwyrm/templates/book/book.html:140
#: bookwyrm/templates/book/edit/edit_book.html:110
#: bookwyrm/templates/book/readthrough.html:76
+#: bookwyrm/templates/groups/form.html:24
#: bookwyrm/templates/lists/bookmark_button.html:15
-#: bookwyrm/templates/lists/form.html:44
+#: bookwyrm/templates/lists/form.html:75
#: bookwyrm/templates/preferences/edit_user.html:124
#: bookwyrm/templates/settings/announcements/announcement_form.html:69
#: bookwyrm/templates/settings/federation/edit_instance.html:74
@@ -349,11 +354,13 @@ msgstr ""
msgid "Save"
msgstr ""
-#: bookwyrm/templates/author/edit_author.html:117
+#: bookwyrm/templates/author/edit_author.html:119
#: bookwyrm/templates/book/book.html:141 bookwyrm/templates/book/book.html:190
#: bookwyrm/templates/book/cover_modal.html:32
-#: bookwyrm/templates/book/edit/edit_book.html:111
+#: bookwyrm/templates/book/edit/edit_book.html:112
+#: bookwyrm/templates/book/edit/edit_book.html:115
#: bookwyrm/templates/book/readthrough.html:77
+#: bookwyrm/templates/groups/delete_group_modal.html:17
#: bookwyrm/templates/lists/delete_list_modal.html:17
#: bookwyrm/templates/settings/federation/instance.html:88
#: bookwyrm/templates/snippets/delete_readthrough_modal.html:17
@@ -394,7 +401,7 @@ msgstr ""
#: bookwyrm/templates/book/book.html:136
#: bookwyrm/templates/book/edit/edit_book_form.html:34
-#: bookwyrm/templates/lists/form.html:12 bookwyrm/templates/shelf/form.html:17
+#: bookwyrm/templates/lists/form.html:13 bookwyrm/templates/shelf/form.html:17
msgid "Description:"
msgstr ""
@@ -457,7 +464,7 @@ msgstr ""
#: bookwyrm/templates/lists/lists.html:5 bookwyrm/templates/lists/lists.html:12
#: bookwyrm/templates/search/layout.html:25
#: bookwyrm/templates/search/layout.html:50
-#: bookwyrm/templates/user/layout.html:75
+#: bookwyrm/templates/user/layout.html:82
msgid "Lists"
msgstr ""
@@ -467,7 +474,7 @@ msgstr ""
#: bookwyrm/templates/book/book.html:315
#: bookwyrm/templates/book/cover_modal.html:31
-#: bookwyrm/templates/lists/list.html:181
+#: bookwyrm/templates/lists/list.html:182
#: bookwyrm/templates/settings/email_blocklist/domain_form.html:26
#: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:32
msgid "Add"
@@ -540,7 +547,9 @@ msgid "This is a new work"
msgstr ""
#: bookwyrm/templates/book/edit/edit_book.html:97
-#: bookwyrm/templates/password_reset.html:30
+#: bookwyrm/templates/groups/members.html:16
+#: bookwyrm/templates/landing/password_reset.html:30
+#: bookwyrm/templates/snippets/remove_from_group_button.html:16
msgid "Confirm"
msgstr ""
@@ -609,7 +618,7 @@ msgid "John Doe, Jane Smith"
msgstr ""
#: bookwyrm/templates/book/edit/edit_book_form.html:132
-#: bookwyrm/templates/shelf/shelf.html:127
+#: bookwyrm/templates/shelf/shelf.html:140
msgid "Cover"
msgstr ""
@@ -670,11 +679,6 @@ msgstr ""
msgid "Search editions"
msgstr ""
-#: bookwyrm/templates/book/publisher_info.html:21
-#, python-format
-msgid "%(format)s"
-msgstr ""
-
#: bookwyrm/templates/book/publisher_info.html:23
#, python-format
msgid "%(format)s, %(pages)s pages"
@@ -754,7 +758,7 @@ msgid "Help"
msgstr ""
#: bookwyrm/templates/compose.html:5 bookwyrm/templates/compose.html:8
-msgid "Compose status"
+msgid "Edit status"
msgstr ""
#: bookwyrm/templates/confirm_email/confirm_email.html:4
@@ -795,7 +799,7 @@ msgstr ""
#: bookwyrm/templates/confirm_email/resend_form.html:11
#: bookwyrm/templates/landing/layout.html:67
-#: bookwyrm/templates/password_reset_request.html:18
+#: bookwyrm/templates/landing/password_reset_request.html:18
#: bookwyrm/templates/preferences/edit_user.html:56
#: bookwyrm/templates/snippets/register_form.html:13
msgid "Email address:"
@@ -889,6 +893,26 @@ msgstr ""
msgid "All known users"
msgstr ""
+#: bookwyrm/templates/discover/card-header.html:9
+#, python-format
+msgid "%(username)s rated %(book_title)s "
+msgstr ""
+
+#: bookwyrm/templates/discover/card-header.html:13
+#, python-format
+msgid "%(username)s reviewed %(book_title)s "
+msgstr ""
+
+#: bookwyrm/templates/discover/card-header.html:17
+#, python-format
+msgid "%(username)s commented on %(book_title)s "
+msgstr ""
+
+#: bookwyrm/templates/discover/card-header.html:21
+#, python-format
+msgid "%(username)s quoted %(book_title)s "
+msgstr ""
+
#: bookwyrm/templates/discover/discover.html:4
#: bookwyrm/templates/discover/discover.html:10
#: bookwyrm/templates/layout.html:78
@@ -900,28 +924,8 @@ msgstr ""
msgid "See what's new in the local %(site_name)s community"
msgstr ""
-#: bookwyrm/templates/discover/large-book.html:46
-#: bookwyrm/templates/discover/small-book.html:32
-msgid "rated"
-msgstr ""
-
-#: bookwyrm/templates/discover/large-book.html:48
-#: bookwyrm/templates/discover/small-book.html:34
-msgid "reviewed"
-msgstr ""
-
-#: bookwyrm/templates/discover/large-book.html:50
-#: bookwyrm/templates/discover/small-book.html:36
-msgid "commented on"
-msgstr ""
-
#: bookwyrm/templates/discover/large-book.html:52
-#: bookwyrm/templates/discover/small-book.html:38
-msgid "quoted"
-msgstr ""
-
-#: bookwyrm/templates/discover/large-book.html:68
-#: bookwyrm/templates/discover/small-book.html:52
+#: bookwyrm/templates/discover/small-book.html:36
msgid "View status"
msgstr ""
@@ -975,7 +979,7 @@ msgstr ""
#: bookwyrm/templates/email/invite/html_content.html:15
#, python-format
-msgid "Learn more about this instance ."
+msgid "Learn more about %(site_name)s ."
msgstr ""
#: bookwyrm/templates/email/invite/text_content.html:4
@@ -984,7 +988,8 @@ msgid "You're invited to join %(site_name)s! Click the link below to create an a
msgstr ""
#: bookwyrm/templates/email/invite/text_content.html:8
-msgid "Learn more about this instance:"
+#, python-format
+msgid "Learn more about %(site_name)s:"
msgstr ""
#: bookwyrm/templates/email/password_reset/html_content.html:6
@@ -994,10 +999,10 @@ msgid "You requested to reset your %(site_name)s password. Click the link below
msgstr ""
#: bookwyrm/templates/email/password_reset/html_content.html:9
-#: bookwyrm/templates/password_reset.html:4
-#: bookwyrm/templates/password_reset.html:10
-#: bookwyrm/templates/password_reset_request.html:4
-#: bookwyrm/templates/password_reset_request.html:10
+#: bookwyrm/templates/landing/password_reset.html:4
+#: bookwyrm/templates/landing/password_reset.html:10
+#: bookwyrm/templates/landing/password_reset_request.html:4
+#: bookwyrm/templates/landing/password_reset_request.html:10
msgid "Reset Password"
msgstr ""
@@ -1103,7 +1108,7 @@ msgid "What are you reading?"
msgstr ""
#: bookwyrm/templates/get_started/books.html:9
-#: bookwyrm/templates/layout.html:45 bookwyrm/templates/lists/list.html:137
+#: bookwyrm/templates/layout.html:45 bookwyrm/templates/lists/list.html:138
msgid "Search for a book"
msgstr ""
@@ -1121,8 +1126,9 @@ msgstr ""
#: bookwyrm/templates/get_started/books.html:17
#: bookwyrm/templates/get_started/users.html:18
#: bookwyrm/templates/get_started/users.html:19
-#: bookwyrm/templates/layout.html:51 bookwyrm/templates/layout.html:52
-#: bookwyrm/templates/lists/list.html:141
+#: bookwyrm/templates/groups/group.html:19
+#: bookwyrm/templates/groups/group.html:20 bookwyrm/templates/layout.html:51
+#: bookwyrm/templates/layout.html:52 bookwyrm/templates/lists/list.html:142
#: bookwyrm/templates/search/layout.html:4
#: bookwyrm/templates/search/layout.html:9
msgid "Search"
@@ -1138,7 +1144,7 @@ msgid "Popular on %(site_name)s"
msgstr ""
#: bookwyrm/templates/get_started/books.html:58
-#: bookwyrm/templates/lists/list.html:154
+#: bookwyrm/templates/lists/list.html:155
msgid "No books found"
msgstr ""
@@ -1224,9 +1230,110 @@ msgstr ""
msgid "No users found for \"%(query)s\""
msgstr ""
+#: bookwyrm/templates/groups/create_form.html:5
+msgid "Create Group"
+msgstr ""
+
+#: bookwyrm/templates/groups/created_text.html:4
+#, python-format
+msgid "Managed by %(username)s "
+msgstr ""
+
+#: bookwyrm/templates/groups/delete_group_modal.html:4
+msgid "Delete this group?"
+msgstr ""
+
+#: bookwyrm/templates/groups/delete_group_modal.html:7
+#: bookwyrm/templates/lists/delete_list_modal.html:7
+msgid "This action cannot be un-done"
+msgstr ""
+
+#: bookwyrm/templates/groups/delete_group_modal.html:15
+#: bookwyrm/templates/lists/delete_list_modal.html:15
+#: bookwyrm/templates/settings/announcements/announcement.html:20
+#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:49
+#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:36
+#: bookwyrm/templates/snippets/delete_readthrough_modal.html:15
+#: bookwyrm/templates/snippets/follow_request_buttons.html:12
+#: bookwyrm/templates/snippets/join_invitation_buttons.html:13
+msgid "Delete"
+msgstr ""
+
+#: bookwyrm/templates/groups/edit_form.html:5
+msgid "Edit Group"
+msgstr ""
+
+#: bookwyrm/templates/groups/find_users.html:6
+msgid "Add new members!"
+msgstr ""
+
+#: bookwyrm/templates/groups/form.html:8
+msgid "Group Name:"
+msgstr ""
+
+#: bookwyrm/templates/groups/form.html:12
+msgid "Group Description:"
+msgstr ""
+
+#: bookwyrm/templates/groups/form.html:30
+msgid "Delete group"
+msgstr ""
+
+#: bookwyrm/templates/groups/group.html:15
+msgid "Search to add a user"
+msgstr ""
+
+#: bookwyrm/templates/groups/group.html:36
+msgid "This group has no lists"
+msgstr ""
+
+#: bookwyrm/templates/groups/layout.html:16
+msgid "Edit group"
+msgstr ""
+
+#: bookwyrm/templates/groups/members.html:8
+msgid "Members can add and remove books on a group's book lists"
+msgstr ""
+
+#: bookwyrm/templates/groups/members.html:19
+msgid "Leave group"
+msgstr ""
+
+#: bookwyrm/templates/groups/members.html:41
+#: bookwyrm/templates/groups/suggested_users.html:32
+#: bookwyrm/templates/snippets/suggested_users.html:31
+#: bookwyrm/templates/user/user_preview.html:36
+msgid "Follows you"
+msgstr ""
+
+#: bookwyrm/templates/groups/suggested_users.html:17
+#: bookwyrm/templates/snippets/suggested_users.html:16
+#, python-format
+msgid "%(mutuals)s follower you follow"
+msgid_plural "%(mutuals)s followers you follow"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bookwyrm/templates/groups/suggested_users.html:24
+#: bookwyrm/templates/snippets/suggested_users.html:23
+#, python-format
+msgid "%(shared_books)s book on your shelves"
+msgid_plural "%(shared_books)s books on your shelves"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bookwyrm/templates/groups/suggested_users.html:40
+#, python-format
+msgid "No potential members found for \"%(user_query)s\""
+msgstr ""
+
+#: bookwyrm/templates/groups/user_groups.html:15
+msgid "Manager"
+msgstr ""
+
#: bookwyrm/templates/import/import.html:5
#: bookwyrm/templates/import/import.html:9
-#: bookwyrm/templates/shelf/shelf.html:57
+#: bookwyrm/templates/shelf/shelf.html:61
msgid "Import Books"
msgstr ""
@@ -1323,14 +1430,14 @@ msgid "Book"
msgstr ""
#: bookwyrm/templates/import/import_status.html:122
-#: bookwyrm/templates/shelf/shelf.html:128
-#: bookwyrm/templates/shelf/shelf.html:148
+#: bookwyrm/templates/shelf/shelf.html:141
+#: bookwyrm/templates/shelf/shelf.html:163
msgid "Title"
msgstr ""
#: bookwyrm/templates/import/import_status.html:125
-#: bookwyrm/templates/shelf/shelf.html:129
-#: bookwyrm/templates/shelf/shelf.html:151
+#: bookwyrm/templates/shelf/shelf.html:142
+#: bookwyrm/templates/shelf/shelf.html:166
msgid "Author"
msgstr ""
@@ -1339,23 +1446,10 @@ msgid "Imported"
msgstr ""
#: bookwyrm/templates/import/tooltip.html:6
-msgid "You can download your GoodReads data from the Import/Export page of your GoodReads account."
+msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account."
msgstr ""
-#: bookwyrm/templates/invite.html:4 bookwyrm/templates/invite.html:8
-#: bookwyrm/templates/login.html:49
-msgid "Create an Account"
-msgstr ""
-
-#: bookwyrm/templates/invite.html:21
-msgid "Permission Denied"
-msgstr ""
-
-#: bookwyrm/templates/invite.html:22
-msgid "Sorry! This invite code is no longer valid."
-msgstr ""
-
-#: bookwyrm/templates/landing/about.html:7
+#: bookwyrm/templates/landing/about.html:7 bookwyrm/templates/layout.html:230
#, python-format
msgid "About %(site_name)s"
msgstr ""
@@ -1370,6 +1464,20 @@ msgstr ""
msgid "Privacy Policy"
msgstr ""
+#: bookwyrm/templates/landing/invite.html:4
+#: bookwyrm/templates/landing/invite.html:8
+#: bookwyrm/templates/landing/login.html:49
+msgid "Create an Account"
+msgstr ""
+
+#: bookwyrm/templates/landing/invite.html:21
+msgid "Permission Denied"
+msgstr ""
+
+#: bookwyrm/templates/landing/invite.html:22
+msgid "Sorry! This invite code is no longer valid."
+msgstr ""
+
#: bookwyrm/templates/landing/landing.html:6
msgid "Recent Books"
msgstr ""
@@ -1408,6 +1516,53 @@ msgstr ""
msgid "Your Account"
msgstr ""
+#: bookwyrm/templates/landing/login.html:4
+msgid "Login"
+msgstr ""
+
+#: bookwyrm/templates/landing/login.html:7
+#: bookwyrm/templates/landing/login.html:37 bookwyrm/templates/layout.html:179
+msgid "Log in"
+msgstr ""
+
+#: bookwyrm/templates/landing/login.html:15
+msgid "Success! Email address confirmed."
+msgstr ""
+
+#: bookwyrm/templates/landing/login.html:21 bookwyrm/templates/layout.html:170
+#: bookwyrm/templates/snippets/register_form.html:4
+msgid "Username:"
+msgstr ""
+
+#: bookwyrm/templates/landing/login.html:27
+#: bookwyrm/templates/landing/password_reset.html:17
+#: bookwyrm/templates/layout.html:174
+#: bookwyrm/templates/snippets/register_form.html:22
+msgid "Password:"
+msgstr ""
+
+#: bookwyrm/templates/landing/login.html:40 bookwyrm/templates/layout.html:176
+msgid "Forgot your password?"
+msgstr ""
+
+#: bookwyrm/templates/landing/login.html:62
+msgid "More about this site"
+msgstr ""
+
+#: bookwyrm/templates/landing/password_reset.html:23
+#: bookwyrm/templates/preferences/change_password.html:18
+#: bookwyrm/templates/preferences/delete_user.html:20
+msgid "Confirm password:"
+msgstr ""
+
+#: bookwyrm/templates/landing/password_reset_request.html:14
+msgid "A link to reset your password will be sent to your email address"
+msgstr ""
+
+#: bookwyrm/templates/landing/password_reset_request.html:28
+msgid "Reset password"
+msgstr ""
+
#: bookwyrm/templates/layout.html:13
#, python-format
msgid "%(site_name)s search"
@@ -1455,25 +1610,10 @@ msgstr ""
msgid "Notifications"
msgstr ""
-#: bookwyrm/templates/layout.html:170 bookwyrm/templates/layout.html:174
-#: bookwyrm/templates/login.html:21
-#: bookwyrm/templates/snippets/register_form.html:4
-msgid "Username:"
-msgstr ""
-
#: bookwyrm/templates/layout.html:175
msgid "password"
msgstr ""
-#: bookwyrm/templates/layout.html:176 bookwyrm/templates/login.html:40
-msgid "Forgot your password?"
-msgstr ""
-
-#: bookwyrm/templates/layout.html:179 bookwyrm/templates/login.html:7
-#: bookwyrm/templates/login.html:37
-msgid "Log in"
-msgstr ""
-
#: bookwyrm/templates/layout.html:187
msgid "Join"
msgstr ""
@@ -1486,10 +1626,6 @@ msgstr ""
msgid "Error posting status"
msgstr ""
-#: bookwyrm/templates/layout.html:230
-msgid "About this instance"
-msgstr ""
-
#: bookwyrm/templates/layout.html:234
msgid "Contact site admin"
msgstr ""
@@ -1518,11 +1654,16 @@ msgstr ""
#: bookwyrm/templates/lists/created_text.html:5
#, python-format
-msgid "Created and curated by %(username)s "
+msgid "Created by %(username)s and managed by %(groupname)s "
msgstr ""
#: bookwyrm/templates/lists/created_text.html:7
#, python-format
+msgid "Created and curated by %(username)s "
+msgstr ""
+
+#: bookwyrm/templates/lists/created_text.html:9
+#, python-format
msgid "Created by %(username)s "
msgstr ""
@@ -1554,118 +1695,130 @@ msgstr ""
msgid "Delete this list?"
msgstr ""
-#: bookwyrm/templates/lists/delete_list_modal.html:7
-msgid "This action cannot be un-done"
-msgstr ""
-
-#: bookwyrm/templates/lists/delete_list_modal.html:15
-#: bookwyrm/templates/settings/announcements/announcement.html:20
-#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:49
-#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:36
-#: bookwyrm/templates/snippets/delete_readthrough_modal.html:15
-#: bookwyrm/templates/snippets/follow_request_buttons.html:12
-msgid "Delete"
-msgstr ""
-
#: bookwyrm/templates/lists/edit_form.html:5
#: bookwyrm/templates/lists/layout.html:16
msgid "Edit List"
msgstr ""
-#: bookwyrm/templates/lists/form.html:18
+#: bookwyrm/templates/lists/form.html:19
msgid "List curation:"
msgstr ""
-#: bookwyrm/templates/lists/form.html:21
+#: bookwyrm/templates/lists/form.html:22
msgid "Closed"
msgstr ""
-#: bookwyrm/templates/lists/form.html:22
+#: bookwyrm/templates/lists/form.html:23
msgid "Only you can add and remove books to this list"
msgstr ""
-#: bookwyrm/templates/lists/form.html:26
+#: bookwyrm/templates/lists/form.html:27
msgid "Curated"
msgstr ""
-#: bookwyrm/templates/lists/form.html:27
+#: bookwyrm/templates/lists/form.html:28
msgid "Anyone can suggest books, subject to your approval"
msgstr ""
-#: bookwyrm/templates/lists/form.html:31
+#: bookwyrm/templates/lists/form.html:32
msgctxt "curation type"
msgid "Open"
msgstr ""
-#: bookwyrm/templates/lists/form.html:32
+#: bookwyrm/templates/lists/form.html:33
msgid "Anyone can add books to this list"
msgstr ""
-#: bookwyrm/templates/lists/form.html:50
+#: bookwyrm/templates/lists/form.html:37
+msgid "Group"
+msgstr ""
+
+#: bookwyrm/templates/lists/form.html:38
+msgid "Group members can add to and remove from this list"
+msgstr ""
+
+#: bookwyrm/templates/lists/form.html:41
+msgid "Select Group"
+msgstr ""
+
+#: bookwyrm/templates/lists/form.html:45
+msgid "Select a group"
+msgstr ""
+
+#: bookwyrm/templates/lists/form.html:56
+msgid "You don't have any Groups yet!"
+msgstr ""
+
+#: bookwyrm/templates/lists/form.html:58
+msgid "Create a Group"
+msgstr ""
+
+#: bookwyrm/templates/lists/form.html:81
msgid "Delete list"
msgstr ""
-#: bookwyrm/templates/lists/list.html:20
+#: bookwyrm/templates/lists/list.html:21
msgid "You successfully suggested a book for this list!"
msgstr ""
-#: bookwyrm/templates/lists/list.html:22
+#: bookwyrm/templates/lists/list.html:23
msgid "You successfully added a book to this list!"
msgstr ""
-#: bookwyrm/templates/lists/list.html:28
+#: bookwyrm/templates/lists/list.html:29
msgid "This list is currently empty"
msgstr ""
-#: bookwyrm/templates/lists/list.html:66
+#: bookwyrm/templates/lists/list.html:67
#, python-format
msgid "Added by %(username)s "
msgstr ""
-#: bookwyrm/templates/lists/list.html:75
+#: bookwyrm/templates/lists/list.html:76
msgid "List position"
msgstr ""
-#: bookwyrm/templates/lists/list.html:81
+#: bookwyrm/templates/lists/list.html:82
msgid "Set"
msgstr ""
-#: bookwyrm/templates/lists/list.html:91
+#: bookwyrm/templates/lists/list.html:92
+#: bookwyrm/templates/snippets/remove_from_group_button.html:19
#: bookwyrm/templates/snippets/shelf_selector.html:26
msgid "Remove"
msgstr ""
-#: bookwyrm/templates/lists/list.html:105
-#: bookwyrm/templates/lists/list.html:122
+#: bookwyrm/templates/lists/list.html:106
+#: bookwyrm/templates/lists/list.html:123
msgid "Sort List"
msgstr ""
-#: bookwyrm/templates/lists/list.html:115
+#: bookwyrm/templates/lists/list.html:116
msgid "Direction"
msgstr ""
-#: bookwyrm/templates/lists/list.html:129
+#: bookwyrm/templates/lists/list.html:130
msgid "Add Books"
msgstr ""
-#: bookwyrm/templates/lists/list.html:131
+#: bookwyrm/templates/lists/list.html:132
msgid "Suggest Books"
msgstr ""
-#: bookwyrm/templates/lists/list.html:142
+#: bookwyrm/templates/lists/list.html:143
msgid "search"
msgstr ""
-#: bookwyrm/templates/lists/list.html:148
+#: bookwyrm/templates/lists/list.html:149
msgid "Clear search"
msgstr ""
-#: bookwyrm/templates/lists/list.html:153
+#: bookwyrm/templates/lists/list.html:154
#, python-format
msgid "No books found matching the query \"%(query)s\""
msgstr ""
-#: bookwyrm/templates/lists/list.html:181
+#: bookwyrm/templates/lists/list.html:182
msgid "Suggest"
msgstr ""
@@ -1677,29 +1830,17 @@ msgstr ""
msgid "Your Lists"
msgstr ""
-#: bookwyrm/templates/lists/lists.html:35
+#: bookwyrm/templates/lists/lists.html:36
msgid "All Lists"
msgstr ""
-#: bookwyrm/templates/lists/lists.html:39
+#: bookwyrm/templates/lists/lists.html:40
msgid "Saved Lists"
msgstr ""
-#: bookwyrm/templates/login.html:4
-msgid "Login"
-msgstr ""
-
-#: bookwyrm/templates/login.html:15
-msgid "Success! Email address confirmed."
-msgstr ""
-
-#: bookwyrm/templates/login.html:27 bookwyrm/templates/password_reset.html:17
-#: bookwyrm/templates/snippets/register_form.html:22
-msgid "Password:"
-msgstr ""
-
-#: bookwyrm/templates/login.html:62
-msgid "More about this site"
+#: bookwyrm/templates/notifications/items/accept.html:16
+#, python-format
+msgid "accepted your invitation to join group \"%(group_name)s \""
msgstr ""
#: bookwyrm/templates/notifications/items/add.html:24
@@ -1734,22 +1875,22 @@ msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:19
#, python-format
-msgid "favorited your review of %(book_title)s "
+msgid "liked your review of %(book_title)s "
msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:25
#, python-format
-msgid "favorited your comment on%(book_title)s "
+msgid "liked your comment on %(book_title)s "
msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:31
#, python-format
-msgid "favorited your quote from %(book_title)s "
+msgid "liked your quote from %(book_title)s "
msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:37
#, python-format
-msgid "favorited your status "
+msgid "liked your status "
msgstr ""
#: bookwyrm/templates/notifications/items/follow.html:15
@@ -1765,6 +1906,21 @@ msgstr ""
msgid "Your import completed."
msgstr ""
+#: bookwyrm/templates/notifications/items/invite.html:15
+#, python-format
+msgid "invited you to join the group \"%(group_name)s \""
+msgstr ""
+
+#: bookwyrm/templates/notifications/items/join.html:16
+#, python-format
+msgid "has joined your group \"%(group_name)s \""
+msgstr ""
+
+#: bookwyrm/templates/notifications/items/leave.html:16
+#, python-format
+msgid "has left your group \"%(group_name)s \""
+msgstr ""
+
#: bookwyrm/templates/notifications/items/mention.html:20
#, python-format
msgid "mentioned you in a review of %(book_title)s "
@@ -1785,6 +1941,16 @@ msgstr ""
msgid "mentioned you in a status "
msgstr ""
+#: bookwyrm/templates/notifications/items/remove.html:17
+#, python-format
+msgid "has been removed from your group \"%(group_name)s \""
+msgstr ""
+
+#: bookwyrm/templates/notifications/items/remove.html:23
+#, python-format
+msgid "You have been removed from the \"%(group_name)s \" group"
+msgstr ""
+
#: bookwyrm/templates/notifications/items/reply.html:21
#, python-format
msgid "replied to your review of %(book_title)s "
@@ -1810,6 +1976,21 @@ msgstr ""
msgid "A new report needs moderation."
msgstr ""
+#: bookwyrm/templates/notifications/items/update.html:16
+#, python-format
+msgid "has changed the privacy level for %(group_name)s "
+msgstr ""
+
+#: bookwyrm/templates/notifications/items/update.html:20
+#, python-format
+msgid "has changed the name of %(group_name)s "
+msgstr ""
+
+#: bookwyrm/templates/notifications/items/update.html:24
+#, python-format
+msgid "has changed the description of %(group_name)s "
+msgstr ""
+
#: bookwyrm/templates/notifications/notifications_page.html:18
msgid "Delete notifications"
msgstr ""
@@ -1826,20 +2007,6 @@ msgstr ""
msgid "You're all caught up!"
msgstr ""
-#: bookwyrm/templates/password_reset.html:23
-#: bookwyrm/templates/preferences/change_password.html:18
-#: bookwyrm/templates/preferences/delete_user.html:20
-msgid "Confirm password:"
-msgstr ""
-
-#: bookwyrm/templates/password_reset_request.html:14
-msgid "A link to reset your password will be sent to your email address"
-msgstr ""
-
-#: bookwyrm/templates/password_reset_request.html:28
-msgid "Reset password"
-msgstr ""
-
#: bookwyrm/templates/preferences/blocks.html:4
#: bookwyrm/templates/preferences/blocks.html:7
#: bookwyrm/templates/preferences/layout.html:31
@@ -2262,7 +2429,7 @@ msgid "Details"
msgstr ""
#: bookwyrm/templates/settings/federation/instance.html:35
-#: bookwyrm/templates/user/layout.html:63
+#: bookwyrm/templates/user/layout.html:64
msgid "Activity"
msgstr ""
@@ -2298,6 +2465,7 @@ msgid "Notes"
msgstr ""
#: bookwyrm/templates/settings/federation/instance.html:75
+#: bookwyrm/templates/snippets/status/status_options.html:24
msgid "Edit"
msgstr ""
@@ -2637,7 +2805,7 @@ msgid "Short description:"
msgstr ""
#: bookwyrm/templates/settings/site.html:37
-msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support html or markdown."
+msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support HTML or Markdown."
msgstr ""
#: bookwyrm/templates/settings/site.html:41
@@ -2812,7 +2980,7 @@ msgid "Permanently deleted"
msgstr ""
#: bookwyrm/templates/settings/users/user_moderation_actions.html:13
-#: bookwyrm/templates/snippets/status/status_options.html:35
+#: bookwyrm/templates/snippets/status/status_options.html:32
#: bookwyrm/templates/snippets/user_options.html:13
msgid "Send direct message"
msgstr ""
@@ -2837,53 +3005,66 @@ msgstr ""
msgid "Edit Shelf"
msgstr ""
-#: bookwyrm/templates/shelf/shelf.html:28 bookwyrm/views/shelf.py:55
+#: bookwyrm/templates/shelf/shelf.html:28 bookwyrm/views/shelf/shelf.py:53
msgid "All books"
msgstr ""
-#: bookwyrm/templates/shelf/shelf.html:55
+#: bookwyrm/templates/shelf/shelf.html:69
msgid "Create shelf"
msgstr ""
-#: bookwyrm/templates/shelf/shelf.html:77
+#: bookwyrm/templates/shelf/shelf.html:90
#, python-format
msgid "%(formatted_count)s book"
msgid_plural "%(formatted_count)s books"
msgstr[0] ""
msgstr[1] ""
-#: bookwyrm/templates/shelf/shelf.html:84
+#: bookwyrm/templates/shelf/shelf.html:97
#, python-format
msgid "(showing %(start)s-%(end)s)"
msgstr ""
-#: bookwyrm/templates/shelf/shelf.html:96
+#: bookwyrm/templates/shelf/shelf.html:109
msgid "Edit shelf"
msgstr ""
-#: bookwyrm/templates/shelf/shelf.html:104
+#: bookwyrm/templates/shelf/shelf.html:117
msgid "Delete shelf"
msgstr ""
-#: bookwyrm/templates/shelf/shelf.html:130
-#: bookwyrm/templates/shelf/shelf.html:154
+#: bookwyrm/templates/shelf/shelf.html:145
+#: bookwyrm/templates/shelf/shelf.html:171
msgid "Shelved"
msgstr ""
-#: bookwyrm/templates/shelf/shelf.html:131
-#: bookwyrm/templates/shelf/shelf.html:158
+#: bookwyrm/templates/shelf/shelf.html:146
+#: bookwyrm/templates/shelf/shelf.html:174
msgid "Started"
msgstr ""
-#: bookwyrm/templates/shelf/shelf.html:132
-#: bookwyrm/templates/shelf/shelf.html:161
+#: bookwyrm/templates/shelf/shelf.html:147
+#: bookwyrm/templates/shelf/shelf.html:177
msgid "Finished"
msgstr ""
-#: bookwyrm/templates/shelf/shelf.html:187
+#: bookwyrm/templates/shelf/shelf.html:203
msgid "This shelf is empty."
msgstr ""
+#: bookwyrm/templates/snippets/add_to_group_button.html:15
+msgid "Invite"
+msgstr ""
+
+#: bookwyrm/templates/snippets/add_to_group_button.html:24
+msgid "Uninvite"
+msgstr ""
+
+#: bookwyrm/templates/snippets/add_to_group_button.html:28
+#, python-format
+msgid "Remove @%(username)s"
+msgstr ""
+
#: bookwyrm/templates/snippets/announcement.html:31
#, python-format
msgid "Posted by %(username)s "
@@ -2927,22 +3108,22 @@ msgstr ""
msgid "Some thoughts on the book"
msgstr ""
-#: bookwyrm/templates/snippets/create_status/comment.html:26
+#: bookwyrm/templates/snippets/create_status/comment.html:27
#: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:15
msgid "Progress:"
msgstr ""
-#: bookwyrm/templates/snippets/create_status/comment.html:52
+#: bookwyrm/templates/snippets/create_status/comment.html:53
#: bookwyrm/templates/snippets/progress_field.html:18
msgid "pages"
msgstr ""
-#: bookwyrm/templates/snippets/create_status/comment.html:58
+#: bookwyrm/templates/snippets/create_status/comment.html:59
#: bookwyrm/templates/snippets/progress_field.html:23
msgid "percent"
msgstr ""
-#: bookwyrm/templates/snippets/create_status/comment.html:65
+#: bookwyrm/templates/snippets/create_status/comment.html:66
#, python-format
msgid "of %(pages)s pages"
msgstr ""
@@ -2970,7 +3151,7 @@ msgstr ""
msgid "Include spoiler alert"
msgstr ""
-#: bookwyrm/templates/snippets/create_status/layout.html:41
+#: bookwyrm/templates/snippets/create_status/layout.html:48
#: bookwyrm/templates/snippets/reading_modals/form.html:7
msgid "Comment:"
msgstr ""
@@ -2979,6 +3160,7 @@ msgstr ""
#: bookwyrm/templates/snippets/privacy-icons.html:15
#: bookwyrm/templates/snippets/privacy-icons.html:16
#: bookwyrm/templates/snippets/privacy_select.html:20
+#: bookwyrm/templates/snippets/privacy_select_no_followers.html:17
msgid "Private"
msgstr ""
@@ -3074,6 +3256,7 @@ msgid "Unfollow"
msgstr ""
#: bookwyrm/templates/snippets/follow_request_buttons.html:7
+#: bookwyrm/templates/snippets/join_invitation_buttons.html:8
msgid "Accept"
msgstr ""
@@ -3164,12 +3347,12 @@ msgstr ""
msgid "%(username)s has read %(read_count)s of %(goal_count)s books ."
msgstr ""
-#: bookwyrm/templates/snippets/page_text.html:4
+#: bookwyrm/templates/snippets/page_text.html:8
#, python-format
msgid "page %(page)s of %(total_pages)s"
msgstr ""
-#: bookwyrm/templates/snippets/page_text.html:6
+#: bookwyrm/templates/snippets/page_text.html:14
#, python-format
msgid "page %(page)s"
msgstr ""
@@ -3185,12 +3368,14 @@ msgstr ""
#: bookwyrm/templates/snippets/privacy-icons.html:3
#: bookwyrm/templates/snippets/privacy-icons.html:4
#: bookwyrm/templates/snippets/privacy_select.html:11
+#: bookwyrm/templates/snippets/privacy_select_no_followers.html:11
msgid "Public"
msgstr ""
#: bookwyrm/templates/snippets/privacy-icons.html:7
#: bookwyrm/templates/snippets/privacy-icons.html:8
#: bookwyrm/templates/snippets/privacy_select.html:14
+#: bookwyrm/templates/snippets/privacy_select_no_followers.html:14
msgid "Unlisted"
msgstr ""
@@ -3199,6 +3384,7 @@ msgid "Followers-only"
msgstr ""
#: bookwyrm/templates/snippets/privacy_select.html:6
+#: bookwyrm/templates/snippets/privacy_select_no_followers.html:6
msgid "Post privacy"
msgstr ""
@@ -3330,6 +3516,11 @@ msgstr ""
msgid "Hide status"
msgstr ""
+#: bookwyrm/templates/snippets/status/header.html:45
+#, python-format
+msgid "edited %(date)s"
+msgstr ""
+
#: bookwyrm/templates/snippets/status/headers/comment.html:2
#, python-format
msgid "commented on %(book)s "
@@ -3394,29 +3585,6 @@ msgstr ""
msgid "More options"
msgstr ""
-#: bookwyrm/templates/snippets/status/status_options.html:26
-msgid "Delete & re-draft"
-msgstr ""
-
-#: bookwyrm/templates/snippets/suggested_users.html:16
-#, python-format
-msgid "%(mutuals)s follower you follow"
-msgid_plural "%(mutuals)s followers you follow"
-msgstr[0] ""
-msgstr[1] ""
-
-#: bookwyrm/templates/snippets/suggested_users.html:23
-#, python-format
-msgid "%(shared_books)s book on your shelves"
-msgid_plural "%(shared_books)s books on your shelves"
-msgstr[0] ""
-msgstr[1] ""
-
-#: bookwyrm/templates/snippets/suggested_users.html:31
-#: bookwyrm/templates/user/user_preview.html:36
-msgid "Follows you"
-msgstr ""
-
#: bookwyrm/templates/snippets/switch_edition_button.html:5
msgid "Switch to this edition"
msgstr ""
@@ -3466,18 +3634,35 @@ msgstr ""
msgid "%(username)s's %(year)s Books"
msgstr ""
-#: bookwyrm/templates/user/layout.html:18 bookwyrm/templates/user/user.html:10
+#: bookwyrm/templates/user/groups.html:9
+msgid "Your Groups"
+msgstr ""
+
+#: bookwyrm/templates/user/groups.html:11
+#, python-format
+msgid "Groups: %(username)s"
+msgstr ""
+
+#: bookwyrm/templates/user/groups.html:17
+msgid "Create group"
+msgstr ""
+
+#: bookwyrm/templates/user/layout.html:19 bookwyrm/templates/user/user.html:10
msgid "User Profile"
msgstr ""
-#: bookwyrm/templates/user/layout.html:44
+#: bookwyrm/templates/user/layout.html:45
msgid "Follow Requests"
msgstr ""
-#: bookwyrm/templates/user/layout.html:69
+#: bookwyrm/templates/user/layout.html:70
msgid "Reading Goal"
msgstr ""
+#: bookwyrm/templates/user/layout.html:76
+msgid "Groups"
+msgstr ""
+
#: bookwyrm/templates/user/lists.html:11
#, python-format
msgid "Lists: %(username)s"
@@ -3568,15 +3753,15 @@ msgstr ""
msgid "Not a valid csv file"
msgstr ""
-#: bookwyrm/views/login.py:69
+#: bookwyrm/views/landing/login.py:69
msgid "Username or password are incorrect"
msgstr ""
-#: bookwyrm/views/password.py:32
+#: bookwyrm/views/landing/password.py:32
msgid "No user with that email address was found."
msgstr ""
-#: bookwyrm/views/password.py:41
+#: bookwyrm/views/landing/password.py:43
#, python-brace-format
msgid "A password reset link was sent to {email}"
msgstr ""
diff --git a/locale/es_ES/LC_MESSAGES/django.mo b/locale/es_ES/LC_MESSAGES/django.mo
index 93c9caed1..7df750310 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 d066ed1a9..ab71feb8a 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: 2021-10-06 23:57+0000\n"
-"PO-Revision-Date: 2021-10-08 00:04\n"
+"POT-Creation-Date: 2021-10-15 22:03+0000\n"
+"PO-Revision-Date: 2021-10-21 21:00\n"
"Last-Translator: Mouse Reeve \n"
"Language-Team: Spanish\n"
"Language: es\n"
@@ -54,8 +54,8 @@ msgstr "Orden de la lista"
msgid "Book Title"
msgstr "Título"
-#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:134
-#: bookwyrm/templates/shelf/shelf.html:165
+#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:136
+#: bookwyrm/templates/shelf/shelf.html:168
#: bookwyrm/templates/snippets/create_status/review.html:33
msgid "Rating"
msgstr "Calificación"
@@ -151,45 +151,49 @@ msgstr "nombre de usuario"
msgid "A user with that username already exists."
msgstr "Ya existe un usuario con ese nombre."
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home Timeline"
msgstr "Línea temporal de hogar"
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home"
msgstr "Hogar"
-#: bookwyrm/settings.py:118
+#: bookwyrm/settings.py:119
msgid "Books Timeline"
msgstr "Línea temporal de libros"
-#: bookwyrm/settings.py:118 bookwyrm/templates/search/layout.html:21
+#: bookwyrm/settings.py:119 bookwyrm/templates/search/layout.html:21
#: bookwyrm/templates/search/layout.html:42
#: bookwyrm/templates/user/layout.html:81
msgid "Books"
msgstr "Libros"
-#: bookwyrm/settings.py:164
+#: bookwyrm/settings.py:165
msgid "English"
msgstr "Inglés"
-#: bookwyrm/settings.py:165
+#: bookwyrm/settings.py:166
msgid "Deutsch (German)"
msgstr "Deutsch (Alemán)"
-#: bookwyrm/settings.py:166
+#: bookwyrm/settings.py:167
msgid "Español (Spanish)"
msgstr "Español"
-#: bookwyrm/settings.py:167
+#: bookwyrm/settings.py:168
msgid "Français (French)"
msgstr "Français (Francés)"
-#: bookwyrm/settings.py:168
+#: bookwyrm/settings.py:169
+msgid "Português - Brasil (Brazilian Portuguese)"
+msgstr "Português - Brasil (Portugués Brasileño)"
+
+#: bookwyrm/settings.py:170
msgid "简体中文 (Simplified Chinese)"
msgstr "简体中文 (Chino simplificado)"
-#: bookwyrm/settings.py:169
+#: bookwyrm/settings.py:171
msgid "繁體中文 (Traditional Chinese)"
msgstr "繁體中文 (Chino tradicional)"
@@ -221,7 +225,7 @@ msgstr "Editar Autor/Autora"
#: bookwyrm/templates/author/author.html:34
#: bookwyrm/templates/author/edit_author.html:41
msgid "Aliases:"
-msgstr ""
+msgstr "Alias:"
#: bookwyrm/templates/author/author.html:45
msgid "Born:"
@@ -233,7 +237,7 @@ msgstr "Muerto:"
#: bookwyrm/templates/author/author.html:61
msgid "Wikipedia"
-msgstr ""
+msgstr "Wikipedia"
#: bookwyrm/templates/author/author.html:69
#: bookwyrm/templates/book/book.html:94
@@ -296,7 +300,7 @@ msgstr "Separar varios valores con comas."
#: bookwyrm/templates/author/edit_author.html:50
msgid "Bio:"
-msgstr ""
+msgstr "Biografía:"
#: bookwyrm/templates/author/edit_author.html:57
msgid "Wikipedia link:"
@@ -484,7 +488,7 @@ msgstr "Número OCLC:"
#: bookwyrm/templates/book/book_identifiers.html:22
#: bookwyrm/templates/book/edit/edit_book_form.html:240
msgid "ASIN:"
-msgstr ""
+msgstr "ASIN:"
#: bookwyrm/templates/book/cover_modal.html:17
#: bookwyrm/templates/book/edit/edit_book_form.html:143
@@ -571,7 +575,7 @@ msgstr "Idiomas:"
#: bookwyrm/templates/book/edit/edit_book_form.html:74
msgid "Publication"
-msgstr ""
+msgstr "Publicación"
#: bookwyrm/templates/book/edit/edit_book_form.html:77
msgid "Publisher:"
@@ -635,11 +639,11 @@ msgstr "Identificadores de libro"
#: bookwyrm/templates/book/edit/edit_book_form.html:200
msgid "ISBN 13:"
-msgstr ""
+msgstr "ISBN 13:"
#: bookwyrm/templates/book/edit/edit_book_form.html:208
msgid "ISBN 10:"
-msgstr ""
+msgstr "ISBN 10:"
#: bookwyrm/templates/book/edit/edit_book_form.html:216
msgid "Openlibrary ID:"
@@ -669,11 +673,6 @@ msgstr "Idioma:"
msgid "Search editions"
msgstr "Buscar ediciones"
-#: bookwyrm/templates/book/publisher_info.html:21
-#, python-format
-msgid "%(format)s"
-msgstr ""
-
#: bookwyrm/templates/book/publisher_info.html:23
#, python-format
msgid "%(format)s, %(pages)s pages"
@@ -753,8 +752,8 @@ msgid "Help"
msgstr "Ayuda"
#: bookwyrm/templates/compose.html:5 bookwyrm/templates/compose.html:8
-msgid "Compose status"
-msgstr "Componer status"
+msgid "Edit status"
+msgstr "Editar estado"
#: bookwyrm/templates/confirm_email/confirm_email.html:4
msgid "Confirm email"
@@ -888,6 +887,26 @@ msgstr "Usuarios de BookWyrm"
msgid "All known users"
msgstr "Todos los usuarios conocidos"
+#: bookwyrm/templates/discover/card-header.html:9
+#, python-format
+msgid "%(username)s rated %(book_title)s "
+msgstr "%(username)s calificó %(book_title)s "
+
+#: bookwyrm/templates/discover/card-header.html:13
+#, python-format
+msgid "%(username)s reviewed %(book_title)s "
+msgstr "%(username)s reseñó %(book_title)s "
+
+#: bookwyrm/templates/discover/card-header.html:17
+#, python-format
+msgid "%(username)s commented on %(book_title)s "
+msgstr "%(username)s comentó en %(book_title)s "
+
+#: bookwyrm/templates/discover/card-header.html:21
+#, python-format
+msgid "%(username)s quoted %(book_title)s "
+msgstr "%(username)s citó %(book_title)s "
+
#: bookwyrm/templates/discover/discover.html:4
#: bookwyrm/templates/discover/discover.html:10
#: bookwyrm/templates/layout.html:78
@@ -899,28 +918,8 @@ msgstr "Descubrir"
msgid "See what's new in the local %(site_name)s community"
msgstr "Ver que es nuevo en la comunidad local de %(site_name)s"
-#: bookwyrm/templates/discover/large-book.html:46
-#: bookwyrm/templates/discover/small-book.html:32
-msgid "rated"
-msgstr "calificó"
-
-#: bookwyrm/templates/discover/large-book.html:48
-#: bookwyrm/templates/discover/small-book.html:34
-msgid "reviewed"
-msgstr "reseñó"
-
-#: bookwyrm/templates/discover/large-book.html:50
-#: bookwyrm/templates/discover/small-book.html:36
-msgid "commented on"
-msgstr "comentó en"
-
#: bookwyrm/templates/discover/large-book.html:52
-#: bookwyrm/templates/discover/small-book.html:38
-msgid "quoted"
-msgstr "citó"
-
-#: bookwyrm/templates/discover/large-book.html:68
-#: bookwyrm/templates/discover/small-book.html:52
+#: bookwyrm/templates/discover/small-book.html:36
msgid "View status"
msgstr "Ver status"
@@ -974,8 +973,8 @@ msgstr "Únete ahora"
#: bookwyrm/templates/email/invite/html_content.html:15
#, python-format
-msgid "Learn more about this instance ."
-msgstr "Aprenda más sobre esta instancia ."
+msgid "Learn more about %(site_name)s ."
+msgstr "Más información sobre %(site_name)s ."
#: bookwyrm/templates/email/invite/text_content.html:4
#, python-format
@@ -983,8 +982,9 @@ msgid "You're invited to join %(site_name)s! Click the link below to create an a
msgstr "Estás invitado a unirte con %(site_name)s! Haz clic en el enlace a continuación para crear una cuenta."
#: bookwyrm/templates/email/invite/text_content.html:8
-msgid "Learn more about this instance:"
-msgstr "Aprende más sobre esta intancia:"
+#, python-format
+msgid "Learn more about %(site_name)s:"
+msgstr "Más información sobre %(site_name)s:"
#: bookwyrm/templates/email/password_reset/html_content.html:6
#: bookwyrm/templates/email/password_reset/text_content.html:4
@@ -1198,7 +1198,7 @@ msgstr "Un poco sobre ti"
#: bookwyrm/templates/get_started/profile.html:32
#: bookwyrm/templates/preferences/edit_user.html:27
msgid "Avatar:"
-msgstr ""
+msgstr "Avatar:"
#: bookwyrm/templates/get_started/profile.html:42
#: bookwyrm/templates/preferences/edit_user.html:110
@@ -1323,13 +1323,13 @@ msgstr "Libro"
#: bookwyrm/templates/import/import_status.html:122
#: bookwyrm/templates/shelf/shelf.html:128
-#: bookwyrm/templates/shelf/shelf.html:148
+#: bookwyrm/templates/shelf/shelf.html:150
msgid "Title"
msgstr "Título"
#: bookwyrm/templates/import/import_status.html:125
#: bookwyrm/templates/shelf/shelf.html:129
-#: bookwyrm/templates/shelf/shelf.html:151
+#: bookwyrm/templates/shelf/shelf.html:153
msgid "Author"
msgstr "Autor/Autora"
@@ -1338,8 +1338,8 @@ msgid "Imported"
msgstr "Importado"
#: bookwyrm/templates/import/tooltip.html:6
-msgid "You can download your GoodReads data from the Import/Export page of your GoodReads account."
-msgstr "Puedes descargar tus datos de GoodReads de la Página de Exportación/Importación de tu cuenta de GoodReads."
+msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account."
+msgstr "Puede descargar sus datos de Goodreads desde la página de Importación/Exportación de su cuenta de Goodreads."
#: bookwyrm/templates/invite.html:4 bookwyrm/templates/invite.html:8
#: bookwyrm/templates/login.html:49
@@ -1354,7 +1354,7 @@ msgstr "Permiso denegado"
msgid "Sorry! This invite code is no longer valid."
msgstr "¡Disculpa! Este código de invitación no queda válido."
-#: bookwyrm/templates/landing/about.html:7
+#: bookwyrm/templates/landing/about.html:7 bookwyrm/templates/layout.html:230
#, python-format
msgid "About %(site_name)s"
msgstr "Sobre %(site_name)s"
@@ -1442,7 +1442,7 @@ msgstr "Invitaciones"
#: bookwyrm/templates/layout.html:132
msgid "Admin"
-msgstr ""
+msgstr "Administrador"
#: bookwyrm/templates/layout.html:139
msgid "Log out"
@@ -1485,10 +1485,6 @@ msgstr "Status publicado exitosamente"
msgid "Error posting status"
msgstr "Error en publicar status"
-#: bookwyrm/templates/layout.html:230
-msgid "About this instance"
-msgstr "Sobre esta instancia"
-
#: bookwyrm/templates/layout.html:234
msgid "Contact site admin"
msgstr "Contactarse con administradores del sitio"
@@ -1594,7 +1590,7 @@ msgstr "Cualquier usuario puede sugerir libros, en cuanto lo hayas aprobado"
#: bookwyrm/templates/lists/form.html:31
msgctxt "curation type"
msgid "Open"
-msgstr ""
+msgstr "Abrir"
#: bookwyrm/templates/lists/form.html:32
msgid "Anyone can add books to this list"
@@ -1704,12 +1700,12 @@ msgstr "Más sobre este sitio"
#: bookwyrm/templates/notifications/items/add.html:24
#, python-format
msgid "added %(book_title)s to your list \"%(list_name)s \""
-msgstr ""
+msgstr "agregó %(book_title)s a su lista «%(list_name)s »"
#: bookwyrm/templates/notifications/items/add.html:31
#, python-format
msgid "suggested adding %(book_title)s to your list \"%(list_name)s \""
-msgstr ""
+msgstr "sugirió agregar %(book_title)s a su lista «%(list_name)s »"
#: bookwyrm/templates/notifications/items/boost.html:19
#, python-format
@@ -1733,23 +1729,23 @@ msgstr "respaldó tu status "
#: bookwyrm/templates/notifications/items/fav.html:19
#, python-format
-msgid "favorited your review of %(book_title)s "
+msgid "liked your review of %(book_title)s "
msgstr "le gustó tu reseña de %(book_title)s "
#: bookwyrm/templates/notifications/items/fav.html:25
#, python-format
-msgid "favorited your comment on%(book_title)s "
-msgstr ""
+msgid "liked your comment on%(book_title)s "
+msgstr "le gustó tu comentario sobre %(book_title)s "
#: bookwyrm/templates/notifications/items/fav.html:31
#, python-format
-msgid "favorited your quote from %(book_title)s "
+msgid "liked your quote from %(book_title)s "
msgstr "le gustó tu cita de %(book_title)s "
#: bookwyrm/templates/notifications/items/fav.html:37
#, python-format
-msgid "favorited your status "
-msgstr "le gustó tu status "
+msgid "liked your status "
+msgstr "le gustó tu estado "
#: bookwyrm/templates/notifications/items/follow.html:15
msgid "followed you"
@@ -2004,7 +2000,7 @@ msgstr "Editar anuncio"
#: bookwyrm/templates/settings/announcements/announcement.html:35
msgid "Visible:"
-msgstr ""
+msgstr "Visible:"
#: bookwyrm/templates/settings/announcements/announcement.html:38
msgid "True"
@@ -2078,7 +2074,7 @@ msgstr "Fecha final"
#: bookwyrm/templates/settings/users/user_admin.html:34
#: bookwyrm/templates/settings/users/user_info.html:20
msgid "Status"
-msgstr ""
+msgstr "Estado"
#: bookwyrm/templates/settings/announcements/announcements.html:48
msgid "active"
@@ -2110,7 +2106,7 @@ msgstr "Activos este mes"
#: bookwyrm/templates/settings/dashboard/dashboard.html:27
msgid "Statuses"
-msgstr ""
+msgstr "Estados"
#: bookwyrm/templates/settings/dashboard/dashboard.html:33
#: bookwyrm/templates/settings/dashboard/works_chart.html:11
@@ -2157,11 +2153,11 @@ msgstr "Actividad de status"
#: bookwyrm/templates/settings/dashboard/dashboard.html:118
msgid "Works created"
-msgstr ""
+msgstr "Obras creadas"
#: bookwyrm/templates/settings/dashboard/registration_chart.html:10
msgid "Registrations"
-msgstr ""
+msgstr "Inscripciones"
#: bookwyrm/templates/settings/dashboard/status_chart.html:11
msgid "Statuses posted"
@@ -2238,13 +2234,13 @@ msgstr "Instancia:"
#: bookwyrm/templates/settings/federation/instance.html:28
#: bookwyrm/templates/settings/users/user_info.html:106
msgid "Status:"
-msgstr ""
+msgstr "Estado:"
#: bookwyrm/templates/settings/federation/edit_instance.html:52
#: bookwyrm/templates/settings/federation/instance.html:22
#: bookwyrm/templates/settings/users/user_info.html:100
msgid "Software:"
-msgstr ""
+msgstr "Software:"
#: bookwyrm/templates/settings/federation/edit_instance.html:61
#: bookwyrm/templates/settings/federation/instance.html:25
@@ -2297,6 +2293,7 @@ msgid "Notes"
msgstr "Notas"
#: bookwyrm/templates/settings/federation/instance.html:75
+#: bookwyrm/templates/snippets/status/status_options.html:24
msgid "Edit"
msgstr "Editar"
@@ -2357,7 +2354,7 @@ msgstr "Nombre de instancia"
#: bookwyrm/templates/settings/federation/instance_list.html:40
msgid "Software"
-msgstr ""
+msgstr "Software"
#: bookwyrm/templates/settings/federation/instance_list.html:63
msgid "No instances found"
@@ -2636,8 +2633,8 @@ msgid "Short description:"
msgstr "Descripción corta:"
#: bookwyrm/templates/settings/site.html:37
-msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support html or markdown."
-msgstr "Utilizado cuando la instancia se ve de una vista previa en joinbookwyrm.com. No es compatible con html o markdown."
+msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support HTML or Markdown."
+msgstr "Se utiliza cuando se obtiene una vista previa de la instancia en joinbookwyrm.com. No es compatible con HTML ni Markdown."
#: bookwyrm/templates/settings/site.html:41
msgid "Code of conduct:"
@@ -2649,7 +2646,7 @@ msgstr "Política de privacidad:"
#: bookwyrm/templates/settings/site.html:57
msgid "Logo:"
-msgstr ""
+msgstr "Logo:"
#: bookwyrm/templates/settings/site.html:61
msgid "Logo small:"
@@ -2657,7 +2654,7 @@ msgstr "Logo pequeño:"
#: bookwyrm/templates/settings/site.html:65
msgid "Favicon:"
-msgstr ""
+msgstr "Favicon:"
#: bookwyrm/templates/settings/site.html:77
msgid "Support link:"
@@ -2760,7 +2757,7 @@ msgstr "Ver perfil de usuario"
#: bookwyrm/templates/settings/users/user_info.html:36
msgid "Local"
-msgstr ""
+msgstr "Local"
#: bookwyrm/templates/settings/users/user_info.html:38
msgid "Remote"
@@ -2811,7 +2808,7 @@ msgid "Permanently deleted"
msgstr "Eliminado permanentemente"
#: bookwyrm/templates/settings/users/user_moderation_actions.html:13
-#: bookwyrm/templates/snippets/status/status_options.html:35
+#: bookwyrm/templates/snippets/status/status_options.html:32
#: bookwyrm/templates/snippets/user_options.html:13
msgid "Send direct message"
msgstr "Enviar mensaje directo"
@@ -2848,8 +2845,8 @@ msgstr "Crear estante"
#, python-format
msgid "%(formatted_count)s book"
msgid_plural "%(formatted_count)s books"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%(formatted_count)s libro"
+msgstr[1] "%(formatted_count)s libros"
#: bookwyrm/templates/shelf/shelf.html:84
#, python-format
@@ -2864,22 +2861,22 @@ msgstr "Editar estante"
msgid "Delete shelf"
msgstr "Eliminar estante"
-#: bookwyrm/templates/shelf/shelf.html:130
-#: bookwyrm/templates/shelf/shelf.html:154
+#: bookwyrm/templates/shelf/shelf.html:132
+#: bookwyrm/templates/shelf/shelf.html:158
msgid "Shelved"
msgstr "Archivado"
-#: bookwyrm/templates/shelf/shelf.html:131
-#: bookwyrm/templates/shelf/shelf.html:158
+#: bookwyrm/templates/shelf/shelf.html:133
+#: bookwyrm/templates/shelf/shelf.html:161
msgid "Started"
msgstr "Empezado"
-#: bookwyrm/templates/shelf/shelf.html:132
-#: bookwyrm/templates/shelf/shelf.html:161
+#: bookwyrm/templates/shelf/shelf.html:134
+#: bookwyrm/templates/shelf/shelf.html:164
msgid "Finished"
msgstr "Terminado"
-#: bookwyrm/templates/shelf/shelf.html:187
+#: bookwyrm/templates/shelf/shelf.html:190
msgid "This shelf is empty."
msgstr "Este estante está vacio."
@@ -2892,8 +2889,8 @@ msgstr "Publicado por %(username)s "
#, python-format
msgid "and %(remainder_count_display)s other"
msgid_plural "and %(remainder_count_display)s others"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "y %(remainder_count_display)s otro"
+msgstr[1] "y %(remainder_count_display)s otros"
#: bookwyrm/templates/snippets/book_cover.html:61
msgid "No cover"
@@ -2926,22 +2923,22 @@ msgstr "Cita"
msgid "Some thoughts on the book"
msgstr "Algunos pensamientos sobre el libro"
-#: bookwyrm/templates/snippets/create_status/comment.html:26
+#: bookwyrm/templates/snippets/create_status/comment.html:27
#: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:15
msgid "Progress:"
msgstr "Progreso:"
-#: bookwyrm/templates/snippets/create_status/comment.html:52
+#: bookwyrm/templates/snippets/create_status/comment.html:53
#: bookwyrm/templates/snippets/progress_field.html:18
msgid "pages"
msgstr "páginas"
-#: bookwyrm/templates/snippets/create_status/comment.html:58
+#: bookwyrm/templates/snippets/create_status/comment.html:59
#: bookwyrm/templates/snippets/progress_field.html:23
msgid "percent"
msgstr "por ciento"
-#: bookwyrm/templates/snippets/create_status/comment.html:65
+#: bookwyrm/templates/snippets/create_status/comment.html:66
#, python-format
msgid "of %(pages)s pages"
msgstr "de %(pages)s páginas"
@@ -2969,7 +2966,7 @@ msgstr "¡Advertencia, ya vienen spoilers!"
msgid "Include spoiler alert"
msgstr "Incluir alerta de spoiler"
-#: bookwyrm/templates/snippets/create_status/layout.html:41
+#: bookwyrm/templates/snippets/create_status/layout.html:48
#: bookwyrm/templates/snippets/reading_modals/form.html:7
msgid "Comment:"
msgstr "Comentario:"
@@ -3163,12 +3160,12 @@ msgstr "Has leído %(read_count)s de %(goal_count)s libros<
msgid "%(username)s has read %(read_count)s of %(goal_count)s books ."
msgstr "%(username)s ha leído %(read_count)s de %(goal_count)s libros ."
-#: bookwyrm/templates/snippets/page_text.html:4
+#: bookwyrm/templates/snippets/page_text.html:8
#, python-format
msgid "page %(page)s of %(total_pages)s"
msgstr "página %(page)s de %(total_pages)s"
-#: bookwyrm/templates/snippets/page_text.html:6
+#: bookwyrm/templates/snippets/page_text.html:14
#, python-format
msgid "page %(page)s"
msgstr "página %(page)s"
@@ -3319,7 +3316,7 @@ msgstr "(Página %(page)s)"
#: bookwyrm/templates/snippets/status/content_status.html:103
#, python-format
msgid "(%(percent)s%%)"
-msgstr ""
+msgstr "(%(percent)s%%)"
#: bookwyrm/templates/snippets/status/content_status.html:125
msgid "Open image in new window"
@@ -3329,6 +3326,11 @@ msgstr "Abrir imagen en una nueva ventana"
msgid "Hide status"
msgstr "Ocultar status"
+#: bookwyrm/templates/snippets/status/header.html:45
+#, python-format
+msgid "edited %(date)s"
+msgstr "editado %(date)s"
+
#: bookwyrm/templates/snippets/status/headers/comment.html:2
#, python-format
msgid "commented on %(book)s "
@@ -3393,10 +3395,6 @@ msgstr "respaldó"
msgid "More options"
msgstr "Más opciones"
-#: bookwyrm/templates/snippets/status/status_options.html:26
-msgid "Delete & re-draft"
-msgstr "Eliminar y recomponer"
-
#: bookwyrm/templates/snippets/suggested_users.html:16
#, python-format
msgid "%(mutuals)s follower you follow"
@@ -3561,7 +3559,7 @@ msgstr "Archivo excede el tamaño máximo: 10MB"
#: bookwyrm/templatetags/utilities.py:31
#, python-format
msgid "%(title)s: %(subtitle)s"
-msgstr ""
+msgstr "%(title)s: %(subtitle)s"
#: bookwyrm/views/import_data.py:67
msgid "Not a valid csv file"
diff --git a/locale/fr_FR/LC_MESSAGES/django.mo b/locale/fr_FR/LC_MESSAGES/django.mo
index a0d40fae6..5e8dfa664 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 699f8e8ba..141bd894b 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: 2021-10-06 23:57+0000\n"
-"PO-Revision-Date: 2021-10-08 10:19\n"
+"POT-Creation-Date: 2021-10-15 22:03+0000\n"
+"PO-Revision-Date: 2021-10-16 14:36\n"
"Last-Translator: Mouse Reeve \n"
"Language-Team: French\n"
"Language: fr\n"
@@ -54,8 +54,8 @@ msgstr "Ordre de la liste"
msgid "Book Title"
msgstr "Titre du livre"
-#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:134
-#: bookwyrm/templates/shelf/shelf.html:165
+#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:136
+#: bookwyrm/templates/shelf/shelf.html:168
#: bookwyrm/templates/snippets/create_status/review.html:33
msgid "Rating"
msgstr "Note"
@@ -151,45 +151,49 @@ msgstr "nom du compte :"
msgid "A user with that username already exists."
msgstr "Ce nom est déjà associé à un compte."
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home Timeline"
msgstr "Mon fil d’actualité"
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home"
msgstr "Accueil"
-#: bookwyrm/settings.py:118
+#: bookwyrm/settings.py:119
msgid "Books Timeline"
msgstr ""
-#: bookwyrm/settings.py:118 bookwyrm/templates/search/layout.html:21
+#: bookwyrm/settings.py:119 bookwyrm/templates/search/layout.html:21
#: bookwyrm/templates/search/layout.html:42
#: bookwyrm/templates/user/layout.html:81
msgid "Books"
msgstr "Livres"
-#: bookwyrm/settings.py:164
+#: bookwyrm/settings.py:165
msgid "English"
msgstr "English"
-#: bookwyrm/settings.py:165
+#: bookwyrm/settings.py:166
msgid "Deutsch (German)"
msgstr "Deutsch"
-#: bookwyrm/settings.py:166
+#: bookwyrm/settings.py:167
msgid "Español (Spanish)"
msgstr "Español"
-#: bookwyrm/settings.py:167
+#: bookwyrm/settings.py:168
msgid "Français (French)"
msgstr "Français"
-#: bookwyrm/settings.py:168
+#: bookwyrm/settings.py:169
+msgid "Português - Brasil (Brazilian Portuguese)"
+msgstr ""
+
+#: bookwyrm/settings.py:170
msgid "简体中文 (Simplified Chinese)"
msgstr "简化字"
-#: bookwyrm/settings.py:169
+#: bookwyrm/settings.py:171
msgid "繁體中文 (Traditional Chinese)"
msgstr "Infos supplémentaires :"
@@ -669,11 +673,6 @@ msgstr "Langue :"
msgid "Search editions"
msgstr "Rechercher des éditions"
-#: bookwyrm/templates/book/publisher_info.html:21
-#, python-format
-msgid "%(format)s"
-msgstr "%(format)s"
-
#: bookwyrm/templates/book/publisher_info.html:23
#, python-format
msgid "%(format)s, %(pages)s pages"
@@ -753,8 +752,8 @@ msgid "Help"
msgstr "Aide"
#: bookwyrm/templates/compose.html:5 bookwyrm/templates/compose.html:8
-msgid "Compose status"
-msgstr "Rédiger un statut"
+msgid "Edit status"
+msgstr ""
#: bookwyrm/templates/confirm_email/confirm_email.html:4
msgid "Confirm email"
@@ -888,6 +887,26 @@ msgstr "Comptes BookWyrm"
msgid "All known users"
msgstr "Tous les comptes connus"
+#: bookwyrm/templates/discover/card-header.html:9
+#, python-format
+msgid "%(username)s rated %(book_title)s "
+msgstr ""
+
+#: bookwyrm/templates/discover/card-header.html:13
+#, python-format
+msgid "%(username)s reviewed %(book_title)s "
+msgstr ""
+
+#: bookwyrm/templates/discover/card-header.html:17
+#, python-format
+msgid "%(username)s commented on %(book_title)s "
+msgstr ""
+
+#: bookwyrm/templates/discover/card-header.html:21
+#, python-format
+msgid "%(username)s quoted %(book_title)s "
+msgstr ""
+
#: bookwyrm/templates/discover/discover.html:4
#: bookwyrm/templates/discover/discover.html:10
#: bookwyrm/templates/layout.html:78
@@ -899,28 +918,8 @@ msgstr "Découvrir"
msgid "See what's new in the local %(site_name)s community"
msgstr "Voir les nouveautés de la communauté locale %(site_name)s"
-#: bookwyrm/templates/discover/large-book.html:46
-#: bookwyrm/templates/discover/small-book.html:32
-msgid "rated"
-msgstr "a noté"
-
-#: bookwyrm/templates/discover/large-book.html:48
-#: bookwyrm/templates/discover/small-book.html:34
-msgid "reviewed"
-msgstr "a écrit une critique de"
-
-#: bookwyrm/templates/discover/large-book.html:50
-#: bookwyrm/templates/discover/small-book.html:36
-msgid "commented on"
-msgstr "a commenté"
-
#: bookwyrm/templates/discover/large-book.html:52
-#: bookwyrm/templates/discover/small-book.html:38
-msgid "quoted"
-msgstr "a cité"
-
-#: bookwyrm/templates/discover/large-book.html:68
-#: bookwyrm/templates/discover/small-book.html:52
+#: bookwyrm/templates/discover/small-book.html:36
msgid "View status"
msgstr "Afficher tous les status"
@@ -974,8 +973,8 @@ msgstr "S’enregistrer maintenant"
#: bookwyrm/templates/email/invite/html_content.html:15
#, python-format
-msgid "Learn more about this instance ."
-msgstr "En savoir plus sur cette instance ."
+msgid "Learn more about %(site_name)s ."
+msgstr ""
#: bookwyrm/templates/email/invite/text_content.html:4
#, python-format
@@ -983,8 +982,9 @@ msgid "You're invited to join %(site_name)s! Click the link below to create an a
msgstr "Vous avez reçu une invitation à rejoindre %(site_name)s ! Cliquez le lien suivant pour créer un compte."
#: bookwyrm/templates/email/invite/text_content.html:8
-msgid "Learn more about this instance:"
-msgstr "En savoir plus sur cete instance :"
+#, python-format
+msgid "Learn more about %(site_name)s:"
+msgstr ""
#: bookwyrm/templates/email/password_reset/html_content.html:6
#: bookwyrm/templates/email/password_reset/text_content.html:4
@@ -1323,13 +1323,13 @@ msgstr "Livre"
#: bookwyrm/templates/import/import_status.html:122
#: bookwyrm/templates/shelf/shelf.html:128
-#: bookwyrm/templates/shelf/shelf.html:148
+#: bookwyrm/templates/shelf/shelf.html:150
msgid "Title"
msgstr "Titre"
#: bookwyrm/templates/import/import_status.html:125
#: bookwyrm/templates/shelf/shelf.html:129
-#: bookwyrm/templates/shelf/shelf.html:151
+#: bookwyrm/templates/shelf/shelf.html:153
msgid "Author"
msgstr "Auteur/autrice"
@@ -1338,8 +1338,8 @@ msgid "Imported"
msgstr "Importé"
#: bookwyrm/templates/import/tooltip.html:6
-msgid "You can download your GoodReads data from the Import/Export page of your GoodReads account."
-msgstr "Vous pouvez télécharger vos données GoodReads depuis la page Importation/Exportation de votre compte GoodRead."
+msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account."
+msgstr ""
#: bookwyrm/templates/invite.html:4 bookwyrm/templates/invite.html:8
#: bookwyrm/templates/login.html:49
@@ -1354,7 +1354,7 @@ msgstr "Autorisation refusée"
msgid "Sorry! This invite code is no longer valid."
msgstr "Cette invitation n’est plus valide ; désolé !"
-#: bookwyrm/templates/landing/about.html:7
+#: bookwyrm/templates/landing/about.html:7 bookwyrm/templates/layout.html:230
#, python-format
msgid "About %(site_name)s"
msgstr "À propos de %(site_name)s"
@@ -1485,10 +1485,6 @@ msgstr "Publié !"
msgid "Error posting status"
msgstr "Erreur lors de la publication"
-#: bookwyrm/templates/layout.html:230
-msgid "About this instance"
-msgstr "À propos de cette instance"
-
#: bookwyrm/templates/layout.html:234
msgid "Contact site admin"
msgstr "Contacter l’administrateur du site"
@@ -1733,23 +1729,23 @@ msgstr "a partagé votre statut "
#: bookwyrm/templates/notifications/items/fav.html:19
#, python-format
-msgid "favorited your review of %(book_title)s "
-msgstr "a ajouté votre critique de %(book_title)s à ses favoris"
+msgid "liked your review of %(book_title)s "
+msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:25
#, python-format
-msgid "favorited your comment on%(book_title)s "
+msgid "liked your comment on%(book_title)s "
msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:31
#, python-format
-msgid "favorited your quote from %(book_title)s "
-msgstr "a ajouté votre citation de %(book_title)s à ses favoris"
+msgid "liked your quote from %(book_title)s "
+msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:37
#, python-format
-msgid "favorited your status "
-msgstr "a ajouté votre statut à ses favoris"
+msgid "liked your status "
+msgstr ""
#: bookwyrm/templates/notifications/items/follow.html:15
msgid "followed you"
@@ -1904,7 +1900,7 @@ msgstr ""
#: bookwyrm/templates/preferences/edit_user.html:76
msgid "Show suggested users:"
-msgstr ""
+msgstr "Afficher les utilisateurs suggérés :"
#: bookwyrm/templates/preferences/edit_user.html:85
#, python-format
@@ -1917,7 +1913,7 @@ msgstr "Fuseau horaire préféré"
#: bookwyrm/templates/preferences/edit_user.html:116
msgid "Default post privacy:"
-msgstr ""
+msgstr "Niveau de confidentialité des messages par défaut :"
#: bookwyrm/templates/preferences/layout.html:11
msgid "Account"
@@ -1930,12 +1926,12 @@ msgstr "Relations"
#: bookwyrm/templates/reading_progress/finish.html:5
#, python-format
msgid "Finish \"%(book_title)s\""
-msgstr ""
+msgstr "Terminer \"%(book_title)s\""
#: bookwyrm/templates/reading_progress/start.html:5
#, python-format
msgid "Start \"%(book_title)s\""
-msgstr ""
+msgstr "Commencer \"%(book_title)s\""
#: bookwyrm/templates/reading_progress/want.html:5
#, python-format
@@ -2038,11 +2034,11 @@ msgstr "Ajouter une annonce"
#: bookwyrm/templates/settings/announcements/announcement_form.html:16
msgid "Preview:"
-msgstr ""
+msgstr "Aperçu :"
#: bookwyrm/templates/settings/announcements/announcement_form.html:23
msgid "Content:"
-msgstr ""
+msgstr "Contenu :"
#: bookwyrm/templates/settings/announcements/announcement_form.html:30
msgid "Event date:"
@@ -2141,11 +2137,11 @@ msgstr ""
#: bookwyrm/templates/settings/dashboard/dashboard.html:87
msgid "Days"
-msgstr ""
+msgstr "Jours"
#: bookwyrm/templates/settings/dashboard/dashboard.html:88
msgid "Weeks"
-msgstr ""
+msgstr "Semaines"
#: bookwyrm/templates/settings/dashboard/dashboard.html:106
msgid "User signup activity"
@@ -2161,7 +2157,7 @@ msgstr ""
#: bookwyrm/templates/settings/dashboard/registration_chart.html:10
msgid "Registrations"
-msgstr ""
+msgstr "Inscriptions"
#: bookwyrm/templates/settings/dashboard/status_chart.html:11
msgid "Statuses posted"
@@ -2188,7 +2184,7 @@ msgstr ""
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:18
msgid "When someone tries to register with an email from this domain, no account will be created. The registration process will appear to have worked."
-msgstr ""
+msgstr "Quand quelqu'un essaiera de s'inscrire avec un e-mail de ce domaine, aucun compte ne sera créé. Le processus d'inscription semblera avoir fonctionné."
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:25
msgid "Domain"
@@ -2197,14 +2193,14 @@ msgstr ""
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:29
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:27
msgid "Options"
-msgstr ""
+msgstr "Options"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:38
#, python-format
msgid "%(display_count)s user"
msgid_plural "%(display_count)s users"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%(display_count)s utilisateur"
+msgstr[1] "%(display_count)s utilisateurs"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:59
msgid "No email domains currently blocked"
@@ -2297,6 +2293,7 @@ msgid "Notes"
msgstr "Remarques"
#: bookwyrm/templates/settings/federation/instance.html:75
+#: bookwyrm/templates/snippets/status/status_options.html:24
msgid "Edit"
msgstr "Modifier"
@@ -2361,7 +2358,7 @@ msgstr "Logiciel"
#: bookwyrm/templates/settings/federation/instance_list.html:63
msgid "No instances found"
-msgstr ""
+msgstr "Aucune instance trouvée"
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:4
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:11
@@ -2472,33 +2469,33 @@ msgstr "Aucune invitation active"
#: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:5
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:10
msgid "Add IP address"
-msgstr ""
+msgstr "Ajouter une adresse IP"
#: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:11
msgid "Use IP address blocks with caution, and consider using blocks only temporarily, as IP addresses are often shared or change hands. If you block your own IP, you will not be able to access this page."
-msgstr ""
+msgstr "Bloquez des adresses IP avec précaution, voire de façon temporaire, car les adresses IP sont souvent partagées, ou changent de main. Si vous bloquez votre propre adresse IP, vous ne pourrez plus accéder à cette page."
#: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:18
msgid "IP Address:"
-msgstr ""
+msgstr "Adresse IP :"
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:5
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:7
#: bookwyrm/templates/settings/layout.html:63
msgid "IP Address Blocklist"
-msgstr ""
+msgstr "Liste des adresses IP bloquées"
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:18
msgid "Any traffic from this IP address will get a 404 response when trying to access any part of the application."
-msgstr ""
+msgstr "Tout trafic provenant de cette adresse IP obtiendra une réponse 404 en essayant d'accéder à n'importe quelle partie de l'application."
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:24
msgid "Address"
-msgstr ""
+msgstr "Adresse"
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:46
msgid "No IP addresses currently blocked"
-msgstr ""
+msgstr "Aucune adresse IP n'est actuellement bloquée"
#: bookwyrm/templates/settings/ip_blocklist/ip_tooltip.html:6
msgid "You can block IP ranges using CIDR syntax."
@@ -2636,8 +2633,8 @@ msgid "Short description:"
msgstr "Description courte :"
#: bookwyrm/templates/settings/site.html:37
-msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support html or markdown."
-msgstr "Utilisé lorsque l'instance est prévisualisée sur joinbookwyrm.com. Ne supporte pas html ou markdown."
+msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support HTML or Markdown."
+msgstr ""
#: bookwyrm/templates/settings/site.html:41
msgid "Code of conduct:"
@@ -2772,7 +2769,7 @@ msgstr "Détails du compte"
#: bookwyrm/templates/settings/users/user_info.html:51
msgid "Email:"
-msgstr "Email:"
+msgstr "Email :"
#: bookwyrm/templates/settings/users/user_info.html:61
msgid "(View reports)"
@@ -2811,7 +2808,7 @@ msgid "Permanently deleted"
msgstr "Supprimé définitivement"
#: bookwyrm/templates/settings/users/user_moderation_actions.html:13
-#: bookwyrm/templates/snippets/status/status_options.html:35
+#: bookwyrm/templates/snippets/status/status_options.html:32
#: bookwyrm/templates/snippets/user_options.html:13
msgid "Send direct message"
msgstr "Envoyer un message direct"
@@ -2864,22 +2861,22 @@ msgstr "Modifier l’étagère"
msgid "Delete shelf"
msgstr "Supprimer l’étagère"
-#: bookwyrm/templates/shelf/shelf.html:130
-#: bookwyrm/templates/shelf/shelf.html:154
+#: bookwyrm/templates/shelf/shelf.html:132
+#: bookwyrm/templates/shelf/shelf.html:158
msgid "Shelved"
msgstr "Date d’ajout"
-#: bookwyrm/templates/shelf/shelf.html:131
-#: bookwyrm/templates/shelf/shelf.html:158
+#: bookwyrm/templates/shelf/shelf.html:133
+#: bookwyrm/templates/shelf/shelf.html:161
msgid "Started"
msgstr "Commencé"
-#: bookwyrm/templates/shelf/shelf.html:132
-#: bookwyrm/templates/shelf/shelf.html:161
+#: bookwyrm/templates/shelf/shelf.html:134
+#: bookwyrm/templates/shelf/shelf.html:164
msgid "Finished"
msgstr "Terminé"
-#: bookwyrm/templates/shelf/shelf.html:187
+#: bookwyrm/templates/shelf/shelf.html:190
msgid "This shelf is empty."
msgstr "Cette étagère est vide"
@@ -2892,8 +2889,8 @@ msgstr "Publiée par %(username)s "
#, python-format
msgid "and %(remainder_count_display)s other"
msgid_plural "and %(remainder_count_display)s others"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "et %(remainder_count_display)s autre"
+msgstr[1] "et %(remainder_count_display)s autres"
#: bookwyrm/templates/snippets/book_cover.html:61
msgid "No cover"
@@ -2926,22 +2923,22 @@ msgstr "Citation"
msgid "Some thoughts on the book"
msgstr ""
-#: bookwyrm/templates/snippets/create_status/comment.html:26
+#: bookwyrm/templates/snippets/create_status/comment.html:27
#: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:15
msgid "Progress:"
msgstr "Progression :"
-#: bookwyrm/templates/snippets/create_status/comment.html:52
+#: bookwyrm/templates/snippets/create_status/comment.html:53
#: bookwyrm/templates/snippets/progress_field.html:18
msgid "pages"
msgstr "pages"
-#: bookwyrm/templates/snippets/create_status/comment.html:58
+#: bookwyrm/templates/snippets/create_status/comment.html:59
#: bookwyrm/templates/snippets/progress_field.html:23
msgid "percent"
msgstr "pourcent"
-#: bookwyrm/templates/snippets/create_status/comment.html:65
+#: bookwyrm/templates/snippets/create_status/comment.html:66
#, python-format
msgid "of %(pages)s pages"
msgstr "sur %(pages)s pages"
@@ -2969,7 +2966,7 @@ msgstr "Attention spoilers !"
msgid "Include spoiler alert"
msgstr "Afficher une alerte spoiler"
-#: bookwyrm/templates/snippets/create_status/layout.html:41
+#: bookwyrm/templates/snippets/create_status/layout.html:48
#: bookwyrm/templates/snippets/reading_modals/form.html:7
msgid "Comment:"
msgstr "Commentaire :"
@@ -3163,12 +3160,12 @@ msgstr "Vous avez lu %(read_count)s sur %(goal_count)s livr
msgid "%(username)s has read %(read_count)s of %(goal_count)s books ."
msgstr "%(username)s a lu %(read_count)s sur %(goal_count)s livres ."
-#: bookwyrm/templates/snippets/page_text.html:4
+#: bookwyrm/templates/snippets/page_text.html:8
#, python-format
msgid "page %(page)s of %(total_pages)s"
msgstr "page %(page)s sur %(total_pages)s pages"
-#: bookwyrm/templates/snippets/page_text.html:6
+#: bookwyrm/templates/snippets/page_text.html:14
#, python-format
msgid "page %(page)s"
msgstr "page %(page)s"
@@ -3329,10 +3326,15 @@ msgstr "Ouvrir l’image dans une nouvelle fenêtre"
msgid "Hide status"
msgstr ""
+#: bookwyrm/templates/snippets/status/header.html:45
+#, python-format
+msgid "edited %(date)s"
+msgstr ""
+
#: bookwyrm/templates/snippets/status/headers/comment.html:2
#, python-format
msgid "commented on %(book)s "
-msgstr ""
+msgstr "a commenté %(book)s "
#: bookwyrm/templates/snippets/status/headers/note.html:15
#, python-format
@@ -3342,32 +3344,32 @@ msgstr "a répondu au statut de %(book)s "
-msgstr ""
+msgstr "a cité un passage de %(book)s "
#: bookwyrm/templates/snippets/status/headers/rating.html:3
#, python-format
msgid "rated %(book)s :"
-msgstr ""
+msgstr "a noté %(book)s :"
#: bookwyrm/templates/snippets/status/headers/read.html:7
#, python-format
msgid "finished reading %(book)s "
-msgstr ""
+msgstr "a terminé %(book)s "
#: bookwyrm/templates/snippets/status/headers/reading.html:7
#, python-format
msgid "started reading %(book)s "
-msgstr ""
+msgstr "a commencé %(book)s "
#: bookwyrm/templates/snippets/status/headers/review.html:3
#, python-format
msgid "reviewed %(book)s "
-msgstr ""
+msgstr "a critiqué %(book)s "
#: bookwyrm/templates/snippets/status/headers/to_read.html:7
#, python-format
msgid "%(username)s wants to read %(book)s "
-msgstr ""
+msgstr "%(username)s veut lire %(book)s "
#: bookwyrm/templates/snippets/status/layout.html:24
#: bookwyrm/templates/snippets/status/status_options.html:17
@@ -3393,10 +3395,6 @@ msgstr "a partagé"
msgid "More options"
msgstr "Plus d’options"
-#: bookwyrm/templates/snippets/status/status_options.html:26
-msgid "Delete & re-draft"
-msgstr "Supprimer & recommencer la rédaction"
-
#: bookwyrm/templates/snippets/suggested_users.html:16
#, python-format
msgid "%(mutuals)s follower you follow"
@@ -3414,7 +3412,7 @@ msgstr[1] "%(shared_books)s livres sur vos étagères"
#: bookwyrm/templates/snippets/suggested_users.html:31
#: bookwyrm/templates/user/user_preview.html:36
msgid "Follows you"
-msgstr ""
+msgstr "Vous suit"
#: bookwyrm/templates/snippets/switch_edition_button.html:5
msgid "Switch to this edition"
@@ -3552,7 +3550,7 @@ msgstr[1] "%(mutuals_display)s abonné(e)s que vous suivez"
#: bookwyrm/templates/user/user_preview.html:38
msgid "No followers you follow"
-msgstr ""
+msgstr "Aucun·e abonné·e que vous suivez"
#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:28
msgid "File exceeds maximum size: 10MB"
@@ -3569,7 +3567,7 @@ msgstr "Fichier CSV non valide"
#: bookwyrm/views/login.py:69
msgid "Username or password are incorrect"
-msgstr ""
+msgstr "Identifiant ou mot de passe incorrect"
#: bookwyrm/views/password.py:32
msgid "No user with that email address was found."
diff --git a/locale/pt_BR/LC_MESSAGES/django.mo b/locale/pt_BR/LC_MESSAGES/django.mo
index 1942ada36..1ebe52800 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 d3add60c7..2e729a2f2 100644
--- a/locale/pt_BR/LC_MESSAGES/django.po
+++ b/locale/pt_BR/LC_MESSAGES/django.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: bookwyrm\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-10-06 23:57+0000\n"
-"PO-Revision-Date: 2021-10-13 16:42\n"
+"POT-Creation-Date: 2021-10-15 22:03+0000\n"
+"PO-Revision-Date: 2021-10-22 13:31\n"
"Last-Translator: Mouse Reeve \n"
"Language-Team: Portuguese, Brazilian\n"
"Language: pt\n"
@@ -23,15 +23,15 @@ msgstr "Já existe um usuário com este endereço de e-mail."
#: bookwyrm/forms.py:256
msgid "One Day"
-msgstr "Um Dia"
+msgstr "Um dia"
#: bookwyrm/forms.py:257
msgid "One Week"
-msgstr "Uma Semana"
+msgstr "Uma semana"
#: bookwyrm/forms.py:258
msgid "One Month"
-msgstr "Um Mês"
+msgstr "Um mês"
#: bookwyrm/forms.py:259
msgid "Does Not Expire"
@@ -48,14 +48,14 @@ msgstr "Ilimitado"
#: bookwyrm/forms.py:326
msgid "List Order"
-msgstr "Ordem da lista"
+msgstr "Ordem de inserção"
#: bookwyrm/forms.py:327
msgid "Book Title"
msgstr "Título do livro"
-#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:134
-#: bookwyrm/templates/shelf/shelf.html:165
+#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:136
+#: bookwyrm/templates/shelf/shelf.html:168
#: bookwyrm/templates/snippets/create_status/review.html:33
msgid "Rating"
msgstr "Avaliação"
@@ -151,45 +151,49 @@ msgstr "nome de usuário"
msgid "A user with that username already exists."
msgstr "Já existe um usuário com este nome."
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home Timeline"
msgstr "Linha do tempo"
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home"
msgstr "Página inicial"
-#: bookwyrm/settings.py:118
+#: bookwyrm/settings.py:119
msgid "Books Timeline"
msgstr "Linha do tempo dos livros"
-#: bookwyrm/settings.py:118 bookwyrm/templates/search/layout.html:21
+#: bookwyrm/settings.py:119 bookwyrm/templates/search/layout.html:21
#: bookwyrm/templates/search/layout.html:42
#: bookwyrm/templates/user/layout.html:81
msgid "Books"
msgstr "Livros"
-#: bookwyrm/settings.py:164
+#: bookwyrm/settings.py:165
msgid "English"
msgstr "English (Inglês)"
-#: bookwyrm/settings.py:165
+#: bookwyrm/settings.py:166
msgid "Deutsch (German)"
msgstr "Deutsch (Alemão)"
-#: bookwyrm/settings.py:166
+#: bookwyrm/settings.py:167
msgid "Español (Spanish)"
msgstr "Español (Espanhol)"
-#: bookwyrm/settings.py:167
+#: bookwyrm/settings.py:168
msgid "Français (French)"
msgstr "Français (Francês)"
-#: bookwyrm/settings.py:168
+#: bookwyrm/settings.py:169
+msgid "Português - Brasil (Brazilian Portuguese)"
+msgstr "Português - Brasil (Brazilian Portuguese)"
+
+#: bookwyrm/settings.py:170
msgid "简体中文 (Simplified Chinese)"
msgstr "简体中文 (Chinês simplificado)"
-#: bookwyrm/settings.py:169
+#: bookwyrm/settings.py:171
msgid "繁體中文 (Traditional Chinese)"
msgstr "繁體中文 (Chinês tradicional)"
@@ -669,11 +673,6 @@ msgstr "Idioma:"
msgid "Search editions"
msgstr "Procurar edições"
-#: bookwyrm/templates/book/publisher_info.html:21
-#, python-format
-msgid "%(format)s"
-msgstr "%(format)s"
-
#: bookwyrm/templates/book/publisher_info.html:23
#, python-format
msgid "%(format)s, %(pages)s pages"
@@ -753,8 +752,8 @@ msgid "Help"
msgstr "Ajuda"
#: bookwyrm/templates/compose.html:5 bookwyrm/templates/compose.html:8
-msgid "Compose status"
-msgstr "Escrever publicação"
+msgid "Edit status"
+msgstr "Editar publicação"
#: bookwyrm/templates/confirm_email/confirm_email.html:4
msgid "Confirm email"
@@ -888,6 +887,26 @@ msgstr "Usuários da BookWyrm"
msgid "All known users"
msgstr "Todos os usuários conhecidos"
+#: bookwyrm/templates/discover/card-header.html:9
+#, python-format
+msgid "%(username)s rated %(book_title)s "
+msgstr "%(username)s avaliou %(book_title)s "
+
+#: bookwyrm/templates/discover/card-header.html:13
+#, python-format
+msgid "%(username)s reviewed %(book_title)s "
+msgstr "%(username)s resenhou %(book_title)s "
+
+#: bookwyrm/templates/discover/card-header.html:17
+#, python-format
+msgid "%(username)s commented on %(book_title)s "
+msgstr "%(username)s comentou sobre %(book_title)s "
+
+#: bookwyrm/templates/discover/card-header.html:21
+#, python-format
+msgid "%(username)s quoted %(book_title)s "
+msgstr "%(username)s citou %(book_title)s "
+
#: bookwyrm/templates/discover/discover.html:4
#: bookwyrm/templates/discover/discover.html:10
#: bookwyrm/templates/layout.html:78
@@ -899,28 +918,8 @@ msgstr "Explorar"
msgid "See what's new in the local %(site_name)s community"
msgstr "Veja as novidades da comunidade %(site_name)s local"
-#: bookwyrm/templates/discover/large-book.html:46
-#: bookwyrm/templates/discover/small-book.html:32
-msgid "rated"
-msgstr "avaliado"
-
-#: bookwyrm/templates/discover/large-book.html:48
-#: bookwyrm/templates/discover/small-book.html:34
-msgid "reviewed"
-msgstr "resenhado"
-
-#: bookwyrm/templates/discover/large-book.html:50
-#: bookwyrm/templates/discover/small-book.html:36
-msgid "commented on"
-msgstr "comentado"
-
#: bookwyrm/templates/discover/large-book.html:52
-#: bookwyrm/templates/discover/small-book.html:38
-msgid "quoted"
-msgstr "citou"
-
-#: bookwyrm/templates/discover/large-book.html:68
-#: bookwyrm/templates/discover/small-book.html:52
+#: bookwyrm/templates/discover/small-book.html:36
msgid "View status"
msgstr "Ver publicação"
@@ -937,7 +936,7 @@ msgstr "Confirmar email"
#: bookwyrm/templates/email/confirm/html_content.html:15
#, python-format
msgid "Or enter the code \"%(confirmation_code)s
\" at login."
-msgstr "Ou insira o código \"%(confirmation_code)s
\" ao fazer login."
+msgstr "Ou insira o código \"%(confirmation_code)s
\" quando entrar."
#: bookwyrm/templates/email/confirm/subject.html:2
msgid "Please confirm your email"
@@ -946,7 +945,7 @@ msgstr "Por favor, confirme seu email"
#: bookwyrm/templates/email/confirm/text_content.html:10
#, python-format
msgid "Or enter the code \"%(confirmation_code)s\" at login."
-msgstr "Ou insira o código \"%(confirmation_code)s\" ao fazer login."
+msgstr "Ou insira o código \"%(confirmation_code)s\" quando entrar."
#: bookwyrm/templates/email/html_layout.html:15
#: bookwyrm/templates/email/text_layout.html:2
@@ -974,8 +973,8 @@ msgstr "Inscreva-se"
#: bookwyrm/templates/email/invite/html_content.html:15
#, python-format
-msgid "Learn more about this instance ."
-msgstr "Saiba mais sobre esta instância ."
+msgid "Learn more about %(site_name)s ."
+msgstr "Saiba mais sobre %(site_name)s ."
#: bookwyrm/templates/email/invite/text_content.html:4
#, python-format
@@ -983,14 +982,15 @@ msgid "You're invited to join %(site_name)s! Click the link below to create an a
msgstr "Você recebeu um convite para juntar-se a %(site_name)s! Clique no link abaixo para criar uma conta."
#: bookwyrm/templates/email/invite/text_content.html:8
-msgid "Learn more about this instance:"
-msgstr "Saiba mais sobre esta instância:"
+#, python-format
+msgid "Learn more about %(site_name)s:"
+msgstr "Saiba mais sobre %(site_name)s:"
#: bookwyrm/templates/email/password_reset/html_content.html:6
#: bookwyrm/templates/email/password_reset/text_content.html:4
#, python-format
msgid "You requested to reset your %(site_name)s password. Click the link below to set a new password and log in to your account."
-msgstr "Você solicitou a redefinição de sua senha no %(site_name)s. Clique no link abaixo para definir uma nova senha e fazer login."
+msgstr "Você solicitou a redefinição de sua senha no %(site_name)s. Clique no link abaixo para definir uma nova senha e entrar no site."
#: bookwyrm/templates/email/password_reset/html_content.html:9
#: bookwyrm/templates/password_reset.html:4
@@ -1189,7 +1189,7 @@ msgstr "Nome de exibição:"
#: bookwyrm/templates/get_started/profile.html:22
#: bookwyrm/templates/preferences/edit_user.html:49
msgid "Summary:"
-msgstr "Descrição:"
+msgstr "Bio:"
#: bookwyrm/templates/get_started/profile.html:23
msgid "A little bit about you"
@@ -1323,13 +1323,13 @@ msgstr "Livro"
#: bookwyrm/templates/import/import_status.html:122
#: bookwyrm/templates/shelf/shelf.html:128
-#: bookwyrm/templates/shelf/shelf.html:148
+#: bookwyrm/templates/shelf/shelf.html:150
msgid "Title"
msgstr "Título"
#: bookwyrm/templates/import/import_status.html:125
#: bookwyrm/templates/shelf/shelf.html:129
-#: bookwyrm/templates/shelf/shelf.html:151
+#: bookwyrm/templates/shelf/shelf.html:153
msgid "Author"
msgstr "Autor"
@@ -1338,7 +1338,7 @@ msgid "Imported"
msgstr "Importado"
#: bookwyrm/templates/import/tooltip.html:6
-msgid "You can download your GoodReads data from the Import/Export page of your GoodReads account."
+msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account."
msgstr "Você pode baixar seus dados do Goodreads na página de Importar/Exportar da sua conta."
#: bookwyrm/templates/invite.html:4 bookwyrm/templates/invite.html:8
@@ -1354,7 +1354,7 @@ msgstr "Permissão negada"
msgid "Sorry! This invite code is no longer valid."
msgstr "Desculpe! Este convite não é mais válido."
-#: bookwyrm/templates/landing/about.html:7
+#: bookwyrm/templates/landing/about.html:7 bookwyrm/templates/layout.html:230
#, python-format
msgid "About %(site_name)s"
msgstr "Sobre %(site_name)s"
@@ -1422,7 +1422,7 @@ msgstr "Menu de navegação principal"
#: bookwyrm/templates/layout.html:72
msgid "Feed"
-msgstr "Feed"
+msgstr "Novidades"
#: bookwyrm/templates/layout.html:106
msgid "Your Books"
@@ -1466,12 +1466,12 @@ msgstr "senha"
#: bookwyrm/templates/layout.html:176 bookwyrm/templates/login.html:40
msgid "Forgot your password?"
-msgstr "Esqueceu a senha?"
+msgstr "Esqueceu sua senha?"
#: bookwyrm/templates/layout.html:179 bookwyrm/templates/login.html:7
#: bookwyrm/templates/login.html:37
msgid "Log in"
-msgstr "Fazer login"
+msgstr "Entrar"
#: bookwyrm/templates/layout.html:187
msgid "Join"
@@ -1485,10 +1485,6 @@ msgstr "Publicação feita com sucesso"
msgid "Error posting status"
msgstr "Erro ao publicar"
-#: bookwyrm/templates/layout.html:230
-msgid "About this instance"
-msgstr "Sobre esta instância"
-
#: bookwyrm/templates/layout.html:234
msgid "Contact site admin"
msgstr "Contatar administração"
@@ -1500,7 +1496,7 @@ msgstr "Documentação"
#: bookwyrm/templates/layout.html:245
#, python-format
msgid "Support %(site_name)s on %(support_title)s "
-msgstr "Apoie a instância %(site_name)s em %(support_title)s "
+msgstr "Apoie a instância %(site_name)s: %(support_title)s "
#: bookwyrm/templates/layout.html:249
msgid "BookWyrm's source code is freely available. You can contribute or report issues on GitHub ."
@@ -1733,22 +1729,22 @@ msgstr "compartilhou sua publicação "
#: bookwyrm/templates/notifications/items/fav.html:19
#, python-format
-msgid "favorited your review of %(book_title)s "
+msgid "liked your review of %(book_title)s "
msgstr "curtiu sua resenha de %(book_title)s "
#: bookwyrm/templates/notifications/items/fav.html:25
#, python-format
-msgid "favorited your comment on%(book_title)s "
-msgstr "curtiu seu comentário sobre%(book_title)s "
+msgid "liked your comment on%(book_title)s "
+msgstr "curtiu seu comentário sobre %(book_title)s "
#: bookwyrm/templates/notifications/items/fav.html:31
#, python-format
-msgid "favorited your quote from %(book_title)s "
+msgid "liked your quote from %(book_title)s "
msgstr "curtiu sua citação de %(book_title)s "
#: bookwyrm/templates/notifications/items/fav.html:37
#, python-format
-msgid "favorited your status "
+msgid "liked your status "
msgstr "curtiu sua publicação "
#: bookwyrm/templates/notifications/items/follow.html:15
@@ -1900,7 +1896,7 @@ msgstr "Privacidade"
#: bookwyrm/templates/preferences/edit_user.html:72
msgid "Show reading goal prompt in feed:"
-msgstr "Mostrar sugestão de meta de leitura no feed:"
+msgstr "Mostrar sugestão de meta de leitura:"
#: bookwyrm/templates/preferences/edit_user.html:76
msgid "Show suggested users:"
@@ -1962,7 +1958,7 @@ msgstr "Adicionar livro manualmente"
#: bookwyrm/templates/search/book.html:116
msgid "Log in to import or add books."
-msgstr "Faça login para importar ou adicionar livros."
+msgstr "Entre para importar ou adicionar livros."
#: bookwyrm/templates/search/layout.html:16
msgid "Search query"
@@ -2115,7 +2111,7 @@ msgstr "Publicações"
#: bookwyrm/templates/settings/dashboard/dashboard.html:33
#: bookwyrm/templates/settings/dashboard/works_chart.html:11
msgid "Works"
-msgstr ""
+msgstr "Obras"
#: bookwyrm/templates/settings/dashboard/dashboard.html:43
#, python-format
@@ -2157,7 +2153,7 @@ msgstr "Publicações"
#: bookwyrm/templates/settings/dashboard/dashboard.html:118
msgid "Works created"
-msgstr ""
+msgstr "Obras criadas"
#: bookwyrm/templates/settings/dashboard/registration_chart.html:10
msgid "Registrations"
@@ -2297,6 +2293,7 @@ msgid "Notes"
msgstr "Notas"
#: bookwyrm/templates/settings/federation/instance.html:75
+#: bookwyrm/templates/snippets/status/status_options.html:24
msgid "Edit"
msgstr "Editar"
@@ -2550,7 +2547,7 @@ msgstr "Comentários da moderação"
#: bookwyrm/templates/settings/reports/report.html:41
#: bookwyrm/templates/snippets/create_status.html:28
msgid "Comment"
-msgstr "Comentário"
+msgstr "Comentar"
#: bookwyrm/templates/settings/reports/report.html:46
msgid "Reported statuses"
@@ -2636,8 +2633,8 @@ msgid "Short description:"
msgstr "Descrição curta:"
#: bookwyrm/templates/settings/site.html:37
-msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support html or markdown."
-msgstr "Mostrado quando a instância é vista em joinbookwyrm.com. Não compatível com HTML ou markdown."
+msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support HTML or Markdown."
+msgstr "Mostrado quando a instância é vista em joinbookwyrm.com. Não é compatível com HTML ou Markdown."
#: bookwyrm/templates/settings/site.html:41
msgid "Code of conduct:"
@@ -2811,7 +2808,7 @@ msgid "Permanently deleted"
msgstr "Excluído permanentemente"
#: bookwyrm/templates/settings/users/user_moderation_actions.html:13
-#: bookwyrm/templates/snippets/status/status_options.html:35
+#: bookwyrm/templates/snippets/status/status_options.html:32
#: bookwyrm/templates/snippets/user_options.html:13
msgid "Send direct message"
msgstr "Enviar mensagem direta"
@@ -2864,22 +2861,22 @@ msgstr "Editar estante"
msgid "Delete shelf"
msgstr "Excluir estante"
-#: bookwyrm/templates/shelf/shelf.html:130
-#: bookwyrm/templates/shelf/shelf.html:154
+#: bookwyrm/templates/shelf/shelf.html:132
+#: bookwyrm/templates/shelf/shelf.html:158
msgid "Shelved"
msgstr "Adicionado"
-#: bookwyrm/templates/shelf/shelf.html:131
-#: bookwyrm/templates/shelf/shelf.html:158
+#: bookwyrm/templates/shelf/shelf.html:133
+#: bookwyrm/templates/shelf/shelf.html:161
msgid "Started"
msgstr "Iniciado"
-#: bookwyrm/templates/shelf/shelf.html:132
-#: bookwyrm/templates/shelf/shelf.html:161
+#: bookwyrm/templates/shelf/shelf.html:134
+#: bookwyrm/templates/shelf/shelf.html:164
msgid "Finished"
msgstr "Terminado"
-#: bookwyrm/templates/shelf/shelf.html:187
+#: bookwyrm/templates/shelf/shelf.html:190
msgid "This shelf is empty."
msgstr "Esta estante está vazia."
@@ -2926,22 +2923,22 @@ msgstr "Citar"
msgid "Some thoughts on the book"
msgstr "Algumas ideias sobre o livro"
-#: bookwyrm/templates/snippets/create_status/comment.html:26
+#: bookwyrm/templates/snippets/create_status/comment.html:27
#: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:15
msgid "Progress:"
msgstr "Progresso:"
-#: bookwyrm/templates/snippets/create_status/comment.html:52
+#: bookwyrm/templates/snippets/create_status/comment.html:53
#: bookwyrm/templates/snippets/progress_field.html:18
msgid "pages"
msgstr "páginas"
-#: bookwyrm/templates/snippets/create_status/comment.html:58
+#: bookwyrm/templates/snippets/create_status/comment.html:59
#: bookwyrm/templates/snippets/progress_field.html:23
msgid "percent"
msgstr "porcento"
-#: bookwyrm/templates/snippets/create_status/comment.html:65
+#: bookwyrm/templates/snippets/create_status/comment.html:66
#, python-format
msgid "of %(pages)s pages"
msgstr "de %(pages)s páginas"
@@ -2969,7 +2966,7 @@ msgstr "Alerta de spoiler!"
msgid "Include spoiler alert"
msgstr "Incluir alerta de spoiler"
-#: bookwyrm/templates/snippets/create_status/layout.html:41
+#: bookwyrm/templates/snippets/create_status/layout.html:48
#: bookwyrm/templates/snippets/reading_modals/form.html:7
msgid "Comment:"
msgstr "Comentário:"
@@ -3142,7 +3139,7 @@ msgstr "Privacidade da meta:"
#: bookwyrm/templates/snippets/goal_form.html:33
#: bookwyrm/templates/snippets/reading_modals/layout.html:13
msgid "Post to feed"
-msgstr "Publicar no feed"
+msgstr "Publicar"
#: bookwyrm/templates/snippets/goal_form.html:37
msgid "Set goal"
@@ -3151,7 +3148,7 @@ msgstr "Definir meta"
#: bookwyrm/templates/snippets/goal_progress.html:9
#, python-format
msgid "%(percent)s%% complete!"
-msgstr "%(percent)s%% completo!"
+msgstr "%(percent)s%% lá!"
#: bookwyrm/templates/snippets/goal_progress.html:12
#, python-format
@@ -3163,12 +3160,12 @@ msgstr "Você leu %(read_count)s de %(goal_count)s livros
msgid "%(username)s has read %(read_count)s of %(goal_count)s books ."
msgstr "%(username)s leu %(read_count)s de %(goal_count)s livros ."
-#: bookwyrm/templates/snippets/page_text.html:4
+#: bookwyrm/templates/snippets/page_text.html:8
#, python-format
msgid "page %(page)s of %(total_pages)s"
msgstr "página %(page)s de %(total_pages)s"
-#: bookwyrm/templates/snippets/page_text.html:6
+#: bookwyrm/templates/snippets/page_text.html:14
#, python-format
msgid "page %(page)s"
msgstr "página %(page)s"
@@ -3256,7 +3253,7 @@ msgstr "Progresso"
#: bookwyrm/templates/snippets/register_form.html:32
msgid "Sign Up"
-msgstr "Se cadastrar"
+msgstr "Cadastrar"
#: bookwyrm/templates/snippets/report_button.html:6
msgid "Report"
@@ -3329,6 +3326,11 @@ msgstr "Abrir imagem em nova janela"
msgid "Hide status"
msgstr "Esconder publicação"
+#: bookwyrm/templates/snippets/status/header.html:45
+#, python-format
+msgid "edited %(date)s"
+msgstr "editado em %(date)s"
+
#: bookwyrm/templates/snippets/status/headers/comment.html:2
#, python-format
msgid "commented on %(book)s "
@@ -3393,10 +3395,6 @@ msgstr "compartilhado"
msgid "More options"
msgstr "Mais opções"
-#: bookwyrm/templates/snippets/status/status_options.html:26
-msgid "Delete & re-draft"
-msgstr "Excluir e rascunhar"
-
#: bookwyrm/templates/snippets/suggested_users.html:16
#, python-format
msgid "%(mutuals)s follower you follow"
diff --git a/locale/zh_Hans/LC_MESSAGES/django.mo b/locale/zh_Hans/LC_MESSAGES/django.mo
index 9eaced00b..1d1227f80 100644
Binary files a/locale/zh_Hans/LC_MESSAGES/django.mo and b/locale/zh_Hans/LC_MESSAGES/django.mo differ
diff --git a/locale/zh_Hans/LC_MESSAGES/django.po b/locale/zh_Hans/LC_MESSAGES/django.po
index 7bbcbcc54..2a0707359 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: 2021-10-06 23:57+0000\n"
-"PO-Revision-Date: 2021-10-08 00:03\n"
+"POT-Creation-Date: 2021-10-15 22:03+0000\n"
+"PO-Revision-Date: 2021-10-16 14:36\n"
"Last-Translator: Mouse Reeve \n"
"Language-Team: Chinese Simplified\n"
"Language: zh\n"
@@ -40,7 +40,7 @@ msgstr "永不失效"
#: bookwyrm/forms.py:263
#, python-brace-format
msgid "{i} uses"
-msgstr ""
+msgstr "{i} 次使用"
#: bookwyrm/forms.py:264
msgid "Unlimited"
@@ -54,8 +54,8 @@ msgstr "列表顺序"
msgid "Book Title"
msgstr "书名"
-#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:134
-#: bookwyrm/templates/shelf/shelf.html:165
+#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:136
+#: bookwyrm/templates/shelf/shelf.html:168
#: bookwyrm/templates/snippets/create_status/review.html:33
msgid "Rating"
msgstr "评价"
@@ -74,51 +74,51 @@ msgstr "降序"
#: bookwyrm/importers/importer.py:75
msgid "Error loading book"
-msgstr ""
+msgstr "加载书籍时出错"
#: bookwyrm/importers/importer.py:88
msgid "Could not find a match for book"
-msgstr ""
+msgstr "找不到匹配的书"
#: bookwyrm/models/base_model.py:17
msgid "Pending"
-msgstr ""
+msgstr "待处理"
#: bookwyrm/models/base_model.py:18
msgid "Self deletion"
-msgstr ""
+msgstr "自我删除"
#: bookwyrm/models/base_model.py:19
msgid "Moderator suspension"
-msgstr ""
+msgstr "仲裁员停用"
#: bookwyrm/models/base_model.py:20
msgid "Moderator deletion"
-msgstr ""
+msgstr "仲裁员删除"
#: bookwyrm/models/base_model.py:21
msgid "Domain block"
-msgstr ""
+msgstr "域名屏蔽"
#: bookwyrm/models/book.py:232
msgid "Audiobook"
-msgstr ""
+msgstr "有声书籍"
#: bookwyrm/models/book.py:233
msgid "eBook"
-msgstr ""
+msgstr "电子书"
#: bookwyrm/models/book.py:234
msgid "Graphic novel"
-msgstr ""
+msgstr "图像小说"
#: bookwyrm/models/book.py:235
msgid "Hardcover"
-msgstr ""
+msgstr "硬封面"
#: bookwyrm/models/book.py:236
msgid "Paperback"
-msgstr ""
+msgstr "平装"
#: bookwyrm/models/federated_server.py:11
#: bookwyrm/templates/settings/federation/edit_instance.html:42
@@ -151,45 +151,49 @@ msgstr "用户名"
msgid "A user with that username already exists."
msgstr "已经存在使用该用户名的用户。"
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home Timeline"
msgstr "主页时间线"
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home"
msgstr "主页"
-#: bookwyrm/settings.py:118
+#: bookwyrm/settings.py:119
msgid "Books Timeline"
msgstr "书目时间线"
-#: bookwyrm/settings.py:118 bookwyrm/templates/search/layout.html:21
+#: bookwyrm/settings.py:119 bookwyrm/templates/search/layout.html:21
#: bookwyrm/templates/search/layout.html:42
#: bookwyrm/templates/user/layout.html:81
msgid "Books"
msgstr "书目"
-#: bookwyrm/settings.py:164
+#: bookwyrm/settings.py:165
msgid "English"
msgstr "English(英语)"
-#: bookwyrm/settings.py:165
+#: bookwyrm/settings.py:166
msgid "Deutsch (German)"
msgstr "Deutsch(德语)"
-#: bookwyrm/settings.py:166
+#: bookwyrm/settings.py:167
msgid "Español (Spanish)"
msgstr "Español(西班牙语)"
-#: bookwyrm/settings.py:167
+#: bookwyrm/settings.py:168
msgid "Français (French)"
msgstr "Français(法语)"
-#: bookwyrm/settings.py:168
+#: bookwyrm/settings.py:169
+msgid "Português - Brasil (Brazilian Portuguese)"
+msgstr ""
+
+#: bookwyrm/settings.py:170
msgid "简体中文 (Simplified Chinese)"
msgstr "简体中文"
-#: bookwyrm/settings.py:169
+#: bookwyrm/settings.py:171
msgid "繁體中文 (Traditional Chinese)"
msgstr "繁體中文(繁体中文)"
@@ -570,7 +574,7 @@ msgstr "语言:"
#: bookwyrm/templates/book/edit/edit_book_form.html:74
msgid "Publication"
-msgstr ""
+msgstr "出版"
#: bookwyrm/templates/book/edit/edit_book_form.html:77
msgid "Publisher:"
@@ -622,7 +626,7 @@ msgstr "格式:"
#: bookwyrm/templates/book/edit/edit_book_form.html:177
msgid "Format details:"
-msgstr ""
+msgstr "装订细节:"
#: bookwyrm/templates/book/edit/edit_book_form.html:187
msgid "Pages:"
@@ -666,12 +670,7 @@ msgstr "语言:"
#: bookwyrm/templates/book/editions/search_filter.html:5
msgid "Search editions"
-msgstr ""
-
-#: bookwyrm/templates/book/publisher_info.html:21
-#, python-format
-msgid "%(format)s"
-msgstr "%(format)s"
+msgstr "搜索版本"
#: bookwyrm/templates/book/publisher_info.html:23
#, python-format
@@ -749,11 +748,11 @@ msgstr "关闭"
#: bookwyrm/templates/components/tooltip.html:3
msgid "Help"
-msgstr ""
+msgstr "帮助"
#: bookwyrm/templates/compose.html:5 bookwyrm/templates/compose.html:8
-msgid "Compose status"
-msgstr "撰写状态"
+msgid "Edit status"
+msgstr ""
#: bookwyrm/templates/confirm_email/confirm_email.html:4
msgid "Confirm email"
@@ -885,6 +884,26 @@ msgstr "BookWyrm 用户"
msgid "All known users"
msgstr "所有已知用户"
+#: bookwyrm/templates/discover/card-header.html:9
+#, python-format
+msgid "%(username)s rated %(book_title)s "
+msgstr ""
+
+#: bookwyrm/templates/discover/card-header.html:13
+#, python-format
+msgid "%(username)s reviewed %(book_title)s "
+msgstr ""
+
+#: bookwyrm/templates/discover/card-header.html:17
+#, python-format
+msgid "%(username)s commented on %(book_title)s "
+msgstr ""
+
+#: bookwyrm/templates/discover/card-header.html:21
+#, python-format
+msgid "%(username)s quoted %(book_title)s "
+msgstr ""
+
#: bookwyrm/templates/discover/discover.html:4
#: bookwyrm/templates/discover/discover.html:10
#: bookwyrm/templates/layout.html:78
@@ -896,28 +915,8 @@ msgstr "发现"
msgid "See what's new in the local %(site_name)s community"
msgstr "看看本地 %(site_name)s 社区的新消息"
-#: bookwyrm/templates/discover/large-book.html:46
-#: bookwyrm/templates/discover/small-book.html:32
-msgid "rated"
-msgstr "评价了"
-
-#: bookwyrm/templates/discover/large-book.html:48
-#: bookwyrm/templates/discover/small-book.html:34
-msgid "reviewed"
-msgstr "写了书评给"
-
-#: bookwyrm/templates/discover/large-book.html:50
-#: bookwyrm/templates/discover/small-book.html:36
-msgid "commented on"
-msgstr "评论了"
-
#: bookwyrm/templates/discover/large-book.html:52
-#: bookwyrm/templates/discover/small-book.html:38
-msgid "quoted"
-msgstr "引用了"
-
-#: bookwyrm/templates/discover/large-book.html:68
-#: bookwyrm/templates/discover/small-book.html:52
+#: bookwyrm/templates/discover/small-book.html:36
msgid "View status"
msgstr "浏览状态"
@@ -971,8 +970,8 @@ msgstr "立即加入"
#: bookwyrm/templates/email/invite/html_content.html:15
#, python-format
-msgid "Learn more about this instance ."
-msgstr "了解更多 有关本实例的信息 。"
+msgid "Learn more about %(site_name)s ."
+msgstr ""
#: bookwyrm/templates/email/invite/text_content.html:4
#, python-format
@@ -980,8 +979,9 @@ msgid "You're invited to join %(site_name)s! Click the link below to create an a
msgstr "你受邀请加入 %(site_name)s!点击下面的连接来创建帐号。"
#: bookwyrm/templates/email/invite/text_content.html:8
-msgid "Learn more about this instance:"
-msgstr "了解更多有关本实例的信息:"
+#, python-format
+msgid "Learn more about %(site_name)s:"
+msgstr ""
#: bookwyrm/templates/email/password_reset/html_content.html:6
#: bookwyrm/templates/email/password_reset/text_content.html:4
@@ -1083,11 +1083,11 @@ msgstr "可以关注的人"
#: bookwyrm/templates/feed/suggested_users.html:9
msgid "Don't show suggested users"
-msgstr ""
+msgstr "不显示推荐用户"
#: bookwyrm/templates/feed/suggested_users.html:14
msgid "View directory"
-msgstr ""
+msgstr "查看目录"
#: bookwyrm/templates/get_started/book_preview.html:6
#, python-format
@@ -1320,13 +1320,13 @@ msgstr "书目"
#: bookwyrm/templates/import/import_status.html:122
#: bookwyrm/templates/shelf/shelf.html:128
-#: bookwyrm/templates/shelf/shelf.html:148
+#: bookwyrm/templates/shelf/shelf.html:150
msgid "Title"
msgstr "标题"
#: bookwyrm/templates/import/import_status.html:125
#: bookwyrm/templates/shelf/shelf.html:129
-#: bookwyrm/templates/shelf/shelf.html:151
+#: bookwyrm/templates/shelf/shelf.html:153
msgid "Author"
msgstr "作者"
@@ -1335,7 +1335,7 @@ msgid "Imported"
msgstr "已导入"
#: bookwyrm/templates/import/tooltip.html:6
-msgid "You can download your GoodReads data from the Import/Export page of your GoodReads account."
+msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account."
msgstr ""
#: bookwyrm/templates/invite.html:4 bookwyrm/templates/invite.html:8
@@ -1351,7 +1351,7 @@ msgstr "没有权限"
msgid "Sorry! This invite code is no longer valid."
msgstr "抱歉!此邀请码已不再有效。"
-#: bookwyrm/templates/landing/about.html:7
+#: bookwyrm/templates/landing/about.html:7 bookwyrm/templates/layout.html:230
#, python-format
msgid "About %(site_name)s"
msgstr "关于 %(site_name)s"
@@ -1394,7 +1394,7 @@ msgstr "请求邀请"
#: bookwyrm/templates/landing/layout.html:49
#, python-format
msgid "%(name)s registration is closed"
-msgstr ""
+msgstr "%(name)s 注册已关闭"
#: bookwyrm/templates/landing/layout.html:60
msgid "Thank you! Your request has been received."
@@ -1407,11 +1407,11 @@ msgstr "你的帐号"
#: bookwyrm/templates/layout.html:13
#, python-format
msgid "%(site_name)s search"
-msgstr ""
+msgstr "%(site_name)s 搜索"
#: bookwyrm/templates/layout.html:43
msgid "Search for a book, user, or list"
-msgstr ""
+msgstr "搜索书籍、用户或列表"
#: bookwyrm/templates/layout.html:61 bookwyrm/templates/layout.html:62
msgid "Main navigation menu"
@@ -1476,15 +1476,11 @@ msgstr "加入"
#: bookwyrm/templates/layout.html:221
msgid "Successfully posted status"
-msgstr ""
+msgstr "成功发布的状态"
#: bookwyrm/templates/layout.html:222
msgid "Error posting status"
-msgstr ""
-
-#: bookwyrm/templates/layout.html:230
-msgid "About this instance"
-msgstr "关于本实例"
+msgstr "发布状态时出错"
#: bookwyrm/templates/layout.html:234
msgid "Contact site admin"
@@ -1505,7 +1501,7 @@ msgstr "BookWyrm 是开源软件。你可以在 %(book_title)s to your list \"%(list_name)s \""
-msgstr ""
+msgstr "添加了 %(book_title)s 到你的列表 “%(list_name)s ”"
#: bookwyrm/templates/notifications/items/add.html:31
#, python-format
msgid "suggested adding %(book_title)s to your list \"%(list_name)s \""
-msgstr ""
+msgstr "建议了添加 %(book_title)s 到你的列表 “%(list_name)s ” 中"
#: bookwyrm/templates/notifications/items/boost.html:19
#, python-format
@@ -1730,23 +1726,23 @@ msgstr "转发了你的 状态 "
#: bookwyrm/templates/notifications/items/fav.html:19
#, python-format
-msgid "favorited your review of %(book_title)s "
-msgstr "喜欢了你 对 %(book_title)s 的书评 "
+msgid "liked your review of %(book_title)s "
+msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:25
#, python-format
-msgid "favorited your comment on%(book_title)s "
+msgid "liked your comment on%(book_title)s "
msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:31
#, python-format
-msgid "favorited your quote from %(book_title)s "
-msgstr "喜欢了你 来自 %(book_title)s 的引用 "
+msgid "liked your quote from %(book_title)s "
+msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:37
#, python-format
-msgid "favorited your status "
-msgstr "喜欢了你的 状态 "
+msgid "liked your status "
+msgstr ""
#: bookwyrm/templates/notifications/items/follow.html:15
msgid "followed you"
@@ -1888,20 +1884,20 @@ msgstr "个人资料"
#: bookwyrm/templates/preferences/edit_user.html:13
#: bookwyrm/templates/preferences/edit_user.html:68
msgid "Display preferences"
-msgstr ""
+msgstr "显示偏好"
#: bookwyrm/templates/preferences/edit_user.html:14
#: bookwyrm/templates/preferences/edit_user.html:106
msgid "Privacy"
-msgstr ""
+msgstr "隐私"
#: bookwyrm/templates/preferences/edit_user.html:72
msgid "Show reading goal prompt in feed:"
-msgstr ""
+msgstr "在状态流中显示阅读目标提示:"
#: bookwyrm/templates/preferences/edit_user.html:76
msgid "Show suggested users:"
-msgstr ""
+msgstr "显示推荐用户:"
#: bookwyrm/templates/preferences/edit_user.html:85
#, python-format
@@ -2035,15 +2031,15 @@ msgstr "创建公告"
#: bookwyrm/templates/settings/announcements/announcement_form.html:16
msgid "Preview:"
-msgstr ""
+msgstr "预览:"
#: bookwyrm/templates/settings/announcements/announcement_form.html:23
msgid "Content:"
-msgstr ""
+msgstr "内容:"
#: bookwyrm/templates/settings/announcements/announcement_form.html:30
msgid "Event date:"
-msgstr ""
+msgstr "事件日期:"
#: bookwyrm/templates/settings/announcements/announcements.html:3
#: bookwyrm/templates/settings/announcements/announcements.html:5
@@ -2087,122 +2083,122 @@ msgstr "停用"
#: bookwyrm/templates/settings/announcements/announcements.html:52
msgid "No announcements found"
-msgstr ""
+msgstr "未找到公告"
#: bookwyrm/templates/settings/dashboard/dashboard.html:6
#: bookwyrm/templates/settings/dashboard/dashboard.html:8
#: bookwyrm/templates/settings/layout.html:26
msgid "Dashboard"
-msgstr ""
+msgstr "仪表盘"
#: bookwyrm/templates/settings/dashboard/dashboard.html:15
#: bookwyrm/templates/settings/dashboard/dashboard.html:100
msgid "Total users"
-msgstr ""
+msgstr "用户总数"
#: bookwyrm/templates/settings/dashboard/dashboard.html:21
#: bookwyrm/templates/settings/dashboard/user_chart.html:16
msgid "Active this month"
-msgstr ""
+msgstr "今月活跃"
#: bookwyrm/templates/settings/dashboard/dashboard.html:27
msgid "Statuses"
-msgstr ""
+msgstr "状态"
#: bookwyrm/templates/settings/dashboard/dashboard.html:33
#: bookwyrm/templates/settings/dashboard/works_chart.html:11
msgid "Works"
-msgstr ""
+msgstr "作品"
#: bookwyrm/templates/settings/dashboard/dashboard.html:43
#, python-format
msgid "%(display_count)s open report"
msgid_plural "%(display_count)s open reports"
-msgstr[0] ""
+msgstr[0] "%(display_count)s 条待处理报告"
#: bookwyrm/templates/settings/dashboard/dashboard.html:54
#, python-format
msgid "%(display_count)s invite request"
msgid_plural "%(display_count)s invite requests"
-msgstr[0] ""
+msgstr[0] "%(display_count)s 条邀请请求"
#: bookwyrm/templates/settings/dashboard/dashboard.html:65
msgid "Instance Activity"
-msgstr ""
+msgstr "实例活动"
#: bookwyrm/templates/settings/dashboard/dashboard.html:83
msgid "Interval:"
-msgstr ""
+msgstr "区段:"
#: bookwyrm/templates/settings/dashboard/dashboard.html:87
msgid "Days"
-msgstr ""
+msgstr "天"
#: bookwyrm/templates/settings/dashboard/dashboard.html:88
msgid "Weeks"
-msgstr ""
+msgstr "周"
#: bookwyrm/templates/settings/dashboard/dashboard.html:106
msgid "User signup activity"
-msgstr ""
+msgstr "用户注册活动"
#: bookwyrm/templates/settings/dashboard/dashboard.html:112
msgid "Status activity"
-msgstr ""
+msgstr "状态动态"
#: bookwyrm/templates/settings/dashboard/dashboard.html:118
msgid "Works created"
-msgstr ""
+msgstr "创建的作品"
#: bookwyrm/templates/settings/dashboard/registration_chart.html:10
msgid "Registrations"
-msgstr ""
+msgstr "注册"
#: bookwyrm/templates/settings/dashboard/status_chart.html:11
msgid "Statuses posted"
-msgstr ""
+msgstr "发布的状态"
#: bookwyrm/templates/settings/dashboard/user_chart.html:11
msgid "Total"
-msgstr ""
+msgstr "总数"
#: bookwyrm/templates/settings/email_blocklist/domain_form.html:5
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:10
msgid "Add domain"
-msgstr ""
+msgstr "添加域名"
#: bookwyrm/templates/settings/email_blocklist/domain_form.html:11
msgid "Domain:"
-msgstr ""
+msgstr "域名:"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:5
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:7
#: bookwyrm/templates/settings/layout.html:59
msgid "Email Blocklist"
-msgstr ""
+msgstr "邮件屏蔽列表"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:18
msgid "When someone tries to register with an email from this domain, no account will be created. The registration process will appear to have worked."
-msgstr ""
+msgstr "当有人试图使用此域名的电子邮件注册时,帐户将不会被创建,但注册过程看起来会像是成功了的样子。"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:25
msgid "Domain"
-msgstr ""
+msgstr "域名"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:29
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:27
msgid "Options"
-msgstr ""
+msgstr "选项"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:38
#, python-format
msgid "%(display_count)s user"
msgid_plural "%(display_count)s users"
-msgstr[0] ""
+msgstr[0] "%(display_count)s 名用户"
#: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:59
msgid "No email domains currently blocked"
-msgstr ""
+msgstr "目前没有屏蔽邮件域名"
#: bookwyrm/templates/settings/federation/edit_instance.html:3
#: bookwyrm/templates/settings/federation/edit_instance.html:6
@@ -2291,12 +2287,13 @@ msgid "Notes"
msgstr "备注"
#: bookwyrm/templates/settings/federation/instance.html:75
+#: bookwyrm/templates/snippets/status/status_options.html:24
msgid "Edit"
msgstr "编辑"
#: bookwyrm/templates/settings/federation/instance.html:79
msgid "No notes "
-msgstr ""
+msgstr "没有备注 "
#: bookwyrm/templates/settings/federation/instance.html:94
#: bookwyrm/templates/settings/users/user_moderation_actions.html:8
@@ -2355,7 +2352,7 @@ msgstr "软件"
#: bookwyrm/templates/settings/federation/instance_list.html:63
msgid "No instances found"
-msgstr ""
+msgstr "未找到实例"
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:4
#: bookwyrm/templates/settings/invites/manage_invite_requests.html:11
@@ -2466,37 +2463,37 @@ msgstr "无有效的邀请"
#: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:5
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:10
msgid "Add IP address"
-msgstr ""
+msgstr "添加 IP 地址"
#: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:11
msgid "Use IP address blocks with caution, and consider using blocks only temporarily, as IP addresses are often shared or change hands. If you block your own IP, you will not be able to access this page."
-msgstr ""
+msgstr "请谨慎使用 IP 地址屏蔽,并尽可能只使用暂时的屏蔽,因为 IP 地址常常被共享或变更。 如果您屏蔽了自己的 IP,您将无法访问此页面。"
#: bookwyrm/templates/settings/ip_blocklist/ip_address_form.html:18
msgid "IP Address:"
-msgstr ""
+msgstr "IP 地址:"
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:5
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:7
#: bookwyrm/templates/settings/layout.html:63
msgid "IP Address Blocklist"
-msgstr ""
+msgstr "IP 地址屏蔽列表"
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:18
msgid "Any traffic from this IP address will get a 404 response when trying to access any part of the application."
-msgstr ""
+msgstr "从此 IP 地址的所有尝试访问此应用的流量都将会收到 404 的答复。"
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:24
msgid "Address"
-msgstr ""
+msgstr "地址"
#: bookwyrm/templates/settings/ip_blocklist/ip_blocklist.html:46
msgid "No IP addresses currently blocked"
-msgstr ""
+msgstr "目前没有屏蔽 IP 地址"
#: bookwyrm/templates/settings/ip_blocklist/ip_tooltip.html:6
msgid "You can block IP ranges using CIDR syntax."
-msgstr ""
+msgstr "你可以使用 CIDR 语法来进行 IP 段的屏蔽。"
#: bookwyrm/templates/settings/layout.html:4
msgid "Administration"
@@ -2508,7 +2505,7 @@ msgstr "管理用户"
#: bookwyrm/templates/settings/layout.html:51
msgid "Moderation"
-msgstr ""
+msgstr "仲裁"
#: bookwyrm/templates/settings/layout.html:55
#: bookwyrm/templates/settings/reports/reports.html:8
@@ -2627,10 +2624,10 @@ msgstr "实例描述:"
#: bookwyrm/templates/settings/site.html:36
msgid "Short description:"
-msgstr ""
+msgstr "简要描述:"
#: bookwyrm/templates/settings/site.html:37
-msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support html or markdown."
+msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support HTML or Markdown."
msgstr ""
#: bookwyrm/templates/settings/site.html:41
@@ -2691,21 +2688,21 @@ msgstr "注册关闭文字:"
#: bookwyrm/templates/settings/site.html:124
msgid "Invite request text:"
-msgstr ""
+msgstr "邀请请求文本:"
#: bookwyrm/templates/settings/users/delete_user_form.html:5
#: bookwyrm/templates/settings/users/user_moderation_actions.html:31
msgid "Permanently delete user"
-msgstr ""
+msgstr "永久删除用户"
#: bookwyrm/templates/settings/users/delete_user_form.html:12
#, python-format
msgid "Are you sure you want to delete %(username)s 's account? This action cannot be undone. To proceed, please enter your password to confirm deletion."
-msgstr ""
+msgstr "你确定要删除 %(username)s 的帐号吗?此操作不能被撤销。请输入你的密码确认删除操作以继续。"
#: bookwyrm/templates/settings/users/delete_user_form.html:17
msgid "Your password:"
-msgstr ""
+msgstr "你的密码:"
#: bookwyrm/templates/settings/users/user.html:7
msgid "Back to users"
@@ -2758,7 +2755,7 @@ msgstr "本站"
#: bookwyrm/templates/settings/users/user_info.html:38
msgid "Remote"
-msgstr ""
+msgstr "远端"
#: bookwyrm/templates/settings/users/user_info.html:47
msgid "User details"
@@ -2766,31 +2763,31 @@ msgstr "用户详情"
#: bookwyrm/templates/settings/users/user_info.html:51
msgid "Email:"
-msgstr ""
+msgstr "邮箱:"
#: bookwyrm/templates/settings/users/user_info.html:61
msgid "(View reports)"
-msgstr ""
+msgstr "(查看报告)"
#: bookwyrm/templates/settings/users/user_info.html:67
msgid "Blocked by count:"
-msgstr ""
+msgstr "被屏蔽次数:"
#: bookwyrm/templates/settings/users/user_info.html:70
msgid "Last active date:"
-msgstr ""
+msgstr "最后活跃日期:"
#: bookwyrm/templates/settings/users/user_info.html:73
msgid "Manually approved followers:"
-msgstr ""
+msgstr "手动批准关注者:"
#: bookwyrm/templates/settings/users/user_info.html:76
msgid "Discoverable:"
-msgstr ""
+msgstr "可发现:"
#: bookwyrm/templates/settings/users/user_info.html:80
msgid "Deactivation reason:"
-msgstr ""
+msgstr "停用原因:"
#: bookwyrm/templates/settings/users/user_info.html:95
msgid "Instance details"
@@ -2805,7 +2802,7 @@ msgid "Permanently deleted"
msgstr "已永久删除"
#: bookwyrm/templates/settings/users/user_moderation_actions.html:13
-#: bookwyrm/templates/snippets/status/status_options.html:35
+#: bookwyrm/templates/snippets/status/status_options.html:32
#: bookwyrm/templates/snippets/user_options.html:13
msgid "Send direct message"
msgstr "发送私信"
@@ -2842,12 +2839,12 @@ msgstr "创建书架"
#, python-format
msgid "%(formatted_count)s book"
msgid_plural "%(formatted_count)s books"
-msgstr[0] ""
+msgstr[0] "%(formatted_count)s 本书籍"
#: bookwyrm/templates/shelf/shelf.html:84
#, python-format
msgid "(showing %(start)s-%(end)s)"
-msgstr ""
+msgstr "(正在显示 %(start)s 到 %(end)s)"
#: bookwyrm/templates/shelf/shelf.html:96
msgid "Edit shelf"
@@ -2857,22 +2854,22 @@ msgstr "编辑书架"
msgid "Delete shelf"
msgstr "删除书架"
-#: bookwyrm/templates/shelf/shelf.html:130
-#: bookwyrm/templates/shelf/shelf.html:154
+#: bookwyrm/templates/shelf/shelf.html:132
+#: bookwyrm/templates/shelf/shelf.html:158
msgid "Shelved"
msgstr "上架时间"
-#: bookwyrm/templates/shelf/shelf.html:131
-#: bookwyrm/templates/shelf/shelf.html:158
+#: bookwyrm/templates/shelf/shelf.html:133
+#: bookwyrm/templates/shelf/shelf.html:161
msgid "Started"
msgstr "开始时间"
-#: bookwyrm/templates/shelf/shelf.html:132
-#: bookwyrm/templates/shelf/shelf.html:161
+#: bookwyrm/templates/shelf/shelf.html:134
+#: bookwyrm/templates/shelf/shelf.html:164
msgid "Finished"
msgstr "完成时间"
-#: bookwyrm/templates/shelf/shelf.html:187
+#: bookwyrm/templates/shelf/shelf.html:190
msgid "This shelf is empty."
msgstr "此书架是空的。"
@@ -2918,22 +2915,22 @@ msgstr "引用"
msgid "Some thoughts on the book"
msgstr "对书的一些看法"
-#: bookwyrm/templates/snippets/create_status/comment.html:26
+#: bookwyrm/templates/snippets/create_status/comment.html:27
#: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:15
msgid "Progress:"
msgstr "进度:"
-#: bookwyrm/templates/snippets/create_status/comment.html:52
+#: bookwyrm/templates/snippets/create_status/comment.html:53
#: bookwyrm/templates/snippets/progress_field.html:18
msgid "pages"
msgstr "页数"
-#: bookwyrm/templates/snippets/create_status/comment.html:58
+#: bookwyrm/templates/snippets/create_status/comment.html:59
#: bookwyrm/templates/snippets/progress_field.html:23
msgid "percent"
msgstr "百分比"
-#: bookwyrm/templates/snippets/create_status/comment.html:65
+#: bookwyrm/templates/snippets/create_status/comment.html:66
#, python-format
msgid "of %(pages)s pages"
msgstr "全书 %(pages)s 页"
@@ -2951,7 +2948,7 @@ msgstr "内容"
#: bookwyrm/templates/snippets/create_status/content_warning_field.html:10
msgid "Content warning:"
-msgstr ""
+msgstr "内容警告:"
#: bookwyrm/templates/snippets/create_status/content_warning_field.html:18
msgid "Spoilers ahead!"
@@ -2961,7 +2958,7 @@ msgstr "前有剧透!"
msgid "Include spoiler alert"
msgstr "加入剧透警告"
-#: bookwyrm/templates/snippets/create_status/layout.html:41
+#: bookwyrm/templates/snippets/create_status/layout.html:48
#: bookwyrm/templates/snippets/reading_modals/form.html:7
msgid "Comment:"
msgstr "评论:"
@@ -2988,15 +2985,15 @@ msgstr "摘自《%(book_title)s》的节录"
#: bookwyrm/templates/snippets/create_status/quotation.html:32
msgid "Position:"
-msgstr ""
+msgstr "位置:"
#: bookwyrm/templates/snippets/create_status/quotation.html:45
msgid "On page:"
-msgstr ""
+msgstr "页码:"
#: bookwyrm/templates/snippets/create_status/quotation.html:51
msgid "At percent:"
-msgstr ""
+msgstr "百分比:"
#: bookwyrm/templates/snippets/create_status/review.html:25
#, python-format
@@ -3077,7 +3074,7 @@ msgstr "没有评价"
#, python-format
msgid "%(half_rating)s star"
msgid_plural "%(half_rating)s stars"
-msgstr[0] ""
+msgstr[0] "%(half_rating)s 星"
#: bookwyrm/templates/snippets/form_rate_stars.html:64
#: bookwyrm/templates/snippets/stars.html:7
@@ -3150,12 +3147,12 @@ msgstr "你已经阅读了 %(goal_count)s 本书中的 %(re
msgid "%(username)s has read %(read_count)s of %(goal_count)s books ."
msgstr "%(username)s 已经阅读了 %(goal_count)s 本书中的 %(read_count)s 本 。"
-#: bookwyrm/templates/snippets/page_text.html:4
+#: bookwyrm/templates/snippets/page_text.html:8
#, python-format
msgid "page %(page)s of %(total_pages)s"
msgstr "%(total_pages)s 页中的第 %(page)s 页"
-#: bookwyrm/templates/snippets/page_text.html:6
+#: bookwyrm/templates/snippets/page_text.html:14
#, python-format
msgid "page %(page)s"
msgstr "第 %(page)s 页"
@@ -3220,7 +3217,7 @@ msgstr "已完成阅读"
#: bookwyrm/templates/snippets/reading_modals/form.html:9
msgid "(Optional)"
-msgstr ""
+msgstr "(可选)"
#: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:5
#: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:50
@@ -3292,21 +3289,21 @@ msgstr "完成阅读"
#: bookwyrm/templates/snippets/status/content_status.html:72
msgid "Content warning"
-msgstr ""
+msgstr "内容警告"
#: bookwyrm/templates/snippets/status/content_status.html:79
msgid "Show status"
-msgstr ""
+msgstr "显示状态"
#: bookwyrm/templates/snippets/status/content_status.html:101
#, python-format
msgid "(Page %(page)s)"
-msgstr ""
+msgstr "(第 %(page)s 页)"
#: bookwyrm/templates/snippets/status/content_status.html:103
#, python-format
msgid "(%(percent)s%%)"
-msgstr ""
+msgstr "(%(percent)s%%)"
#: bookwyrm/templates/snippets/status/content_status.html:125
msgid "Open image in new window"
@@ -3314,6 +3311,11 @@ msgstr "在新窗口中打开图像"
#: bookwyrm/templates/snippets/status/content_status.html:144
msgid "Hide status"
+msgstr "隐藏状态"
+
+#: bookwyrm/templates/snippets/status/header.html:45
+#, python-format
+msgid "edited %(date)s"
msgstr ""
#: bookwyrm/templates/snippets/status/headers/comment.html:2
@@ -3380,10 +3382,6 @@ msgstr "转发了"
msgid "More options"
msgstr "更多选项"
-#: bookwyrm/templates/snippets/status/status_options.html:26
-msgid "Delete & re-draft"
-msgstr "删除并重新起草"
-
#: bookwyrm/templates/snippets/suggested_users.html:16
#, python-format
msgid "%(mutuals)s follower you follow"
@@ -3566,5 +3564,5 @@ msgstr "密码重置连接已发送给 {email}"
#: bookwyrm/views/rss_feed.py:35
#, python-brace-format
msgid "Status updates from {obj.display_name}"
-msgstr ""
+msgstr "{obj.display_name} 的状态更新"
diff --git a/locale/zh_Hant/LC_MESSAGES/django.mo b/locale/zh_Hant/LC_MESSAGES/django.mo
index 97c0a9fb7..0bd0ad46e 100644
Binary files a/locale/zh_Hant/LC_MESSAGES/django.mo and b/locale/zh_Hant/LC_MESSAGES/django.mo differ
diff --git a/locale/zh_Hant/LC_MESSAGES/django.po b/locale/zh_Hant/LC_MESSAGES/django.po
index bcfcdf06b..7b9d3b778 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: 2021-10-06 23:57+0000\n"
-"PO-Revision-Date: 2021-10-08 00:03\n"
+"POT-Creation-Date: 2021-10-15 22:03+0000\n"
+"PO-Revision-Date: 2021-10-16 14:36\n"
"Last-Translator: Mouse Reeve \n"
"Language-Team: Chinese Traditional\n"
"Language: zh\n"
@@ -54,8 +54,8 @@ msgstr "列表順序"
msgid "Book Title"
msgstr "書名"
-#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:134
-#: bookwyrm/templates/shelf/shelf.html:165
+#: bookwyrm/forms.py:328 bookwyrm/templates/shelf/shelf.html:136
+#: bookwyrm/templates/shelf/shelf.html:168
#: bookwyrm/templates/snippets/create_status/review.html:33
msgid "Rating"
msgstr "評價"
@@ -151,45 +151,49 @@ msgstr "使用者名稱"
msgid "A user with that username already exists."
msgstr "已經存在使用該名稱的使用者。"
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home Timeline"
msgstr "主頁時間線"
-#: bookwyrm/settings.py:117
+#: bookwyrm/settings.py:118
msgid "Home"
msgstr "主頁"
-#: bookwyrm/settings.py:118
+#: bookwyrm/settings.py:119
msgid "Books Timeline"
msgstr ""
-#: bookwyrm/settings.py:118 bookwyrm/templates/search/layout.html:21
+#: bookwyrm/settings.py:119 bookwyrm/templates/search/layout.html:21
#: bookwyrm/templates/search/layout.html:42
#: bookwyrm/templates/user/layout.html:81
msgid "Books"
msgstr "書目"
-#: bookwyrm/settings.py:164
+#: bookwyrm/settings.py:165
msgid "English"
msgstr "English(英語)"
-#: bookwyrm/settings.py:165
+#: bookwyrm/settings.py:166
msgid "Deutsch (German)"
msgstr "Deutsch(德語)"
-#: bookwyrm/settings.py:166
+#: bookwyrm/settings.py:167
msgid "Español (Spanish)"
msgstr "Español(西班牙語)"
-#: bookwyrm/settings.py:167
+#: bookwyrm/settings.py:168
msgid "Français (French)"
msgstr "Français(法語)"
-#: bookwyrm/settings.py:168
+#: bookwyrm/settings.py:169
+msgid "Português - Brasil (Brazilian Portuguese)"
+msgstr ""
+
+#: bookwyrm/settings.py:170
msgid "简体中文 (Simplified Chinese)"
msgstr "簡體中文"
-#: bookwyrm/settings.py:169
+#: bookwyrm/settings.py:171
msgid "繁體中文 (Traditional Chinese)"
msgstr "繁體中文"
@@ -668,11 +672,6 @@ msgstr "語言:"
msgid "Search editions"
msgstr ""
-#: bookwyrm/templates/book/publisher_info.html:21
-#, python-format
-msgid "%(format)s"
-msgstr "%(format)s"
-
#: bookwyrm/templates/book/publisher_info.html:23
#, python-format
msgid "%(format)s, %(pages)s pages"
@@ -752,8 +751,8 @@ msgid "Help"
msgstr ""
#: bookwyrm/templates/compose.html:5 bookwyrm/templates/compose.html:8
-msgid "Compose status"
-msgstr "撰寫狀態"
+msgid "Edit status"
+msgstr ""
#: bookwyrm/templates/confirm_email/confirm_email.html:4
msgid "Confirm email"
@@ -885,6 +884,26 @@ msgstr "BookWyrm 使用者"
msgid "All known users"
msgstr "所有已知使用者"
+#: bookwyrm/templates/discover/card-header.html:9
+#, python-format
+msgid "%(username)s rated %(book_title)s "
+msgstr ""
+
+#: bookwyrm/templates/discover/card-header.html:13
+#, python-format
+msgid "%(username)s reviewed %(book_title)s "
+msgstr ""
+
+#: bookwyrm/templates/discover/card-header.html:17
+#, python-format
+msgid "%(username)s commented on %(book_title)s "
+msgstr ""
+
+#: bookwyrm/templates/discover/card-header.html:21
+#, python-format
+msgid "%(username)s quoted %(book_title)s "
+msgstr ""
+
#: bookwyrm/templates/discover/discover.html:4
#: bookwyrm/templates/discover/discover.html:10
#: bookwyrm/templates/layout.html:78
@@ -896,28 +915,8 @@ msgstr ""
msgid "See what's new in the local %(site_name)s community"
msgstr ""
-#: bookwyrm/templates/discover/large-book.html:46
-#: bookwyrm/templates/discover/small-book.html:32
-msgid "rated"
-msgstr "評價了"
-
-#: bookwyrm/templates/discover/large-book.html:48
-#: bookwyrm/templates/discover/small-book.html:34
-msgid "reviewed"
-msgstr "寫了書評給"
-
-#: bookwyrm/templates/discover/large-book.html:50
-#: bookwyrm/templates/discover/small-book.html:36
-msgid "commented on"
-msgstr "評論了"
-
#: bookwyrm/templates/discover/large-book.html:52
-#: bookwyrm/templates/discover/small-book.html:38
-msgid "quoted"
-msgstr "引用了"
-
-#: bookwyrm/templates/discover/large-book.html:68
-#: bookwyrm/templates/discover/small-book.html:52
+#: bookwyrm/templates/discover/small-book.html:36
msgid "View status"
msgstr ""
@@ -971,8 +970,8 @@ msgstr "立即加入"
#: bookwyrm/templates/email/invite/html_content.html:15
#, python-format
-msgid "Learn more about this instance ."
-msgstr "瞭解更多 有關本實例的資訊 。"
+msgid "Learn more about %(site_name)s ."
+msgstr ""
#: bookwyrm/templates/email/invite/text_content.html:4
#, python-format
@@ -980,8 +979,9 @@ msgid "You're invited to join %(site_name)s! Click the link below to create an a
msgstr "你受邀請加入 %(site_name)s!點選下面的連結來建立帳號。"
#: bookwyrm/templates/email/invite/text_content.html:8
-msgid "Learn more about this instance:"
-msgstr "瞭解更多有關本實例的資訊:"
+#, python-format
+msgid "Learn more about %(site_name)s:"
+msgstr ""
#: bookwyrm/templates/email/password_reset/html_content.html:6
#: bookwyrm/templates/email/password_reset/text_content.html:4
@@ -1320,13 +1320,13 @@ msgstr "書目"
#: bookwyrm/templates/import/import_status.html:122
#: bookwyrm/templates/shelf/shelf.html:128
-#: bookwyrm/templates/shelf/shelf.html:148
+#: bookwyrm/templates/shelf/shelf.html:150
msgid "Title"
msgstr "標題"
#: bookwyrm/templates/import/import_status.html:125
#: bookwyrm/templates/shelf/shelf.html:129
-#: bookwyrm/templates/shelf/shelf.html:151
+#: bookwyrm/templates/shelf/shelf.html:153
msgid "Author"
msgstr "作者"
@@ -1335,7 +1335,7 @@ msgid "Imported"
msgstr "已匯入"
#: bookwyrm/templates/import/tooltip.html:6
-msgid "You can download your GoodReads data from the Import/Export page of your GoodReads account."
+msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account."
msgstr ""
#: bookwyrm/templates/invite.html:4 bookwyrm/templates/invite.html:8
@@ -1351,7 +1351,7 @@ msgstr "沒有權限"
msgid "Sorry! This invite code is no longer valid."
msgstr "抱歉!此邀請碼已不再有效。"
-#: bookwyrm/templates/landing/about.html:7
+#: bookwyrm/templates/landing/about.html:7 bookwyrm/templates/layout.html:230
#, python-format
msgid "About %(site_name)s"
msgstr "關於 %(site_name)s"
@@ -1482,10 +1482,6 @@ msgstr ""
msgid "Error posting status"
msgstr ""
-#: bookwyrm/templates/layout.html:230
-msgid "About this instance"
-msgstr "關於本實例"
-
#: bookwyrm/templates/layout.html:234
msgid "Contact site admin"
msgstr "聯絡網站管理員"
@@ -1730,23 +1726,23 @@ msgstr "轉發了你的 狀態 "
#: bookwyrm/templates/notifications/items/fav.html:19
#, python-format
-msgid "favorited your review of %(book_title)s "
-msgstr "喜歡了你 對 %(book_title)s 的書評 "
+msgid "liked your review of %(book_title)s "
+msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:25
#, python-format
-msgid "favorited your comment on%(book_title)s "
+msgid "liked your comment on%(book_title)s "
msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:31
#, python-format
-msgid "favorited your quote from %(book_title)s "
-msgstr "喜歡了你 來自 %(book_title)s 的引用 "
+msgid "liked your quote from %(book_title)s "
+msgstr ""
#: bookwyrm/templates/notifications/items/fav.html:37
#, python-format
-msgid "favorited your status "
-msgstr "喜歡了你的 狀態 "
+msgid "liked your status "
+msgstr ""
#: bookwyrm/templates/notifications/items/follow.html:15
msgid "followed you"
@@ -2291,6 +2287,7 @@ msgid "Notes"
msgstr "備註"
#: bookwyrm/templates/settings/federation/instance.html:75
+#: bookwyrm/templates/snippets/status/status_options.html:24
msgid "Edit"
msgstr "編輯"
@@ -2630,7 +2627,7 @@ msgid "Short description:"
msgstr ""
#: bookwyrm/templates/settings/site.html:37
-msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support html or markdown."
+msgid "Used when the instance is previewed on joinbookwyrm.com. Does not support HTML or Markdown."
msgstr ""
#: bookwyrm/templates/settings/site.html:41
@@ -2805,7 +2802,7 @@ msgid "Permanently deleted"
msgstr ""
#: bookwyrm/templates/settings/users/user_moderation_actions.html:13
-#: bookwyrm/templates/snippets/status/status_options.html:35
+#: bookwyrm/templates/snippets/status/status_options.html:32
#: bookwyrm/templates/snippets/user_options.html:13
msgid "Send direct message"
msgstr "發送私信"
@@ -2857,22 +2854,22 @@ msgstr "編輯書架"
msgid "Delete shelf"
msgstr "刪除書架"
-#: bookwyrm/templates/shelf/shelf.html:130
-#: bookwyrm/templates/shelf/shelf.html:154
+#: bookwyrm/templates/shelf/shelf.html:132
+#: bookwyrm/templates/shelf/shelf.html:158
msgid "Shelved"
msgstr "上架時間"
-#: bookwyrm/templates/shelf/shelf.html:131
-#: bookwyrm/templates/shelf/shelf.html:158
+#: bookwyrm/templates/shelf/shelf.html:133
+#: bookwyrm/templates/shelf/shelf.html:161
msgid "Started"
msgstr "開始時間"
-#: bookwyrm/templates/shelf/shelf.html:132
-#: bookwyrm/templates/shelf/shelf.html:161
+#: bookwyrm/templates/shelf/shelf.html:134
+#: bookwyrm/templates/shelf/shelf.html:164
msgid "Finished"
msgstr "完成時間"
-#: bookwyrm/templates/shelf/shelf.html:187
+#: bookwyrm/templates/shelf/shelf.html:190
msgid "This shelf is empty."
msgstr "此書架是空的。"
@@ -2918,22 +2915,22 @@ msgstr "引用"
msgid "Some thoughts on the book"
msgstr ""
-#: bookwyrm/templates/snippets/create_status/comment.html:26
+#: bookwyrm/templates/snippets/create_status/comment.html:27
#: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:15
msgid "Progress:"
msgstr "進度:"
-#: bookwyrm/templates/snippets/create_status/comment.html:52
+#: bookwyrm/templates/snippets/create_status/comment.html:53
#: bookwyrm/templates/snippets/progress_field.html:18
msgid "pages"
msgstr "頁數"
-#: bookwyrm/templates/snippets/create_status/comment.html:58
+#: bookwyrm/templates/snippets/create_status/comment.html:59
#: bookwyrm/templates/snippets/progress_field.html:23
msgid "percent"
msgstr "百分比"
-#: bookwyrm/templates/snippets/create_status/comment.html:65
+#: bookwyrm/templates/snippets/create_status/comment.html:66
#, python-format
msgid "of %(pages)s pages"
msgstr "全書 %(pages)s 頁"
@@ -2961,7 +2958,7 @@ msgstr "前有劇透!"
msgid "Include spoiler alert"
msgstr "加入劇透警告"
-#: bookwyrm/templates/snippets/create_status/layout.html:41
+#: bookwyrm/templates/snippets/create_status/layout.html:48
#: bookwyrm/templates/snippets/reading_modals/form.html:7
msgid "Comment:"
msgstr "評論:"
@@ -3150,12 +3147,12 @@ msgstr "你已經閱讀了 %(goal_count)s 本書中的 %(re
msgid "%(username)s has read %(read_count)s of %(goal_count)s books ."
msgstr "%(username)s 已經閱讀了 %(goal_count)s 本書中的 %(read_count)s 本 。"
-#: bookwyrm/templates/snippets/page_text.html:4
+#: bookwyrm/templates/snippets/page_text.html:8
#, python-format
msgid "page %(page)s of %(total_pages)s"
msgstr "%(total_pages)s 頁中的第 %(page)s 頁"
-#: bookwyrm/templates/snippets/page_text.html:6
+#: bookwyrm/templates/snippets/page_text.html:14
#, python-format
msgid "page %(page)s"
msgstr "第 %(page)s 頁"
@@ -3316,6 +3313,11 @@ msgstr "在新視窗中開啟圖片"
msgid "Hide status"
msgstr ""
+#: bookwyrm/templates/snippets/status/header.html:45
+#, python-format
+msgid "edited %(date)s"
+msgstr ""
+
#: bookwyrm/templates/snippets/status/headers/comment.html:2
#, python-format
msgid "commented on %(book)s "
@@ -3380,10 +3382,6 @@ msgstr "轉發了"
msgid "More options"
msgstr "更多選項"
-#: bookwyrm/templates/snippets/status/status_options.html:26
-msgid "Delete & re-draft"
-msgstr "刪除並重新起草"
-
#: bookwyrm/templates/snippets/suggested_users.html:16
#, python-format
msgid "%(mutuals)s follower you follow"
diff --git a/requirements.txt b/requirements.txt
index 93bb4073d..63bed4e6c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,7 +3,7 @@ colorthief==0.2.1
Django==3.2.5
django-imagekit==4.0.2
django-model-utils==4.0.0
-environs==7.2.0
+environs==9.3.4
flower==0.9.4
gunicorn==20.0.4
Markdown==3.3.3